FEATURE: Make the tag_groups#search endpoint public. (#12643)

FEATURE: Make the tag_groups#search endpoint public. (#12643)

The method uses the “TagGroup#visible” method to respect the tag group visibility settings.

diff --git a/app/assets/javascripts/select-kit/addon/components/tag-group-chooser.js b/app/assets/javascripts/select-kit/addon/components/tag-group-chooser.js
index d2026ff..5abf916 100644
--- a/app/assets/javascripts/select-kit/addon/components/tag-group-chooser.js
+++ b/app/assets/javascripts/select-kit/addon/components/tag-group-chooser.js
@@ -55,9 +55,9 @@ export default MultiSelectComponent.extend(TagsMixin, {
 
   _transformJson(context, json) {
     return json.results
-      .sort((a, b) => a.id > b.id)
+      .sort((a, b) => a.name > b.name)
       .map((result) => {
-        return { id: result.text, name: result.text, count: result.count };
+        return { id: result.name, name: result.name, count: result.count };
       });
   },
 });
diff --git a/app/controllers/tag_groups_controller.rb b/app/controllers/tag_groups_controller.rb
index 58a8f98..5419779 100644
--- a/app/controllers/tag_groups_controller.rb
+++ b/app/controllers/tag_groups_controller.rb
@@ -1,8 +1,8 @@
 # frozen_string_literal: true
 
 class TagGroupsController < ApplicationController
-  requires_login
-  before_action :ensure_staff
+  requires_login except: [:search]
+  before_action :ensure_staff, except: [:search]
 
   skip_before_action :check_xhr, only: [:index, :show, :new]
   before_action :fetch_tag_group, only: [:show, :update, :destroy]
@@ -61,15 +61,21 @@ class TagGroupsController < ApplicationController
   end
 
   def search
-    matches = if params[:q].present?
-      TagGroup.where('lower(name) ILIKE ?', "%#{params[:q].strip}%")
-    else
-      TagGroup.all
+    matches = TagGroup.includes(:tags).visible(guardian).all
+
+    if params[:q].present?
+      matches = matches.where('lower(name) ILIKE ?', "%#{params[:q].strip}%")
+    end
+
+    if params[:ids].present?
+      matches = matches.where(id: params[:ids])
     end
 
     matches = matches.order('name').limit(params[:limit] || 5)
 
-    render json: { results: matches.map { |x| { id: x.name, text: x.name } } }
+    render json: {
+      results: matches.map { |x| { name: x.name, tag_names: x.tags.base_tags.pluck(:name).sort } }
+    }
   end
 
   private
diff --git a/config/routes.rb b/config/routes.rb
index 9b1c045..b92a8e2 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -932,11 +932,8 @@ Discourse::Application.routes.draw do
       get '*tag_id', to: redirect(relative_url_root + 'tag/%{tag_id}')
     end
 
-    resources :tag_groups, constraints: StaffConstraint.new, except: [:edit] do
-      collection do
-        get '/filter/search' => 'tag_groups#search'
-      end
-    end
+    resources :tag_groups, constraints: StaffConstraint.new, except: [:edit]
+    get '/tag_groups/filter/search' => 'tag_groups#search', format: :json
 
     Discourse.filters.each do |filter|
       root to: "list##{filter}", constraints: HomePageConstraint.new("#{filter}"), as: "list_#{filter}"
diff --git a/spec/requests/tag_groups_controller_spec.rb b/spec/requests/tag_groups_controller_spec.rb
index 140f295..045906a 100644
--- a/spec/requests/tag_groups_controller_spec.rb
+++ b/spec/requests/tag_groups_controller_spec.rb
@@ -4,9 +4,10 @@ require 'rails_helper'
 
 RSpec.describe TagGroupsController do
   fab!(:user) { Fabricate(:user) }
-  fab!(:tag_group) { Fabricate(:tag_group) }
 
   describe '#index' do
+    fab!(:tag_group) { Fabricate(:tag_group) }
+
     describe 'for a non staff user' do
       it 'should not be accessible' do
         get "/tag_groups.json"
@@ -41,4 +42,73 @@ RSpec.describe TagGroupsController do
       end
     end
   end
+
+  describe '#search' do
+    fab!(:tag) { Fabricate(:tag) }
+
+    let(:everyone) { Group::AUTO_GROUPS[:everyone] }
+    let(:staff) { Group::AUTO_GROUPS[:staff] }
+
+    let(:full) { TagGroupPermission.permission_types[:full] }
+    let(:readonly) { TagGroupPermission.permission_types[:readonly] }
+
+    context 'for anons' do
+      it 'returns the tag group with the associated tag names' do
+        tag_group = tag_group_with_permission(everyone, readonly)
+
+        get '/tag_groups/filter/search.json', params: { ids: [tag_group.id] }
+        expect(response.status).to eq(200)
+
+        results = JSON.parse(response.body, symbolize_names: true).fetch(:results)
+
+        expect(results.first[:name]).to eq(tag_group.name)
+        expect(results.first[:tag_names]).to contain_exactly(tag.name)
+      end
+
+      it 'returns an empty array if the tag group is private' do
+        tag_group = tag_group_with_permission(staff, full)
+
+        get '/tag_groups/filter/search.json', params: { ids: [tag_group.id] }
+        expect(response.status).to eq(200)
+
+        results = JSON.parse(response.body, symbolize_names: true).fetch(:results)
+
+        expect(results).to be_empty
+      end
+    end
+
+    context 'for regular users' do
+      before { sign_in(user) }
+
+      it 'returns the tag group with the associated tag names' do
+        tag_group = tag_group_with_permission(everyone, readonly)
+
+        get '/tag_groups/filter/search.json', params: { ids: [tag_group.id] }
+        expect(response.status).to eq(200)
+
+        results = JSON.parse(response.body, symbolize_names: true).fetch(:results)
+
+        expect(results.first[:name]).to eq(tag_group.name)
+        expect(results.first[:tag_names]).to contain_exactly(tag.name)
+      end
+
+      it 'returns an empty array if the tag group is private' do
+        tag_group = tag_group_with_permission(staff, full)
+
+        get '/tag_groups/filter/search.json', params: { ids: [tag_group.id] }
+        expect(response.status).to eq(200)
+
+        results = JSON.parse(response.body, symbolize_names: true).fetch(:results)
+
+        expect(results).to be_empty
+      end
+    end
+
+    def tag_group_with_permission(auto_group, permission_type)
+      Fabricate(:tag_group, tags: [tag]).tap do |tag_group|
+        tag_group.permissions = [[auto_group, permission_type]]
+        tag_group.save!
+      end
+    end
+  end
 end

GitHub sha: 8339b8f4

This commit appears in #12643 which was approved by eviltrout. It was merged by romanrizzi.