diff --git a/app/controllers/drafts_controller.rb b/app/controllers/drafts_controller.rb index 2f0bb2c89bc..b2629fa7994 100644 --- a/app/controllers/drafts_controller.rb +++ b/app/controllers/drafts_controller.rb @@ -108,8 +108,15 @@ class DraftsController < ApplicationController if post.post_number == 1 conflict ||= original_title.present? && original_title != post.topic.title - conflict ||= - original_tags.present? && original_tags.sort != post.topic.tags.pluck(:name).sort + + # Since the topic might have hidden tags the current editor can't see, + # we need to check for conflicts even though there might not be any visible tags in the editor + if !conflict + original_tags = (original_tags || []).map(&:downcase).to_set + current_tags = post.topic.tags.pluck(:name).to_set + hidden_tags = DiscourseTagging.hidden_tag_names(@guardian).to_set + conflict = original_tags != (current_tags - hidden_tags) + end end if conflict diff --git a/spec/requests/drafts_controller_spec.rb b/spec/requests/drafts_controller_spec.rb index f7b15e32482..aa77f328599 100644 --- a/spec/requests/drafts_controller_spec.rb +++ b/spec/requests/drafts_controller_spec.rb @@ -164,6 +164,39 @@ RSpec.describe DraftsController do expect(response.parsed_body["conflict_user"]["id"]).to eq(post.last_editor.id) end + it "handles hidden tags when checking for tag conflict" do + sign_in(user) + + regular_tag = Fabricate(:tag) + admin_only_tag_one = Fabricate(:tag) + admin_only_tag_two = Fabricate(:tag) + + admin_only_tag_group = Fabricate(:tag_group) + admin_only_tag_group.tags = [admin_only_tag_one, admin_only_tag_two] + admin_only_tag_group.permissions = [ + [Group::AUTO_GROUPS[:admins], TagGroupPermission.permission_types[:full]], + ] + admin_only_tag_group.save! + + post = Fabricate(:post, user:) + post.topic.tags = [regular_tag, admin_only_tag_one] + + post "/drafts.json", + params: { + draft_key: "topic", + sequence: 0, + data: { + postId: post.id, + original_text: post.raw, + original_tags: [regular_tag.name], + action: "edit", + }.to_json, + } + + expect(response.status).to eq(200) + expect(response.parsed_body["conflict_user"]).to eq(nil) + end + it "cant trivially resolve conflicts without interaction" do sign_in(user)