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 d2026ff113e..5abf91625a2 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 58a8f98ba1f..5419779c25d 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 9b1c0454936..b92a8e2e167 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 140f2950296..045906a9b53 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