FEATURE: bulk remove tags (#10831)

diff --git a/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js b/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js
index 650b38f..8b902bf 100644
--- a/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js
+++ b/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js
@@ -68,6 +68,10 @@ addBulkButton("showAppendTagTopics", "append_tags", {
   class: "btn-default",
   enabledSetting: "tagging_enabled",
 });
+addBulkButton("removeTags", "remove_tags", {
+  icon: "tag",
+  class: "btn-danger",
+});
 addBulkButton("deleteTopics", "delete", {
   icon: "trash-alt",
   class: "btn-danger",
@@ -201,6 +205,10 @@ export default Controller.extend(ModalFunctionality, {
     resetRead() {
       this.performAndRefresh({ type: "reset_read" });
     },
+
+    removeTags() {
+      this.performAndRefresh({ type: "remove_tags" });
+    },
   },
 });
 
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 5c3006c..5fa50d9 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -2177,6 +2177,7 @@ en:
         choose_new_tags: "Choose new tags for these topics:"
         choose_append_tags: "Choose new tags to append for these topics:"
         changed_tags: "The tags of those topics were changed."
+        remove_tags: "Remove Tags"
 
       none:
         unread: "You have no unread topics."
diff --git a/lib/topics_bulk_action.rb b/lib/topics_bulk_action.rb
index 5c45a01..3187c2d 100644
--- a/lib/topics_bulk_action.rb
+++ b/lib/topics_bulk_action.rb
@@ -13,7 +13,8 @@ class TopicsBulkAction
   def self.operations
     @operations ||= %w(change_category close archive change_notification_level
                        reset_read dismiss_posts delete unlist archive_messages
-                       move_messages_to_inbox change_tags append_tags relist)
+                       move_messages_to_inbox change_tags append_tags remove_tags
+                       relist)
   end
 
   def self.register_operation(name, &block)
@@ -176,6 +177,15 @@ class TopicsBulkAction
     end
   end
 
+  def remove_tags
+    topics.each do |t|
+      if guardian.can_edit?(t)
+        TopicTag.where(topic_id: t.id).delete_all
+        @changed_ids << t.id
+      end
+    end
+  end
+
   def guardian
     @guardian ||= Guardian.new(@user)
   end
diff --git a/spec/components/topics_bulk_action_spec.rb b/spec/components/topics_bulk_action_spec.rb
index 58cc962..7d72320 100644
--- a/spec/components/topics_bulk_action_spec.rb
+++ b/spec/components/topics_bulk_action_spec.rb
@@ -305,4 +305,38 @@ describe TopicsBulkAction do
       end
     end
   end
+
+  describe "remove_tags" do
+    fab!(:tag1)  { Fabricate(:tag) }
+    fab!(:tag2)  { Fabricate(:tag) }
+
+    before do
+      SiteSetting.tagging_enabled = true
+      SiteSetting.min_trust_level_to_tag_topics = 0
+      topic.tags = [tag1, tag2]
+    end
+
+    it "can remove all tags" do
+      tba = TopicsBulkAction.new(topic.user, [topic.id], type: 'remove_tags')
+      topic_ids = tba.perform!
+      expect(topic_ids).to eq([topic.id])
+      topic.reload
+      expect(topic.tags.size).to eq(0)
+    end
+
+    context "when user can't edit topic" do
+      before do
+        Guardian.any_instance.expects(:can_edit?).returns(false)
+      end
+
+      it "doesn't remove the tags" do
+        tba = TopicsBulkAction.new(topic.user, [topic.id], type: 'remove_tags')
+        topic_ids = tba.perform!
+        expect(topic_ids).to eq([])
+        topic.reload
+        expect(topic.tags.map(&:name)).to contain_exactly(tag1.name, tag2.name)
+      end
+    end
+  end
+
 end

GitHub sha: f4c7c7bf

This commit appears in #10831 which was approved by gschlager. It was merged by techAPJ.

This commit has been mentioned on Discourse Meta. There might be relevant details there:

https://meta.discourse.org/t/bulk-actions-remove-tags-in-addition-to-change-tags/52145/8