From 4b2e8af7114ee56fe030ebdf92dbc440e34fce47 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 28 Jul 2017 20:27:49 +0100 Subject: [PATCH 1/8] Backend support for group pms --- app/controllers/chat_controller.rb | 4 +-- app/models/rule.rb | 22 +++++++++++--- app/serializers/rule_serializer.rb | 13 ++++++++- app/services/manager.rb | 19 +++++++----- config/locales/server.en.yml | 1 + spec/models/rule_spec.rb | 46 +++++++++++++++++++++++++----- spec/services/manager_spec.rb | 27 ++++++++++++++++++ 7 files changed, 111 insertions(+), 21 deletions(-) diff --git a/app/controllers/chat_controller.rb b/app/controllers/chat_controller.rb index 42879f8..82126ea 100644 --- a/app/controllers/chat_controller.rb +++ b/app/controllers/chat_controller.rb @@ -118,7 +118,7 @@ class DiscourseChat::ChatController < ApplicationController def create_rule begin - hash = params.require(:rule).permit(:channel_id, :filter, :category_id, tags:[]) + hash = params.require(:rule).permit(:channel_id, :filter, :group_id, :category_id, tags:[]) rule = DiscourseChat::Rule.new(hash) @@ -135,7 +135,7 @@ class DiscourseChat::ChatController < ApplicationController def update_rule begin rule = DiscourseChat::Rule.find(params[:id].to_i) - hash = params.require(:rule).permit(:filter, :category_id, tags:[]) + hash = params.require(:rule).permit(:filter, :group_id, :category_id, tags:[]) if not rule.update(hash) raise Discourse::InvalidParameters, 'Rule is not valid' diff --git a/app/models/rule.rb b/app/models/rule.rb index 6ccd4f4..e485deb 100644 --- a/app/models/rule.rb +++ b/app/models/rule.rb @@ -2,7 +2,7 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel KEY_PREFIX = 'rule:' # Setup ActiveRecord::Store to use the JSON field to read/write these values - store :value, accessors: [ :channel_id, :category_id, :tags, :filter ], coder: JSON + store :value, accessors: [ :channel_id, :group_id, :category_id, :tags, :filter ], coder: JSON after_initialize :init_filter @@ -13,16 +13,29 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel validates :filter, :inclusion => { :in => %w(watch follow mute), :message => "%{value} is not a valid filter" } - validate :channel_valid?, :category_valid?, :tags_valid? + validate :channel_valid?, :category_and_group_valid?, :tags_valid? def channel_valid? - # Validate category + # Validate channel if not (DiscourseChat::Channel.where(id: channel_id).exists?) errors.add(:channel_id, "#{channel_id} is not a valid channel id") end end - def category_valid? + def category_and_group_valid? + if category_id and group_id + errors.add(:category_id, "cannot be specified in addition to group_id") + return + end + + if group_id + # Validate group + if not Group.where(id: group_id).exists? + errors.add(:group_id, "#{group_id} is not a valid group id") + end + return + end + # Validate category if not (category_id.nil? or Category.where(id: category_id).exists?) errors.add(:category_id, "#{category_id} is not a valid category id") @@ -79,6 +92,7 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel scope :with_channel_id, ->(channel_id) { where("value::json->>'channel_id'=?", channel_id.to_s)} scope :with_category_id, ->(category_id) { category_id.nil? ? where("(value::json->'category_id') IS NULL OR json_typeof(value::json->'category_id')='null'") : where("value::json->>'category_id'=?", category_id.to_s)} + scope :with_group_ids, ->(group_id) { where("value::json->>'group_id' IN (?)", group_id.map(&:to_s))} scope :order_by_precedence, ->{ order("CASE WHEN value::json->>'filter' = 'mute' THEN 1 diff --git a/app/serializers/rule_serializer.rb b/app/serializers/rule_serializer.rb index 57a0581..e3b9cb6 100644 --- a/app/serializers/rule_serializer.rb +++ b/app/serializers/rule_serializer.rb @@ -1,3 +1,14 @@ class DiscourseChat::RuleSerializer < ApplicationSerializer - attributes :id, :channel_id, :category_id, :tags, :filter + attributes :id, :channel_id, :group_id, :group_name, :category_id, :tags, :filter + + def group_name + if object.group_id + groups = Group.where(id:object.group_id) + if groups.exists? + return groups.first.name + else + return I18n.t("chat_integration.deleted_group") + end + end + end end \ No newline at end of file diff --git a/app/services/manager.rb b/app/services/manager.rb index 78bee22..d4fd9b9 100644 --- a/app/services/manager.rb +++ b/app/services/manager.rb @@ -18,14 +18,19 @@ module DiscourseChat topic = post.topic - # Abort if a private message (possible TODO: Add support for notifying about group PMs) - return if topic.blank? || topic.archetype == Archetype.private_message + # Abort if topic is blank... this should never be the case + return if topic.blank? - # Load all the rules that apply to this topic's category - matching_rules = DiscourseChat::Rule.with_category_id(topic.category_id) - - if topic.category # Also load the rules for the wildcard category - matching_rules += DiscourseChat::Rule.with_category_id(nil) + # If it's a private message, filter rules by groups, otherwise filter rules by category + if topic.archetype == Archetype.private_message + group_ids_with_access = topic.topic_allowed_groups.pluck(:group_id) + return if group_ids_with_access.empty? + matching_rules = DiscourseChat::Rule.with_group_ids(group_ids_with_access) + else + matching_rules = DiscourseChat::Rule.with_category_id(topic.category_id) + if topic.category # Also load the rules for the wildcard category + matching_rules += DiscourseChat::Rule.with_category_id(nil) + end end # If tagging is enabled, thow away rules that don't apply to this topic diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 559b491..7b889d1 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -60,6 +60,7 @@ en: all_categories: "(all categories)" deleted_category: "(deleted category)" + deleted_group: "(deleted group)" provider: diff --git a/spec/models/rule_spec.rb b/spec/models/rule_spec.rb index f292741..bace0c6 100644 --- a/spec/models/rule_spec.rb +++ b/spec/models/rule_spec.rb @@ -8,6 +8,8 @@ RSpec.describe DiscourseChat::Rule do let(:tag2){Fabricate(:tag)} let(:channel){DiscourseChat::Channel.create(provider:'dummy')} + let(:category) {Fabricate(:category)} + let(:group) {Fabricate(:group)} describe '.alloc_key' do it 'should return sequential numbers' do @@ -28,7 +30,7 @@ RSpec.describe DiscourseChat::Rule do rule = DiscourseChat::Rule.create({ channel: channel, - category_id: 1, + category_id: category.id, tags: [tag1.name, tag2.name], filter: 'watch' }) @@ -38,7 +40,7 @@ RSpec.describe DiscourseChat::Rule do loadedRule = DiscourseChat::Rule.find(rule.id) expect(loadedRule.channel.id).to eq(channel.id) - expect(loadedRule.category_id).to eq(1) + expect(loadedRule.category_id).to eq(category.id) expect(loadedRule.tags).to contain_exactly(tag1.name,tag2.name) expect(loadedRule.filter).to eq('watch') @@ -48,7 +50,7 @@ RSpec.describe DiscourseChat::Rule do before do rule = DiscourseChat::Rule.create({ channel: channel, - category_id: 1, + category_id: category.id, tags: [tag1.name, tag2.name] }) end @@ -102,15 +104,29 @@ RSpec.describe DiscourseChat::Rule do end it 'can be filtered by category' do - rule2 = DiscourseChat::Rule.create(channel:channel, category_id: 1) + rule2 = DiscourseChat::Rule.create(channel:channel, category_id: category.id) rule3 = DiscourseChat::Rule.create(channel:channel, category_id: nil) expect(DiscourseChat::Rule.all.length).to eq(3) - expect(DiscourseChat::Rule.with_category_id(1).length).to eq(2) + expect(DiscourseChat::Rule.with_category_id(category.id).length).to eq(2) expect(DiscourseChat::Rule.with_category_id(nil).length).to eq(1) end + it 'can be filtered by group' do + group1 = Fabricate(:group) + group2 = Fabricate(:group) + rule2 = DiscourseChat::Rule.create(channel:channel, group_id: group1.id) + rule3 = DiscourseChat::Rule.create(channel:channel, group_id: group2.id) + + expect(DiscourseChat::Rule.all.length).to eq(3) + + expect(DiscourseChat::Rule.with_category_id(category.id).length).to eq(1) + expect(DiscourseChat::Rule.with_group_ids([group1.id,group2.id]).length).to eq(2) + expect(DiscourseChat::Rule.with_group_ids([group1.id]).length).to eq(1) + expect(DiscourseChat::Rule.with_group_ids([group2.id]).length).to eq(1) + end + it 'can be sorted by precedence' do rule2 = DiscourseChat::Rule.create(channel:channel, filter:'mute') rule3 = DiscourseChat::Rule.create(channel:channel, filter:'follow') @@ -128,7 +144,7 @@ RSpec.describe DiscourseChat::Rule do DiscourseChat::Rule.create({ filter: 'watch', channel: channel, - category_id: 1, + category_id: category.id, }) end @@ -140,9 +156,25 @@ RSpec.describe DiscourseChat::Rule do expect(rule.valid?).to eq(false) end + it "doesn't allow both category and group to be set" do + expect(rule.valid?).to eq(true) + rule.group_id = group.id + expect(rule.valid?).to eq(false) + rule.category_id = nil + expect(rule.valid?).to eq(true) + end + + it 'validates group correctly' do + rule.category_id = nil + rule.group_id = group.id + expect(rule.valid?).to eq(true) + rule.group_id = -99 + expect(rule.valid?).to eq(false) + end + it 'validates category correctly' do expect(rule.valid?).to eq(true) - rule.category_id = 99 + rule.category_id = -99 expect(rule.valid?).to eq(false) end diff --git a/spec/services/manager_spec.rb b/spec/services/manager_spec.rb index 2180c04..e35cb09 100644 --- a/spec/services/manager_spec.rb +++ b/spec/services/manager_spec.rb @@ -6,6 +6,7 @@ RSpec.describe DiscourseChat::Manager do let(:manager) {::DiscourseChat::Manager} let(:category) {Fabricate(:category)} + let(:group) {Fabricate(:group)} let(:topic){Fabricate(:topic, category_id: category.id )} let(:first_post) {Fabricate(:post, topic: topic)} let(:second_post) {Fabricate(:post, topic: topic, post_number:2)} @@ -107,6 +108,32 @@ RSpec.describe DiscourseChat::Manager do expect(provider.sent_to_channel_ids).to contain_exactly() end + it "should work for group pms" do + DiscourseChat::Rule.create!(channel: chan1, filter: 'watch' ) # Wildcard watch + DiscourseChat::Rule.create!(channel: chan2, filter: 'watch', group_id: group.id ) # Group watch + + private_post = Fabricate(:private_message_post) + private_post.topic.invite_group(Fabricate(:user), group) + + manager.trigger_notifications(private_post.id) + + expect(provider.sent_to_channel_ids).to contain_exactly(chan2.id) + end + + it "should work for pms with multiple groups" do + group2 = Fabricate(:group) + DiscourseChat::Rule.create!(channel: chan1, filter: 'watch', group_id: group.id ) + DiscourseChat::Rule.create!(channel: chan2, filter: 'watch', group_id: group2.id ) + + private_post = Fabricate(:private_message_post) + private_post.topic.invite_group(Fabricate(:user), group) + private_post.topic.invite_group(Fabricate(:user), group2) + + manager.trigger_notifications(private_post.id) + + expect(provider.sent_to_channel_ids).to contain_exactly(chan1.id, chan2.id) + end + it "should not notify about posts the chat_user cannot see" do DiscourseChat::Rule.create!(channel: chan1, filter: 'follow', category_id: nil ) # Wildcard watch From d437634f6184a7d5edb970bc7099a5f5691d7ef3 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Mon, 31 Jul 2017 17:09:21 +0100 Subject: [PATCH 2/8] Move rule editing into a modal dialog --- app/models/rule.rb | 23 ++---- .../admin/components/channel-data.js.es6 | 3 + .../admin/components/channel-details.js.es6 | 7 +- .../admin/components/rule-row.js.es6 | 24 +----- .../admin-plugins-chat-provider.js.es6 | 11 +++ .../admin-plugins-chat-edit-rule.js.es6 | 42 ++++++++++ assets/javascripts/admin/models/rule.js.es6 | 4 +- .../modal/admin-plugins-chat-edit-rule.hbs | 81 +++++++++++++++++++ .../templates/admin/plugins-chat-provider.hbs | 2 + .../templates/components/channel-data.hbs | 7 ++ .../templates/components/channel-details.hbs | 11 +-- .../templates/components/rule-row.hbs | 46 +++-------- .../stylesheets/chat-integration-admin.scss | 5 +- config/locales/client.en.yml | 14 ++++ 14 files changed, 197 insertions(+), 83 deletions(-) create mode 100644 assets/javascripts/admin/components/channel-data.js.es6 create mode 100644 assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 create mode 100644 assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-rule.hbs create mode 100644 assets/javascripts/discourse/templates/components/channel-data.hbs diff --git a/app/models/rule.rb b/app/models/rule.rb index e485deb..44c0125 100644 --- a/app/models/rule.rb +++ b/app/models/rule.rb @@ -61,21 +61,14 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel end end - # Don't want this to end up as anything other than an integer - def category_id=(val) - if val.nil? or val.blank? - super(nil) - else - super(val.to_i) - end - end - - # Don't want this to end up as anything other than an integer - def channel_id=(val) - if val.nil? or val.blank? - super(nil) - else - super(val.to_i) + # These are only allowed to be integers + %w(channel_id category_id group_id).each do |name| + define_method "#{name}=" do |val| + if val.nil? or val.blank? + super(nil) + else + super(val.to_i) + end end end diff --git a/assets/javascripts/admin/components/channel-data.js.es6 b/assets/javascripts/admin/components/channel-data.js.es6 new file mode 100644 index 0000000..259fb6c --- /dev/null +++ b/assets/javascripts/admin/components/channel-data.js.es6 @@ -0,0 +1,3 @@ +export default Ember.Component.extend({ + classNames: ['channel-info'], +}); \ No newline at end of file diff --git a/assets/javascripts/admin/components/channel-details.js.es6 b/assets/javascripts/admin/components/channel-details.js.es6 index 08fcd1b..3b9195c 100644 --- a/assets/javascripts/admin/components/channel-details.js.es6 +++ b/assets/javascripts/admin/components/channel-details.js.es6 @@ -26,8 +26,11 @@ export default Ember.Component.extend({ }, createRule(channel){ - var newRule = this.get('store').createRecord('rule',{channel_id: channel.id}); - channel.rules.pushObject(newRule) + this.sendAction('createRule', channel) + }, + + editRule(rule){ + this.sendAction('editRule', rule, this.get('channel')) }, showError(error_key){ diff --git a/assets/javascripts/admin/components/rule-row.js.es6 b/assets/javascripts/admin/components/rule-row.js.es6 index 7622fa1..9782507 100644 --- a/assets/javascripts/admin/components/rule-row.js.es6 +++ b/assets/javascripts/admin/components/rule-row.js.es6 @@ -2,37 +2,21 @@ import { popupAjaxError } from 'discourse/lib/ajax-error'; export default Ember.Component.extend({ tagName: 'tr', - editing: false, - - autoEdit: function(){ - if(!this.get('rule').id){ - this.set('editing', true); - } - }.on('init'), actions: { edit: function(){ - this.set('editing', true); + this.sendAction('edit', this.get('rule')) }, - - cancel: function(){ - this.send('refresh'); - }, - - save: function(){ - this.get('rule').save().then(result => { - this.send('refresh'); - }).catch(popupAjaxError); - }, - delete(rule){ rule.destroyRecord().then(() => { this.send('refresh'); }).catch(popupAjaxError) }, - refresh: function(){ this.sendAction('refresh'); } + + + } }); \ No newline at end of file diff --git a/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 b/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 index f52965c..c3f90e6 100644 --- a/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 +++ b/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 @@ -35,6 +35,17 @@ export default Ember.Controller.extend({ showModal('admin-plugins-chat-test', { model: model, admin: true }); }, + createRule(channel){ + this.set('modalShowing', true); + var model = {rule: this.store.createRecord('rule',{channel_id: channel.id}), channel:channel, provider:this.get('model.provider')}; + showModal('admin-plugins-chat-edit-rule', { model: model, admin: true }); + }, + editRule(rule, channel){ + this.set('modalShowing', true); + var model = {rule: rule, channel:channel, provider:this.get('model.provider')}; + showModal('admin-plugins-chat-edit-rule', { model: model, admin: true }); + }, + } }); \ No newline at end of file diff --git a/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 b/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 new file mode 100644 index 0000000..220d525 --- /dev/null +++ b/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 @@ -0,0 +1,42 @@ +import Rule from 'discourse/plugins/discourse-chat-integration/admin/models/rule' +import ModalFunctionality from 'discourse/mixins/modal-functionality'; +import { ajax } from 'discourse/lib/ajax'; +import { extractError } from 'discourse/lib/ajax-error'; +import InputValidation from 'discourse/models/input-validation'; + +export default Ember.Controller.extend(ModalFunctionality, { + + setupKeydown: function() { + Ember.run.schedule('afterRender', () => { + $('#chat_integration_edit_channel_modal').keydown(e => { + if (e.keyCode === 13) { + this.send('save'); + } + }); + }); + }.on('init'), + + + saveDisabled: function(){ + return false; + }.property(), + + actions: { + cancel: function(){ + this.send('closeModal'); + }, + + save: function(){ + if(this.get('saveDisabled')){return}; + + const self = this; + + this.get('model.rule').save().then(function(result) { + self.send('closeModal'); + }).catch(function(error) { + self.flash(extractError(error), 'error'); + }); + + } + } +}); \ No newline at end of file diff --git a/assets/javascripts/admin/models/rule.js.es6 b/assets/javascripts/admin/models/rule.js.es6 index 44fe2c8..f225d45 100644 --- a/assets/javascripts/admin/models/rule.js.es6 +++ b/assets/javascripts/admin/models/rule.js.es6 @@ -30,12 +30,12 @@ export default RestModel.extend({ }, updateProperties() { - var prop_names = ['category_id','tags','filter']; + var prop_names = ['category_id','group_id','tags','filter']; return this.getProperties(prop_names); }, createProperties() { - var prop_names = ['channel_id', 'category_id','tags','filter']; + var prop_names = ['channel_id', 'category_id','group_id','tags','filter']; return this.getProperties(prop_names); } diff --git a/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-rule.hbs b/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-rule.hbs new file mode 100644 index 0000000..d7e4c68 --- /dev/null +++ b/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-rule.hbs @@ -0,0 +1,81 @@ +{{#d-modal-body id="chat_integration_edit_rule_modal" title="chat_integration.edit_rule_modal.title"}} +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{#if siteSettings.tagging_enabled}} + + + + + + + + + {{/if}} + +
+ {{i18n (concat 'chat_integration.provider.' model.channel.provider '.title')}} +
+ {{channel-data provider=model.provider channel=model.channel}} +
+ {{combo-box name="filter" content=model.rule.available_filters value=model.rule.filter}} +
+ {{category-chooser + name="category" + value=model.rule.category_id + rootNoneLabel="chat_integration.all_categories" + rootNone=true + overrideWidths=false + }} +
+ {{tag-chooser placeholderKey="chat_integration.all_tags" name="tags" tags=model.rule.tags}} +
+ +
+
+{{/d-modal-body}} + + \ No newline at end of file diff --git a/assets/javascripts/discourse/templates/admin/plugins-chat-provider.hbs b/assets/javascripts/discourse/templates/admin/plugins-chat-provider.hbs index e4b2946..ee1d6bc 100644 --- a/assets/javascripts/discourse/templates/admin/plugins-chat-provider.hbs +++ b/assets/javascripts/discourse/templates/admin/plugins-chat-provider.hbs @@ -14,6 +14,8 @@ refresh='refresh' edit='editChannel' test='testChannel' + createRule='createRule' + editRule='editRule' }} {{/each}} diff --git a/assets/javascripts/discourse/templates/components/channel-data.hbs b/assets/javascripts/discourse/templates/components/channel-data.hbs new file mode 100644 index 0000000..bdcdfbc --- /dev/null +++ b/assets/javascripts/discourse/templates/components/channel-data.hbs @@ -0,0 +1,7 @@ +{{# each provider.channel_parameters as |param|}} + {{#if param.hidden}}{{else}} + {{i18n (concat 'chat_integration.provider.' channel.provider '.param.' param.key '.title')}}: + {{get channel.data param.key}} +
+ {{/if}} +{{/each}} \ No newline at end of file diff --git a/assets/javascripts/discourse/templates/components/channel-details.hbs b/assets/javascripts/discourse/templates/components/channel-details.hbs index 83412ff..b50b5a9 100644 --- a/assets/javascripts/discourse/templates/components/channel-details.hbs +++ b/assets/javascripts/discourse/templates/components/channel-details.hbs @@ -12,14 +12,7 @@ {{/if}} - {{# each provider.channel_parameters as |param|}} - - {{#if param.hidden}}{{else}} - {{i18n (concat 'chat_integration.provider.' channel.provider '.param.' param.key '.title')}}: - {{get channel.data param.key}} -
- {{/if}} - {{/each}} + {{channel-data provider=provider channel=channel}} @@ -43,7 +36,7 @@ {{#each channel.rules as |rule|}} - {{rule-row rule=rule refresh=refresh}} + {{rule-row rule=rule edit='editRule' refresh='refresh'}} {{/each}} diff --git a/assets/javascripts/discourse/templates/components/rule-row.hbs b/assets/javascripts/discourse/templates/components/rule-row.hbs index 9af5d24..59efe10 100644 --- a/assets/javascripts/discourse/templates/components/rule-row.hbs +++ b/assets/javascripts/discourse/templates/components/rule-row.hbs @@ -1,53 +1,31 @@ - {{#if editing}} - {{combo-box name="filter" content=rule.available_filters value=rule.filter}} - {{else}} - {{rule.filterName}} - {{/if}} + {{rule.filterName}} - - {{#if editing}} - {{category-chooser - name="category" - value=rule.category_id - rootNoneLabel="chat_integration.all_categories" - rootNone=true - overrideWidths=false - }} + {{#if rule.category}} + {{category-link rule.category allowUncategorized="true" link="false"}} + {{else if rule.group_id}} + {{i18n "chat_integration.group_prefix"}} {{rule.group_name}} {{else}} - {{#if rule.category}} - {{category-link rule.category allowUncategorized="true" link="false"}} - {{else}} - {{i18n "chat_integration.all_categories"}} - {{/if}} + {{i18n "chat_integration.all_categories"}} {{/if}} {{#if siteSettings.tagging_enabled}} - {{#if editing}} - {{tag-chooser placeholderKey="chat_integration.all_tags" name="tags" tags=rule.tags}} + {{#if rule.tags}} + {{rule.tags}} {{else}} - {{#if rule.tags}} - {{rule.tags}} - {{else}} - {{i18n "chat_integration.all_tags"}} - {{/if}} + {{i18n "chat_integration.all_tags"}} {{/if}} {{/if}} - - {{#if editing}} - {{d-button action="save" actionParam=rule icon="check" class="ok" title="chat_integration.rule_table.save_rule"}} - {{d-button action="cancel" actionParam=rule icon="times" class="cancel" title="chat_integration.rule_table.cancel_edit"}} - {{else}} - {{d-button action="edit" actionParam=rule icon="pencil" class="edit" title="chat_integration.rule_table.edit_rule"}} - {{d-button action="delete" actionParam=rule icon="trash-o" class="delete" title="chat_integration.rule_table.delete_rule"}} - {{/if}} + {{d-button action="edit" actionParam=rule icon="pencil" class="edit" title="chat_integration.rule_table.edit_rule"}} + {{d-button action="delete" actionParam=rule icon="trash-o" class="delete" title="chat_integration.rule_table.delete_rule"}} + diff --git a/assets/stylesheets/chat-integration-admin.scss b/assets/stylesheets/chat-integration-admin.scss index 7407cde..fda4780 100644 --- a/assets/stylesheets/chat-integration-admin.scss +++ b/assets/stylesheets/chat-integration-admin.scss @@ -53,7 +53,7 @@ } -#chat_integration_edit_channel_modal, #chat_integration_test_modal{ +#chat_integration_edit_channel_modal, #chat_integration_test_modal, #chat_integration_edit_rule_modal{ table{ width:100%; @@ -90,5 +90,8 @@ margin-top: 0px; } + .field-name{ + font-weight: bold; + } } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 0094d9a..fdda3a9 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -6,6 +6,7 @@ en: no_providers: "You need to enable some providers in the plugin settings" channels_with_errors: "Some channels for this provider failed last time messages were sent. Click the error icon(s) to learn more." channel_exception: "An unknown error occured when a message was last sent to this channel. Check the site logs for more information." + group_prefix: "Group:" all_categories: "(all categories)" all_tags: "(all tags)" create_rule: "Create Rule" @@ -39,6 +40,19 @@ en: channel_validation: ok: "Valid" fail: "Invalid format" + edit_rule_modal: + title: Edit Rule + save: Save Rule + cancel: Cancel + provider: Provider + channel: Channel + filter: Filter + category: Category + tags: Tags + instructions: + filter: "Notification level. Mute overrides other matching rules." + category: "This rule will only apply to topics in the specified category." + tags: "If specified, this rule will only apply to topics which have at least one of these tags." provider: From 209daf780107ecf2d3cd643f61b5b9e883e30227 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 1 Aug 2017 15:20:00 +0100 Subject: [PATCH 3/8] =?UTF-8?q?Add=20group=20messages=20support=20to=20adm?= =?UTF-8?q?in=20UI,=20and=20add=20a=20=E2=80=98type=E2=80=99=20field=20for?= =?UTF-8?q?=20further=20improvements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/chat_controller.rb | 4 +- app/models/channel.rb | 2 +- app/models/rule.rb | 43 +++++++++----- app/serializers/rule_serializer.rb | 2 +- app/services/manager.rb | 2 +- .../admin-plugins-chat-provider.js.es6 | 4 +- .../admin-plugins-chat-edit-rule.js.es6 | 8 ++- assets/javascripts/admin/models/rule.js.es6 | 21 ++++++- .../routes/admin-plugins-chat-provider.js.es6 | 6 +- .../modal/admin-plugins-chat-edit-rule.hbs | 58 ++++++++++++++----- config/locales/client.en.yml | 7 +++ spec/controllers/chat_controller_spec.rb | 2 +- spec/models/rule_spec.rb | 6 +- spec/services/manager_spec.rb | 6 +- 14 files changed, 124 insertions(+), 47 deletions(-) diff --git a/app/controllers/chat_controller.rb b/app/controllers/chat_controller.rb index 82126ea..257cafb 100644 --- a/app/controllers/chat_controller.rb +++ b/app/controllers/chat_controller.rb @@ -118,7 +118,7 @@ class DiscourseChat::ChatController < ApplicationController def create_rule begin - hash = params.require(:rule).permit(:channel_id, :filter, :group_id, :category_id, tags:[]) + hash = params.require(:rule).permit(:channel_id, :type, :filter, :group_id, :category_id, tags:[]) rule = DiscourseChat::Rule.new(hash) @@ -135,7 +135,7 @@ class DiscourseChat::ChatController < ApplicationController def update_rule begin rule = DiscourseChat::Rule.find(params[:id].to_i) - hash = params.require(:rule).permit(:filter, :group_id, :category_id, tags:[]) + hash = params.require(:rule).permit(:type, :filter, :group_id, :category_id, tags:[]) if not rule.update(hash) raise Discourse::InvalidParameters, 'Rule is not valid' diff --git a/app/models/channel.rb b/app/models/channel.rb index c2730fb..1fe280d 100644 --- a/app/models/channel.rb +++ b/app/models/channel.rb @@ -59,7 +59,7 @@ class DiscourseChat::Channel < DiscourseChat::PluginModel end def rules - DiscourseChat::Rule.with_channel_id(id) + DiscourseChat::Rule.with_channel_id(id).order_by_precedence end scope :with_provider, ->(provider) { where("value::json->>'provider'=?", provider)} diff --git a/app/models/rule.rb b/app/models/rule.rb index 44c0125..8668888 100644 --- a/app/models/rule.rb +++ b/app/models/rule.rb @@ -2,18 +2,22 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel KEY_PREFIX = 'rule:' # Setup ActiveRecord::Store to use the JSON field to read/write these values - store :value, accessors: [ :channel_id, :group_id, :category_id, :tags, :filter ], coder: JSON + store :value, accessors: [ :channel_id, :type, :group_id, :category_id, :tags, :filter ], coder: JSON after_initialize :init_filter def init_filter self.filter ||= 'watch' + self.type ||= 'normal' end validates :filter, :inclusion => { :in => %w(watch follow mute), :message => "%{value} is not a valid filter" } - validate :channel_valid?, :category_and_group_valid?, :tags_valid? + validates :type, :inclusion => { :in => %w(normal group_message), + :message => "%{value} is not a valid filter" } + + validate :channel_valid?, :category_valid?, :group_valid?, :tags_valid? def channel_valid? # Validate channel @@ -22,19 +26,12 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel end end - def category_and_group_valid? - if category_id and group_id - errors.add(:category_id, "cannot be specified in addition to group_id") - return + def category_valid? + if type != 'normal' && !category_id.nil? + errors.add(:category_id, "cannot be specified for that type of rule") end - if group_id - # Validate group - if not Group.where(id: group_id).exists? - errors.add(:group_id, "#{group_id} is not a valid group id") - end - return - end + return unless type == 'normal' # Validate category if not (category_id.nil? or Category.where(id: category_id).exists?) @@ -42,6 +39,19 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel end end + def group_valid? + if type == 'normal' && !group_id.nil? + errors.add(:group_id, "cannot be specified for that type of rule") + end + + return if type == 'normal' + + # Validate group + if not Group.where(id: group_id).exists? + errors.add(:group_id, "#{group_id} is not a valid group id") + end + end + def tags_valid? # Validate tags return if tags.nil? @@ -81,6 +91,8 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel self.channel_id = val.id end + scope :with_type, ->(type) { where("value::json->>'type'=?", type.to_s)} + scope :with_channel, ->(channel) { with_channel_id(channel.id) } scope :with_channel_id, ->(channel_id) { where("value::json->>'channel_id'=?", channel_id.to_s)} @@ -88,6 +100,11 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel scope :with_group_ids, ->(group_id) { where("value::json->>'group_id' IN (?)", group_id.map(&:to_s))} scope :order_by_precedence, ->{ order("CASE + WHEN value::json->>'type' = 'group_mention' THEN 1 + WHEN value::json->>'type' = 'group_message' THEN 2 + ELSE 3 + END", + "CASE WHEN value::json->>'filter' = 'mute' THEN 1 WHEN value::json->>'filter' = 'watch' THEN 2 WHEN value::json->>'filter' = 'follow' THEN 3 diff --git a/app/serializers/rule_serializer.rb b/app/serializers/rule_serializer.rb index e3b9cb6..efaf02b 100644 --- a/app/serializers/rule_serializer.rb +++ b/app/serializers/rule_serializer.rb @@ -1,5 +1,5 @@ class DiscourseChat::RuleSerializer < ApplicationSerializer - attributes :id, :channel_id, :group_id, :group_name, :category_id, :tags, :filter + attributes :id, :channel_id, :type, :group_id, :group_name, :category_id, :tags, :filter def group_name if object.group_id diff --git a/app/services/manager.rb b/app/services/manager.rb index d4fd9b9..11bd537 100644 --- a/app/services/manager.rb +++ b/app/services/manager.rb @@ -25,7 +25,7 @@ module DiscourseChat if topic.archetype == Archetype.private_message group_ids_with_access = topic.topic_allowed_groups.pluck(:group_id) return if group_ids_with_access.empty? - matching_rules = DiscourseChat::Rule.with_group_ids(group_ids_with_access) + matching_rules = DiscourseChat::Rule.with_type('group_message').with_group_ids(group_ids_with_access) else matching_rules = DiscourseChat::Rule.with_category_id(topic.category_id) if topic.category # Also load the rules for the wildcard category diff --git a/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 b/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 index c3f90e6..1d15db3 100644 --- a/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 +++ b/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 @@ -37,12 +37,12 @@ export default Ember.Controller.extend({ createRule(channel){ this.set('modalShowing', true); - var model = {rule: this.store.createRecord('rule',{channel_id: channel.id}), channel:channel, provider:this.get('model.provider')}; + var model = {rule: this.store.createRecord('rule',{channel_id: channel.id}), channel:channel, provider:this.get('model.provider'), groups:this.get('model.groups')}; showModal('admin-plugins-chat-edit-rule', { model: model, admin: true }); }, editRule(rule, channel){ this.set('modalShowing', true); - var model = {rule: rule, channel:channel, provider:this.get('model.provider')}; + var model = {rule: rule, channel:channel, provider:this.get('model.provider'), groups:this.get('model.groups')}; showModal('admin-plugins-chat-edit-rule', { model: model, admin: true }); }, diff --git a/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 b/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 index 220d525..aa32187 100644 --- a/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 +++ b/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 @@ -3,9 +3,9 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; import { ajax } from 'discourse/lib/ajax'; import { extractError } from 'discourse/lib/ajax-error'; import InputValidation from 'discourse/models/input-validation'; +import computed from "ember-addons/ember-computed-decorators"; export default Ember.Controller.extend(ModalFunctionality, { - setupKeydown: function() { Ember.run.schedule('afterRender', () => { $('#chat_integration_edit_channel_modal').keydown(e => { @@ -16,11 +16,15 @@ export default Ember.Controller.extend(ModalFunctionality, { }); }.on('init'), - saveDisabled: function(){ return false; }.property(), + @computed('model.rule.type') + showCategory: function(type){ + return (type == "normal") + }, + actions: { cancel: function(){ this.send('closeModal'); diff --git a/assets/javascripts/admin/models/rule.js.es6 b/assets/javascripts/admin/models/rule.js.es6 index f225d45..70fab17 100644 --- a/assets/javascripts/admin/models/rule.js.es6 +++ b/assets/javascripts/admin/models/rule.js.es6 @@ -9,12 +9,29 @@ export default RestModel.extend({ { id: 'mute', name: I18n.t('chat_integration.filter.mute'), icon: 'times-circle' } ], + available_types: [ + { id: 'normal', name: I18n.t('chat_integration.type.normal')}, + { id: 'group_message', name: I18n.t('chat_integration.type.group_message')}, + { id: 'group_mention', name: I18n.t('chat_integration.type.group_mention')} + ], + category_id: null, tags: null, channel_id: null, filter: 'watch', + type: 'normal', error_key: null, + + removeUnneededInfo: function(){ + const type=this.get('type'); + if(type=='normal'){ + this.set('group_id', null); + }else{ + this.set('category_id', null); + } + }.observes('type'), + @computed('category_id') category(categoryId) { if (categoryId){ @@ -30,12 +47,12 @@ export default RestModel.extend({ }, updateProperties() { - var prop_names = ['category_id','group_id','tags','filter']; + var prop_names = ['type','category_id','group_id','tags','filter']; return this.getProperties(prop_names); }, createProperties() { - var prop_names = ['channel_id', 'category_id','group_id','tags','filter']; + var prop_names = ['type','channel_id', 'category_id','group_id','tags','filter']; return this.getProperties(prop_names); } diff --git a/assets/javascripts/admin/routes/admin-plugins-chat-provider.js.es6 b/assets/javascripts/admin/routes/admin-plugins-chat-provider.js.es6 index 7889816..216f407 100644 --- a/assets/javascripts/admin/routes/admin-plugins-chat-provider.js.es6 +++ b/assets/javascripts/admin/routes/admin-plugins-chat-provider.js.es6 @@ -1,11 +1,15 @@ import { ajax } from 'discourse/lib/ajax'; +import Group from 'discourse/models/group'; export default Discourse.Route.extend({ model(params, transition) { return Ember.RSVP.hash({ channels: this.store.findAll('channel', {provider: params.provider}), - provider: this.modelFor("admin-plugins-chat").findBy('id',params.provider) + provider: this.modelFor("admin-plugins-chat").findBy('id',params.provider), + groups: Group.findAll().then(groups => { + return groups.filter(g => !g.get('automatic')); + }) }).then(value => { value.channels.forEach(channel => { channel.set('rules', channel.rules.map(rule => { diff --git a/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-rule.hbs b/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-rule.hbs index d7e4c68..4b2e83c 100644 --- a/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-rule.hbs +++ b/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-rule.hbs @@ -25,6 +25,17 @@ + + + + {{combo-box name="type" content=model.rule.available_types value=model.rule.type}} + + + + + + + @@ -36,22 +47,37 @@ - - - - {{category-chooser - name="category" - value=model.rule.category_id - rootNoneLabel="chat_integration.all_categories" - rootNone=true - overrideWidths=false - }} - - - - - - + {{#if showCategory}} + + + + {{category-chooser + name="category" + value=model.rule.category_id + rootNoneLabel="chat_integration.all_categories" + rootNone=true + overrideWidths=false + }} + + + + + + + {{else}} + + + + {{combo-box content=model.groups valueAttribute="id" value=model.rule.group_id none="chat_integration.choose_group"}} + + + + + + + {{/if}} + + {{#if siteSettings.tagging_enabled}} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index fdda3a9..43d469f 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -22,6 +22,10 @@ en: close: "Close" error: "An unknown error occured while sending the message. Check the site logs for more information." success: "Message sent successfully" + type: + normal: Normal + group_message: Group Message + group_mention: Group Mention filter: mute: 'Mute' follow: 'First post only' @@ -45,13 +49,16 @@ en: save: Save Rule cancel: Cancel provider: Provider + type: Type channel: Channel filter: Filter category: Category + group: Group tags: Tags instructions: filter: "Notification level. Mute overrides other matching rules." category: "This rule will only apply to topics in the specified category." + group: "This rule will apply to posts referencing this group" tags: "If specified, this rule will only apply to topics which have at least one of these tags." provider: diff --git a/spec/controllers/chat_controller_spec.rb b/spec/controllers/chat_controller_spec.rb index dc76526..dc1eabc 100644 --- a/spec/controllers/chat_controller_spec.rb +++ b/spec/controllers/chat_controller_spec.rb @@ -105,7 +105,7 @@ describe 'Chat Controller', type: :request do "provider" => 'dummy', "data" => {}, "error_key" => nil, - "rules" => [{"id" => rule.id, "filter" => "follow", "channel_id" => channel.id, "category_id" => category.id, "tags" => [tag.name]}] + "rules" => [{"id" => rule.id, "type" => 'normal', "group_name" => nil, "group_id" => nil, "filter" => "follow", "channel_id" => channel.id, "category_id" => category.id, "tags" => [tag.name]}] ) end diff --git a/spec/models/rule_spec.rb b/spec/models/rule_spec.rb index bace0c6..b698383 100644 --- a/spec/models/rule_spec.rb +++ b/spec/models/rule_spec.rb @@ -116,8 +116,8 @@ RSpec.describe DiscourseChat::Rule do it 'can be filtered by group' do group1 = Fabricate(:group) group2 = Fabricate(:group) - rule2 = DiscourseChat::Rule.create(channel:channel, group_id: group1.id) - rule3 = DiscourseChat::Rule.create(channel:channel, group_id: group2.id) + rule2 = DiscourseChat::Rule.create!(channel:channel, type:'group_message', group_id: group1.id) + rule3 = DiscourseChat::Rule.create!(channel:channel, type:'group_message', group_id: group2.id) expect(DiscourseChat::Rule.all.length).to eq(3) @@ -161,12 +161,14 @@ RSpec.describe DiscourseChat::Rule do rule.group_id = group.id expect(rule.valid?).to eq(false) rule.category_id = nil + rule.type = "group_message" expect(rule.valid?).to eq(true) end it 'validates group correctly' do rule.category_id = nil rule.group_id = group.id + rule.type = "group_message" expect(rule.valid?).to eq(true) rule.group_id = -99 expect(rule.valid?).to eq(false) diff --git a/spec/services/manager_spec.rb b/spec/services/manager_spec.rb index e35cb09..c06ea46 100644 --- a/spec/services/manager_spec.rb +++ b/spec/services/manager_spec.rb @@ -110,7 +110,7 @@ RSpec.describe DiscourseChat::Manager do it "should work for group pms" do DiscourseChat::Rule.create!(channel: chan1, filter: 'watch' ) # Wildcard watch - DiscourseChat::Rule.create!(channel: chan2, filter: 'watch', group_id: group.id ) # Group watch + DiscourseChat::Rule.create!(channel: chan2, type: 'group_message', filter: 'watch', group_id: group.id ) # Group watch private_post = Fabricate(:private_message_post) private_post.topic.invite_group(Fabricate(:user), group) @@ -122,8 +122,8 @@ RSpec.describe DiscourseChat::Manager do it "should work for pms with multiple groups" do group2 = Fabricate(:group) - DiscourseChat::Rule.create!(channel: chan1, filter: 'watch', group_id: group.id ) - DiscourseChat::Rule.create!(channel: chan2, filter: 'watch', group_id: group2.id ) + DiscourseChat::Rule.create!(channel: chan1, type: 'group_message', filter: 'watch', group_id: group.id ) + DiscourseChat::Rule.create!(channel: chan2, type: 'group_message', filter: 'watch', group_id: group2.id ) private_post = Fabricate(:private_message_post) private_post.topic.invite_group(Fabricate(:user), group) From f3347b0a92c4877d2e7395c8e549855a0480fe93 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 1 Aug 2017 17:11:34 +0100 Subject: [PATCH 4/8] Add support for group mentions --- app/models/rule.rb | 3 ++- app/services/manager.rb | 13 +++++++++++-- spec/models/rule_spec.rb | 13 +++++++++++++ spec/services/manager_spec.rb | 11 +++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/models/rule.rb b/app/models/rule.rb index 8668888..ca1bbfb 100644 --- a/app/models/rule.rb +++ b/app/models/rule.rb @@ -14,7 +14,7 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel validates :filter, :inclusion => { :in => %w(watch follow mute), :message => "%{value} is not a valid filter" } - validates :type, :inclusion => { :in => %w(normal group_message), + validates :type, :inclusion => { :in => %w(normal group_message group_mention), :message => "%{value} is not a valid filter" } validate :channel_valid?, :category_valid?, :group_valid?, :tags_valid? @@ -80,6 +80,7 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel super(val.to_i) end end + end # Mock foreign key diff --git a/app/services/manager.rb b/app/services/manager.rb index 11bd537..8c6ac82 100644 --- a/app/services/manager.rb +++ b/app/services/manager.rb @@ -27,9 +27,18 @@ module DiscourseChat return if group_ids_with_access.empty? matching_rules = DiscourseChat::Rule.with_type('group_message').with_group_ids(group_ids_with_access) else - matching_rules = DiscourseChat::Rule.with_category_id(topic.category_id) + matching_rules = DiscourseChat::Rule.with_type('normal').with_category_id(topic.category_id) if topic.category # Also load the rules for the wildcard category - matching_rules += DiscourseChat::Rule.with_category_id(nil) + matching_rules += DiscourseChat::Rule.with_type('normal').with_category_id(nil) + end + end + + # If groups are mentioned, check for any matching rules and append them + mentions = post.raw_mentions + if mentions && mentions.length > 0 + groups = Group.where('LOWER(name) IN (?)', mentions) + if groups.exists? + matching_rules += DiscourseChat::Rule.with_type('group_mention').with_group_ids(groups.map(&:id)) end end diff --git a/spec/models/rule_spec.rb b/spec/models/rule_spec.rb index b698383..83efb13 100644 --- a/spec/models/rule_spec.rb +++ b/spec/models/rule_spec.rb @@ -127,6 +127,19 @@ RSpec.describe DiscourseChat::Rule do expect(DiscourseChat::Rule.with_group_ids([group2.id]).length).to eq(1) end + it 'can be filtered by type' do + group1 = Fabricate(:group) + + rule2 = DiscourseChat::Rule.create!(channel: channel, type: 'group_message', group_id: group1.id) + rule3 = DiscourseChat::Rule.create!(channel: channel, type: 'group_mention', group_id: group1.id) + + expect(DiscourseChat::Rule.all.length).to eq(3) + + expect(DiscourseChat::Rule.with_type('group_message').length).to eq(1) + expect(DiscourseChat::Rule.with_type('group_mention').length).to eq(1) + expect(DiscourseChat::Rule.with_type('normal').length).to eq(1) + end + it 'can be sorted by precedence' do rule2 = DiscourseChat::Rule.create(channel:channel, filter:'mute') rule3 = DiscourseChat::Rule.create(channel:channel, filter:'follow') diff --git a/spec/services/manager_spec.rb b/spec/services/manager_spec.rb index c06ea46..c7ba534 100644 --- a/spec/services/manager_spec.rb +++ b/spec/services/manager_spec.rb @@ -134,6 +134,17 @@ RSpec.describe DiscourseChat::Manager do expect(provider.sent_to_channel_ids).to contain_exactly(chan1.id, chan2.id) end + it "should work for group mentions" do + third_post = Fabricate(:post, topic: topic, post_number: 3, raw: "let's mention @#{group.name}") + + DiscourseChat::Rule.create!(channel: chan1, filter: 'watch') # Wildcard watch + DiscourseChat::Rule.create!(channel: chan2, type: 'group_message', filter: 'watch', group_id: group.id) + DiscourseChat::Rule.create!(channel: chan3, type: 'group_mention', filter: 'watch', group_id: group.id) + + manager.trigger_notifications(third_post.id) + expect(provider.sent_to_channel_ids).to contain_exactly(chan1.id, chan3.id) + end + it "should not notify about posts the chat_user cannot see" do DiscourseChat::Rule.create!(channel: chan1, filter: 'follow', category_id: nil ) # Wildcard watch From 6aa94fcb27ee1fd65dc46eb88219bc8b6b37341a Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 1 Aug 2017 17:12:21 +0100 Subject: [PATCH 5/8] =?UTF-8?q?Add=20once=20off=20job=20to=20=E2=80=9Cmigr?= =?UTF-8?q?ate=E2=80=9D=20the=20Rule=20model?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can’t use an actual activerecord migration because everything is JSON serialised :( --- app/initializers/discourse_chat.rb | 4 +++- app/jobs/onceoff/add_type_field.rb | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 app/jobs/onceoff/add_type_field.rb diff --git a/app/initializers/discourse_chat.rb b/app/initializers/discourse_chat.rb index 0ab00a7..e6754c6 100644 --- a/app/initializers/discourse_chat.rb +++ b/app/initializers/discourse_chat.rb @@ -47,4 +47,6 @@ require_relative "../services/manager" require_relative "../jobs/regular/notify_chats" -require_relative "../../lib/discourse_chat/provider" \ No newline at end of file +require_relative "../../lib/discourse_chat/provider" + +require_relative "../jobs/onceoff/add_type_field" diff --git a/app/jobs/onceoff/add_type_field.rb b/app/jobs/onceoff/add_type_field.rb new file mode 100644 index 0000000..20de608 --- /dev/null +++ b/app/jobs/onceoff/add_type_field.rb @@ -0,0 +1,9 @@ +module Jobs + class DiscourseChatAddTypeField < Jobs::Onceoff + def execute_onceoff(args) + DiscourseChat::Rule.find_each do |rule| + rule.save(validate: false) + end + end + end +end From c06a4aa4f6a7d36d30e4b3c6e3b1ec0572f6e2f5 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 1 Aug 2017 17:28:12 +0100 Subject: [PATCH 6/8] Fix qunit --- test/javascripts/acceptance/chat-integration-test.js.es6 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/javascripts/acceptance/chat-integration-test.js.es6 b/test/javascripts/acceptance/chat-integration-test.js.es6 index 580fc8d..f286203 100644 --- a/test/javascripts/acceptance/chat-integration-test.js.es6 +++ b/test/javascripts/acceptance/chat-integration-test.js.es6 @@ -37,6 +37,9 @@ acceptance("Chat Integration", { server.post('/admin/plugins/chat/test', () => { return response({ }); }); + server.get('/groups/search.json', () => { + return response([]); + }); } From 01d7fb47ef3963d95fa1af0e970c119688a0942e Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 1 Aug 2017 19:16:47 +0100 Subject: [PATCH 7/8] Display group rules correctly in slash commands --- app/helpers/helper.rb | 25 ++++++++++++++++++------- config/locales/server.en.yml | 3 +++ spec/helpers/helper_spec.rb | 4 +++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/app/helpers/helper.rb b/app/helpers/helper.rb index 7deca25..c50aac6 100644 --- a/app/helpers/helper.rb +++ b/app/helpers/helper.rb @@ -82,14 +82,25 @@ module DiscourseChat i = 1 rules.each do |rule| category_id = rule.category_id - if category_id.nil? - category_name = I18n.t("chat_integration.all_categories") - else - category = Category.find_by(id: category_id) - if category - category_name = category.slug + + case rule.type + when "normal" + if category_id.nil? + category_name = I18n.t("chat_integration.all_categories") else - category_name = I18n.t("chat_integration.deleted_category") + category = Category.find_by(id: category_id) + if category + category_name = category.slug + else + category_name = I18n.t("chat_integration.deleted_category") + end + end + when "group_mention", "group_message" + group = Group.find_by(id: rule.group_id) + if group + category_name = I18n.t("chat_integration.#{rule.type}_template", name: group.name) + else + category_name = I18n.t("chat_integration.deleted_group") end end diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 7b889d1..c04bad2 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -62,6 +62,9 @@ en: deleted_category: "(deleted category)" deleted_group: "(deleted group)" + group_mention_template: "mentions of: @%{name}" + group_message_template: "messages to: @%{name}" + provider: ####################################### diff --git a/spec/helpers/helper_spec.rb b/spec/helpers/helper_spec.rb index 61214de..d627968 100644 --- a/spec/helpers/helper_spec.rb +++ b/spec/helpers/helper_spec.rb @@ -152,16 +152,18 @@ RSpec.describe DiscourseChat::Manager do end context 'with some rules' do + let(:group){Fabricate(:group)} before do DiscourseChat::Rule.create!(channel: chan1, filter:'watch', category_id:category.id, tags:nil) DiscourseChat::Rule.create!(channel: chan1, filter:'mute', category_id:nil, tags:nil) DiscourseChat::Rule.create!(channel: chan1, filter:'follow', category_id:nil, tags:[tag1.name]) + DiscourseChat::Rule.create!(channel: chan1, filter:'watch', type: 'group_message', group_id:group.id) DiscourseChat::Rule.create!(channel: chan2, filter:'watch', category_id:1, tags:nil) end it 'displays the correct rules' do string = DiscourseChat::Helper.status_for_channel(chan1) - expect(string.scan('status.rule_string').size).to eq(3) + expect(string.scan('status.rule_string').size).to eq(4) end it 'only displays tags for rules with tags' do From 7c3f58de411a5d25cfca84eab1c69c326e8f6049 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 1 Aug 2017 20:12:42 +0100 Subject: [PATCH 8/8] Update display of group rules in admin UI --- .../javascripts/admin/components/rule-row.js.es6 | 12 ++++++++++++ .../discourse/templates/components/rule-row.hbs | 16 ++++++++++------ config/locales/client.en.yml | 11 +++++++---- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/assets/javascripts/admin/components/rule-row.js.es6 b/assets/javascripts/admin/components/rule-row.js.es6 index 9782507..f246e98 100644 --- a/assets/javascripts/admin/components/rule-row.js.es6 +++ b/assets/javascripts/admin/components/rule-row.js.es6 @@ -3,6 +3,18 @@ import { popupAjaxError } from 'discourse/lib/ajax-error'; export default Ember.Component.extend({ tagName: 'tr', + isCategory: function(){ + return this.get('rule.type') == 'normal' + }.property('rule.type'), + + isMessage: function(){ + return this.get('rule.type') == 'group_message' + }.property('rule.type'), + + isMention: function(){ + return this.get('rule.type') == 'group_mention' + }.property('rule.type'), + actions: { edit: function(){ this.sendAction('edit', this.get('rule')) diff --git a/assets/javascripts/discourse/templates/components/rule-row.hbs b/assets/javascripts/discourse/templates/components/rule-row.hbs index 59efe10..12202e5 100644 --- a/assets/javascripts/discourse/templates/components/rule-row.hbs +++ b/assets/javascripts/discourse/templates/components/rule-row.hbs @@ -4,12 +4,16 @@ - {{#if rule.category}} - {{category-link rule.category allowUncategorized="true" link="false"}} - {{else if rule.group_id}} - {{i18n "chat_integration.group_prefix"}} {{rule.group_name}} - {{else}} - {{i18n "chat_integration.all_categories"}} + {{#if isCategory}} + {{#if rule.category}} + {{category-link rule.category allowUncategorized="true" link="false"}} + {{else}} + {{i18n "chat_integration.all_categories"}} + {{/if}} + {{else if isMention}} + {{i18n "chat_integration.group_mention_template" name=rule.group_name}} + {{else if isMessage}} + {{i18n "chat_integration.group_message_template" name=rule.group_name}} {{/if}} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 43d469f..830fe30 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -6,7 +6,9 @@ en: no_providers: "You need to enable some providers in the plugin settings" channels_with_errors: "Some channels for this provider failed last time messages were sent. Click the error icon(s) to learn more." channel_exception: "An unknown error occured when a message was last sent to this channel. Check the site logs for more information." - group_prefix: "Group:" + group_mention_template: "Mentions of: @{{name}}" + group_message_template: "Messages to: @{{name}}" + choose_group: "(choose a group)" all_categories: "(all categories)" all_tags: "(all tags)" create_rule: "Create Rule" @@ -56,10 +58,11 @@ en: group: Group tags: Tags instructions: - filter: "Notification level. Mute overrides other matching rules." - category: "This rule will only apply to topics in the specified category." + type: "Change the type to trigger notifications for group messages or mentions" + filter: "Notification level. Mute overrides other matching rules" + category: "This rule will only apply to topics in the specified category" group: "This rule will apply to posts referencing this group" - tags: "If specified, this rule will only apply to topics which have at least one of these tags." + tags: "If specified, this rule will only apply to topics which have at least one of these tags" provider: