FIX: improves tags checking when updating category of topic (#7921)

FIX: improves tags checking when updating category of topic (#7921)

  • will ensure this tag is not restricted to another category, and not only ensure this category can use it
  • will clean tags param, in case client is sending an empty array, eg: [""], this could be solved client-side, but we ensure it won’t happen ever this way
diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb
index 8116dfb..1c6a905 100644
--- a/app/controllers/topics_controller.rb
+++ b/app/controllers/topics_controller.rb
@@ -311,14 +311,15 @@ class TopicsController < ApplicationController
         return render_json_error(I18n.t('category.errors.not_found'))
       end
 
-      if category && topic_tags = (params[:tags] || topic.tags.pluck(:name))
-        category_tags = category.tags.pluck(:name)
-        category_tag_groups = category.tag_groups.joins(:tags).pluck("tags.name")
-        allowed_tags = (category_tags + category_tag_groups).uniq
+      if category && topic_tags = (params[:tags] || topic.tags.pluck(:name)).reject { |c| c.empty? }
+        if topic_tags.present?
+          allowed_tags = DiscourseTagging.filter_allowed_tags(
+            Tag.all,
+            guardian,
+            category: category
+          ).pluck("tags.name")
 
-        if topic_tags.present? && allowed_tags.present?
           invalid_tags = topic_tags - allowed_tags
-
           if !invalid_tags.empty?
             return render_json_error(I18n.t('category.errors.disallowed_topic_tags', tags: invalid_tags.join(", ")))
           end
diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb
index a5440b1..d46e89a 100644
--- a/spec/requests/topics_controller_spec.rb
+++ b/spec/requests/topics_controller_spec.rb
@@ -1133,6 +1133,32 @@ RSpec.describe TopicsController do
 
             expect(response.status).to eq(200)
           end
+
+          it 'can’t add a category-only tags from another category to a category' do
+            restricted_category.allowed_tags = [tag2.name]
+
+            put "/t/#{topic.slug}/#{topic.id}.json", params: {
+              tags: [tag2],
+              category_id: category.id
+            }
+
+            result = ::JSON.parse(response.body)
+            expect(response.status).to eq(422)
+            expect(result['errors']).to be_present
+            expect(topic.reload.category_id).not_to eq(restricted_category.id)
+          end
+
+          it 'will clean tag params' do
+            restricted_category.allowed_tags = [tag2.name]
+
+            put "/t/#{topic.slug}/#{topic.id}.json", params: {
+              tags: [""],
+              category_id: restricted_category.id
+            }
+
+            result = ::JSON.parse(response.body)
+            expect(response.status).to eq(200)
+          end
         end
 
         context "allow_uncategorized_topics is false" do

GitHub sha: e117b10e