From 6b236d3c836f91d3c57227072320ed24f7a0a483 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 27 Oct 2015 16:57:40 -0400 Subject: [PATCH] FEATURE: Bulk Unlisting of topics --- .../controllers/topic-bulk-actions.js.es6 | 80 +++++++++---------- .../templates/modal/bulk_actions_buttons.hbs | 4 +- config/locales/client.en.yml | 1 + lib/topics_bulk_action.rb | 11 ++- spec/components/topics_bulk_action_spec.rb | 27 +++++++ 5 files changed, 77 insertions(+), 46 deletions(-) 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 b5e8bcbb4bf..2dd79219e53 100644 --- a/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 @@ -13,12 +13,13 @@ addBulkButton('closeTopics', 'close_topics'); addBulkButton('archiveTopics', 'archive_topics'); addBulkButton('showNotificationLevel', 'notification_level'); addBulkButton('resetRead', 'reset_read'); +addBulkButton('unlistTopics', 'unlist_topics'); // Modal for performing bulk actions on topics export default Ember.ArrayController.extend(ModalFunctionality, { buttonRows: null, - onShow: function() { + onShow() { this.set('controllers.modal.modalClass', 'topic-bulk-actions-modal small'); const buttonRows = []; @@ -36,87 +37,80 @@ export default Ember.ArrayController.extend(ModalFunctionality, { this.send('changeBulkTemplate', 'modal/bulk_actions_buttons'); }, - perform: function(operation) { + perform(operation) { this.set('loading', true); - var self = this, - topics = this.get('model'); - return Discourse.Topic.bulkOperation(this.get('model'), operation).then(function(result) { - self.set('loading', false); + const topics = this.get('model'); + return Discourse.Topic.bulkOperation(this.get('model'), operation).then(result => { + this.set('loading', false); if (result && result.topic_ids) { - return result.topic_ids.map(function (t) { - return topics.findBy('id', t); - }); + return result.topic_ids.map(t => topics.findBy('id', t)); } return result; - }).catch(function() { + }).catch(() => { bootbox.alert(I18n.t('generic_error')); - self.set('loading', false); + this.set('loading', false); }); }, - forEachPerformed: function(operation, cb) { - var self = this; - this.perform(operation).then(function (topics) { + forEachPerformed(operation, cb) { + this.perform(operation).then(topics => { if (topics) { topics.forEach(cb); - const refreshTarget = self.get('refreshTarget'); + const refreshTarget = this.get('refreshTarget'); if (refreshTarget) { refreshTarget.send('refresh'); } - self.send('closeModal'); + this.send('closeModal'); } }); }, - performAndRefresh: function(operation) { - const self = this; - return this.perform(operation).then(function() { - const refreshTarget = self.get('refreshTarget'); + performAndRefresh(operation) { + return this.perform(operation).then(() => { + const refreshTarget = this.get('refreshTarget'); if (refreshTarget) { refreshTarget.send('refresh'); } - self.send('closeModal'); + this.send('closeModal'); }); }, actions: { - showChangeCategory: function() { + showChangeCategory() { this.send('changeBulkTemplate', 'modal/bulk_change_category'); this.set('controllers.modal.modalClass', 'topic-bulk-actions-modal full'); }, - showNotificationLevel: function() { + showNotificationLevel() { this.send('changeBulkTemplate', 'modal/bulk_notification_level'); }, - deleteTopics: function() { + deleteTopics() { this.performAndRefresh({type: 'delete'}); }, - closeTopics: function() { - this.forEachPerformed({type: 'close'}, function(t) { - t.set('closed', true); - }); + closeTopics() { + this.forEachPerformed({type: 'close'}, t => t.set('closed', true)); }, - archiveTopics: function() { - this.forEachPerformed({type: 'archive'}, function(t) { - t.set('archived', true); - }); + archiveTopics() { + this.forEachPerformed({type: 'archive'}, t => t.set('archived', true)); }, - changeCategory: function() { - var categoryId = parseInt(this.get('newCategoryId'), 10) || 0, - category = Discourse.Category.findById(categoryId), - self = this; - this.perform({type: 'change_category', category_id: categoryId}).then(function(topics) { - topics.forEach(function(t) { - t.set('category', category); - }); - const refreshTarget = self.get('refreshTarget'); + unlistTopics() { + this.forEachPerformed({type: 'unlist'}, t => t.set('visible', false)); + }, + + changeCategory() { + const categoryId = parseInt(this.get('newCategoryId'), 10) || 0; + const category = Discourse.Category.findById(categoryId); + + this.perform({type: 'change_category', category_id: categoryId}).then(topics => { + topics.forEach(t => t.set('category', category)); + const refreshTarget = this.get('refreshTarget'); if (refreshTarget) { refreshTarget.send('refresh'); } - self.send('closeModal'); + this.send('closeModal'); }); }, - resetRead: function() { + resetRead() { this.performAndRefresh({ type: 'reset_read' }); } } diff --git a/app/assets/javascripts/discourse/templates/modal/bulk_actions_buttons.hbs b/app/assets/javascripts/discourse/templates/modal/bulk_actions_buttons.hbs index 6cd4580a538..94f87b8074a 100644 --- a/app/assets/javascripts/discourse/templates/modal/bulk_actions_buttons.hbs +++ b/app/assets/javascripts/discourse/templates/modal/bulk_actions_buttons.hbs @@ -1,6 +1,6 @@ -{{#each row in buttonRows}} +{{#each buttonRows as |row|}}

- {{#each button in row}} + {{#each row as |button|}} {{d-button action=button.action label=button.label}} {{/each}}

diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 6eff38ce549..64cec34cb3a 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1008,6 +1008,7 @@ en: topics: bulk: + unlist_topics: "Unlist Topics" reset_read: "Reset Read" delete: "Delete Topics" dismiss: "Dismiss" diff --git a/lib/topics_bulk_action.rb b/lib/topics_bulk_action.rb index 337c32eac1a..1a54ae9e3c8 100644 --- a/lib/topics_bulk_action.rb +++ b/lib/topics_bulk_action.rb @@ -8,7 +8,7 @@ class TopicsBulkAction end def self.operations - @operations ||= %w(change_category close archive change_notification_level reset_read dismiss_posts delete) + @operations ||= %w(change_category close archive change_notification_level reset_read dismiss_posts delete unlist) end def self.register_operation(name, &block) @@ -66,6 +66,15 @@ class TopicsBulkAction end end + def unlist + topics.each do |t| + if guardian.can_moderate?(t) + t.update_status('visible', false, @user) + @changed_ids << t.id + end + end + end + def archive topics.each do |t| if guardian.can_moderate?(t) diff --git a/spec/components/topics_bulk_action_spec.rb b/spec/components/topics_bulk_action_spec.rb index 2a3396d2dc5..24dc4310ba4 100644 --- a/spec/components/topics_bulk_action_spec.rb +++ b/spec/components/topics_bulk_action_spec.rb @@ -153,4 +153,31 @@ describe TopicsBulkAction do end end end + + describe "unlist" do + let(:topic) { Fabricate(:topic) } + + context "when the user can moderate the topic" do + it "unlists the topic and returns the topic_id" do + Guardian.any_instance.expects(:can_moderate?).returns(true) + Guardian.any_instance.expects(:can_create?).returns(true) + tba = TopicsBulkAction.new(topic.user, [topic.id], type: 'unlist') + topic_ids = tba.perform! + expect(topic_ids).to eq([topic.id]) + topic.reload + expect(topic).not_to be_visible + end + end + + context "when the user can't edit the topic" do + it "doesn't unlist the topic" do + Guardian.any_instance.expects(:can_moderate?).returns(false) + tba = TopicsBulkAction.new(topic.user, [topic.id], type: 'unlist') + topic_ids = tba.perform! + expect(topic_ids).to be_blank + topic.reload + expect(topic).to be_visible + end + end + end end