diff --git a/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 b/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 index ba5e6de1791..7be180cc777 100644 --- a/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 @@ -15,6 +15,7 @@ addBulkButton('showNotificationLevel', 'notification_level'); addBulkButton('resetRead', 'reset_read'); addBulkButton('unlistTopics', 'unlist_topics'); addBulkButton('showTagTopics', 'change_tags'); +addBulkButton('showAppendTagTopics', 'append_tags'); // Modal for performing bulk actions on topics export default Ember.Controller.extend(ModalFunctionality, { @@ -78,6 +79,9 @@ export default Ember.Controller.extend(ModalFunctionality, { actions: { showTagTopics() { this.set('tags', ''); + this.set('action', 'changeTags'); + this.set('label', 'change_tags'); + this.set('title', 'choose_new_tags'); this.send('changeBulkTemplate', 'bulk-tag'); }, @@ -85,6 +89,18 @@ export default Ember.Controller.extend(ModalFunctionality, { this.performAndRefresh({type: 'change_tags', tags: this.get('tags')}); }, + showAppendTagTopics() { + this.set('tags', ''); + this.set('action', 'appendTags'); + this.set('label', 'append_tags'); + this.set('title', 'choose_append_tags'); + this.send('changeBulkTemplate', 'bulk-tag'); + }, + + appendTags() { + this.performAndRefresh({type: 'append_tags', tags: this.get('tags')}); + }, + showChangeCategory() { this.send('changeBulkTemplate', 'modal/bulk-change-category'); this.set('modal.modalClass', 'topic-bulk-actions-modal full'); diff --git a/app/assets/javascripts/discourse/templates/bulk-tag.hbs b/app/assets/javascripts/discourse/templates/bulk-tag.hbs index 636f83cb343..4ed48ddc2b6 100644 --- a/app/assets/javascripts/discourse/templates/bulk-tag.hbs +++ b/app/assets/javascripts/discourse/templates/bulk-tag.hbs @@ -1,5 +1,5 @@ -

{{i18n "topics.bulk.choose_new_tags"}}

+

{{i18n (concat "topics.bulk." title)}}

{{tag-chooser tags=tags categoryId=categoryId}}

-{{d-button action="changeTags" disabled=emptyTags label="topics.bulk.change_tags"}} +{{d-button action=action disabled=emptyTags label=(concat "topics.bulk." label)}} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index b00207e7a9c..c39541bbdba 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1362,8 +1362,10 @@ en: selected: one: "You have selected 1 topic." other: "You have selected {{count}} topics." - change_tags: "Change Tags" + change_tags: "Replace Tags" + append_tags: "Append Tags" 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." none: diff --git a/lib/discourse_tagging.rb b/lib/discourse_tagging.rb index 4b7245a17db..d595ac2a86c 100644 --- a/lib/discourse_tagging.rb +++ b/lib/discourse_tagging.rb @@ -4,7 +4,7 @@ module DiscourseTagging TAGS_FILTER_REGEXP = /[\/\?#\[\]@!\$&'\(\)\*\+,;=\.%\\`^\s|\{\}"<>]+/ # /?#[]@!$&'()*+,;=.%\`^|{}"<> - def self.tag_topic_by_names(topic, guardian, tag_names_arg) + def self.tag_topic_by_names(topic, guardian, tag_names_arg, append=false) if SiteSetting.tagging_enabled tag_names = DiscourseTagging.tags_for_saving(tag_names_arg, guardian) || [] @@ -29,6 +29,7 @@ module DiscourseTagging if tag_names.present? category = topic.category + tag_names = tag_names + old_tag_names if append # guardian is explicitly nil cause we don't want to strip all # staff tags that already passed validation diff --git a/lib/topics_bulk_action.rb b/lib/topics_bulk_action.rb index 2b370911309..4df73ff29c3 100644 --- a/lib/topics_bulk_action.rb +++ b/lib/topics_bulk_action.rb @@ -11,7 +11,7 @@ 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) + move_messages_to_inbox change_tags append_tags) end def self.register_operation(name, &block) @@ -146,6 +146,20 @@ class TopicsBulkAction end end + def append_tags + tags = @operation[:tags] + tags = DiscourseTagging.tags_for_saving(tags, guardian) if tags.present? + + topics.each do |t| + if guardian.can_edit?(t) + if tags.present? + DiscourseTagging.tag_topic_by_names(t, guardian, tags, append=true) + end + @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 6aa99fcd106..ee6e94b48aa 100644 --- a/spec/components/topics_bulk_action_spec.rb +++ b/spec/components/topics_bulk_action_spec.rb @@ -232,4 +232,62 @@ describe TopicsBulkAction do end end end + + describe "append tags" do + let(:topic) { Fabricate(:topic) } + let(:tag1) { Fabricate(:tag) } + let(:tag2) { Fabricate(:tag) } + let(:tag3) { Fabricate(:tag) } + + before do + SiteSetting.tagging_enabled = true + SiteSetting.min_trust_level_to_tag_topics = 0 + topic.tags = [tag1, tag2] + end + + it "can append new or existing tags" do + SiteSetting.min_trust_to_create_tag = 0 + tba = TopicsBulkAction.new(topic.user, [topic.id], type: 'append_tags', tags: [tag1.name, tag3.name, 'newtag']) + topic_ids = tba.perform! + expect(topic_ids).to eq([topic.id]) + topic.reload + expect(topic.tags.map(&:name).sort).to eq([tag1.name, tag2.name, tag3.name, 'newtag'].sort) + end + + it "can append empty tags" do + tba = TopicsBulkAction.new(topic.user, [topic.id], type: 'append_tags', tags: []) + topic_ids = tba.perform! + expect(topic_ids).to eq([topic.id]) + topic.reload + expect(topic.tags.map(&:name).sort).to eq([tag1.name, tag2.name].sort) + end + + context "when the user can't create new topics" do + before do + SiteSetting.min_trust_to_create_tag = 4 + end + + it "can append existing tags but doesn't append new tags" do + tba = TopicsBulkAction.new(topic.user, [topic.id], type: 'append_tags', tags: [tag3.name, 'newtag']) + topic_ids = tba.perform! + expect(topic_ids).to eq([topic.id]) + topic.reload + expect(topic.tags.map(&:name)).to eq([tag1.name, tag2.name, tag3.name]) + end + end + + context "when user can't edit topic" do + before do + Guardian.any_instance.expects(:can_edit?).returns(false) + end + + it "doesn't change the tags" do + tba = TopicsBulkAction.new(topic.user, [topic.id], type: 'append_tags', tags: ['newtag', tag3.name]) + topic_ids = tba.perform! + expect(topic_ids).to eq([]) + topic.reload + expect(topic.tags.map(&:name)).to eq([tag1.name, tag2.name]) + end + end + end end