diff --git a/app/controllers/chat_controller.rb b/app/controllers/chat_controller.rb index 21e3cd1..63e9b9e 100644 --- a/app/controllers/chat_controller.rb +++ b/app/controllers/chat_controller.rb @@ -9,29 +9,25 @@ class DiscourseChat::ChatController < ApplicationController providers = ::DiscourseChat::Provider.enabled_providers.map {|x| { name: x::PROVIDER_NAME, id: x::PROVIDER_NAME, - channel_regex: (defined? x::PROVIDER_CHANNEL_REGEX) ? x::PROVIDER_CHANNEL_REGEX : nil + channel_parameters: (defined? x::CHANNEL_PARAMETERS) ? x::CHANNEL_PARAMETERS : [] }} render json:providers, root: 'providers' end - def test_provider + def test begin - requested_provider = params[:provider] - channel = params[:channel] - topic_id = params[:topic_id] + channel_id = params[:channel_id].to_i + topic_id = params[:topic_id].to_i - provider = ::DiscourseChat::Provider.get_by_name(requested_provider) + channel = DiscourseChat::Channel.find(channel_id) - if provider.nil? or not ::DiscourseChat::Provider.is_enabled(provider) + provider = ::DiscourseChat::Provider.get_by_name(channel.provider) + + if not ::DiscourseChat::Provider.is_enabled(provider) raise Discourse::NotFound end - if defined? provider::PROVIDER_CHANNEL_REGEX - channel_regex = Regexp.new provider::PROVIDER_CHANNEL_REGEX - raise Discourse::InvalidParameters, 'Channel is not valid' if not channel_regex.match?(channel) - end - post = Topic.find(topic_id.to_i).posts.first provider.trigger_notification(post, channel) @@ -48,23 +44,80 @@ class DiscourseChat::ChatController < ApplicationController end end - def list_rules + def list_channels providers = ::DiscourseChat::Provider.enabled_providers.map {|x| x::PROVIDER_NAME} requested_provider = params[:provider] - if providers.include? requested_provider - rules = DiscourseChat::Rule.with_provider(requested_provider) - else + if not providers.include? requested_provider raise Discourse::NotFound end - render_serialized rules, DiscourseChat::RuleSerializer, root: 'rules' + channels = DiscourseChat::Channel.with_provider(requested_provider) + + render_serialized channels, DiscourseChat::ChannelSerializer, root: 'channels' + end + + def create_channel + begin + providers = ::DiscourseChat::Provider.enabled_providers.map {|x| x::PROVIDER_NAME} + + if not defined? params[:channel] and defined? params[:channel][:provider] + raise Discourse::InvalidParameters, 'Provider is not valid' + end + + requested_provider = params[:channel][:provider] + + if not providers.include? requested_provider + raise Discourse::InvalidParameters, 'Provider is not valid' + end + + allowed_keys = DiscourseChat::Provider.get_by_name(requested_provider)::CHANNEL_PARAMETERS.map{|p| p[:key].to_sym} + + hash = params.require(:channel).permit(:provider, data:allowed_keys) + + channel = DiscourseChat::Channel.new(hash) + + if not channel.save(hash) + raise Discourse::InvalidParameters, 'Channel is not valid' + end + + render_serialized channel, DiscourseChat::ChannelSerializer, root: 'channel' + rescue Discourse::InvalidParameters => e + render json: {errors: [e.message]}, status: 422 + end + end + + def update_channel + begin + channel = DiscourseChat::Channel.find(params[:id].to_i) + channel.error_key = nil # Reset any error on the rule + + allowed_keys = DiscourseChat::Provider.get_by_name(channel.provider)::CHANNEL_PARAMETERS.map{|p| p[:key].to_sym} + + hash = params.require(:channel).permit(data:allowed_keys) + + if not channel.update(hash) + raise Discourse::InvalidParameters, 'Channel is not valid' + end + + render_serialized channel, DiscourseChat::ChannelSerializer, root: 'channel' + rescue Discourse::InvalidParameters => e + render json: {errors: [e.message]}, status: 422 + end + end + + def destroy_channel + rule = DiscourseChat::Channel.find(params[:id].to_i) + + rule.destroy + + render json: success_json end def create_rule begin - hash = params.require(:rule).permit(:provider, :channel, :filter, :category_id, tags:[]) + hash = params.require(:rule).permit(:channel_id, :filter, :category_id, tags:[]) rule = DiscourseChat::Rule.new(hash) @@ -81,8 +134,7 @@ class DiscourseChat::ChatController < ApplicationController def update_rule begin rule = DiscourseChat::Rule.find(params[:id].to_i) - rule.error_key = nil # Reset any error on the rule - hash = params.require(:rule).permit(:provider, :channel, :filter, :category_id, tags:[]) + hash = params.require(:rule).permit(:filter, :category_id, tags:[]) if not rule.update(hash) raise Discourse::InvalidParameters, 'Rule is not valid' diff --git a/app/helpers/helper.rb b/app/helpers/helper.rb index ba96b35..50c0479 100644 --- a/app/helpers/helper.rb +++ b/app/helpers/helper.rb @@ -2,8 +2,9 @@ module DiscourseChat module Helper # Produce a string with a list of all rules associated with a channel - def self.status_for_channel(provider, channel) - rules = DiscourseChat::Rule.with_channel(provider, channel) + def self.status_for_channel(channel) + rules = channel.rules.order_by_precedence + provider = channel.provider text = I18n.t("chat_integration.provider.#{provider}.status.header") + "\n" @@ -43,8 +44,8 @@ module DiscourseChat # Delete a rule based on its (1 based) index as seen in the # status_for_channel function - def self.delete_by_index(provider, channel, index) - rules = DiscourseChat::Rule.with_channel(provider, channel) + def self.delete_by_index(channel, index) + rules = channel.rules.order_by_precedence return false if index < 1 or index > rules.size @@ -58,8 +59,8 @@ module DiscourseChat # :updated if an existing rule has been updated # :created if a new rule has been created # false if there was an error - def self.smart_create_rule(provider:, channel:, filter:, category_id:, tags:) - existing_rules = DiscourseChat::Rule.with_channel(provider, channel) + def self.smart_create_rule(channel:, filter:, category_id:nil, tags:nil) + existing_rules = DiscourseChat::Rule.with_channel(channel) # Select the ones that have the same category same_category = existing_rules.select { |rule| rule.category_id == category_id } @@ -100,7 +101,7 @@ module DiscourseChat end # This rule is unique! Create a new one: - return :created if Rule.new({provider: provider, channel: channel, filter: filter, category_id: category_id, tags: tags}).save + return :created if Rule.new(channel: channel, filter: filter, category_id: category_id, tags: tags).save return false # Error diff --git a/app/models/channel.rb b/app/models/channel.rb index 5077a77..2337ade 100644 --- a/app/models/channel.rb +++ b/app/models/channel.rb @@ -2,6 +2,54 @@ class DiscourseChat::Channel < DiscourseChat::PluginModel KEY_PREFIX = 'channel:' # Setup ActiveRecord::Store to use the JSON field to read/write these values - store :value, accessors: [ :name ], coder: JSON + store :value, accessors: [ :provider, :error_key, :data ], coder: JSON + + after_initialize :init_data + + def init_data + self.data = {} if self.data.nil? + end + + after_destroy :destroy_rules + def destroy_rules + rules.destroy_all() + end + + validate :provider_valid?, :data_valid? + + def provider_valid? + # Validate provider + if not ::DiscourseChat::Provider.provider_names.include? provider + errors.add(:provider, "#{provider} is not a valid provider") + return + end + end + + def data_valid? + # If provider is invalid, don't try and check data + return unless ::DiscourseChat::Provider.provider_names.include? provider + + params = ::DiscourseChat::Provider.get_by_name(provider)::CHANNEL_PARAMETERS + + unless params.map {|p| p[:key]}.sort == data.keys.sort + errors.add(:data, "data does not match the required structure for provider #{provider}") + return + end + + data.each do |key, value| + regex_string = params.find{|p| p[:key] == key}[:regex] + if !Regexp.new(regex_string).match?(value) + errors.add(:data, "data.#{key} is invalid") + end + end + end + + def rules + DiscourseChat::Rule.with_channel_id(id) + end + + scope :with_provider, ->(provider) { where("value::json->>'provider'=?", provider)} + + scope :with_data_value, ->(key, value) { where("(value::json->>'data')::json->>?=?", key, value)} end \ No newline at end of file diff --git a/app/models/rule.rb b/app/models/rule.rb index b2f3707..6ccd4f4 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: [ :provider, :channel, :category_id, :tags, :filter, :error_key ], coder: JSON + store :value, accessors: [ :channel_id, :category_id, :tags, :filter ], coder: JSON after_initialize :init_filter @@ -13,27 +13,12 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel validates :filter, :inclusion => { :in => %w(watch follow mute), :message => "%{value} is not a valid filter" } - validate :provider_and_channel_valid?, :category_valid?, :tags_valid? + validate :channel_valid?, :category_valid?, :tags_valid? - def provider_and_channel_valid? - # Validate provider - if not ::DiscourseChat::Provider.provider_names.include? provider - errors.add(:provider, "#{provider} is not a valid provider") - return - end - - # Validate channel - if channel.blank? - errors.add(:channel, "channel cannot be blank") - return - end - - provider_class = ::DiscourseChat::Provider.get_by_name(provider) - if defined? provider_class::PROVIDER_CHANNEL_REGEX - channel_regex = Regexp.new provider_class::PROVIDER_CHANNEL_REGEX - if not channel_regex.match?(channel) - errors.add(:channel, "#{channel} is not a valid channel for provider #{provider}") - end + def channel_valid? + # Validate category + if not (DiscourseChat::Channel.where(id: channel_id).exists?) + errors.add(:channel_id, "#{channel_id} is not a valid channel id") end end @@ -72,12 +57,33 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel end end - scope :with_provider, ->(provider) { where("value::json->>'provider'=?", provider)} + # 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) + end + end - scope :with_channel, ->(provider, channel) { with_provider(provider).where("value::json->>'channel'=?", channel)} + # Mock foreign key + # Could return nil + def channel + DiscourseChat::Channel.find_by(id:channel_id) + end + def channel=(val) + self.channel_id = val.id + end - scope :with_category, ->(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_channel, ->(channel) { with_channel_id(channel.id) } + 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 :order_by_precedence, ->{ order("CASE + WHEN value::json->>'filter' = 'mute' THEN 1 + WHEN value::json->>'filter' = 'watch' THEN 2 + WHEN value::json->>'filter' = 'follow' THEN 3 + END") } end \ No newline at end of file diff --git a/app/routes/discourse_chat.rb b/app/routes/discourse_chat.rb index 207b4e1..1b65c53 100644 --- a/app/routes/discourse_chat.rb +++ b/app/routes/discourse_chat.rb @@ -4,10 +4,14 @@ module DiscourseChat AdminEngine.routes.draw do get "" => "chat#respond" get '/providers' => "chat#list_providers" - post '/test' => "chat#test_provider" + post '/test' => "chat#test" - get '/rules' => "chat#list_rules" - put '/rules' => "chat#create_rule" + get '/channels' => "chat#list_channels" + post '/channels' => "chat#create_channel" + put '/channels/:id' => "chat#update_channel" + delete '/channels/:id' => "chat#destroy_channel" + + post '/rules' => "chat#create_rule" put '/rules/:id' => "chat#update_rule" delete '/rules/:id' => "chat#destroy_rule" diff --git a/app/serializers/channel_serializer.rb b/app/serializers/channel_serializer.rb new file mode 100644 index 0000000..e24831f --- /dev/null +++ b/app/serializers/channel_serializer.rb @@ -0,0 +1,11 @@ +require_relative './rule_serializer' + +class DiscourseChat::ChannelSerializer < ApplicationSerializer + attributes :id, :provider, :error_key, :data, :rules + + def rules + object.rules.order_by_precedence.map do |rule| + DiscourseChat::RuleSerializer.new(rule, root:false) + end + end +end \ No newline at end of file diff --git a/app/serializers/rule_serializer.rb b/app/serializers/rule_serializer.rb index 7ff023b..57a0581 100644 --- a/app/serializers/rule_serializer.rb +++ b/app/serializers/rule_serializer.rb @@ -1,3 +1,3 @@ -class DiscourseChat::RuleSerializer < ActiveModel::Serializer - attributes :id, :provider, :channel, :category_id, :tags, :filter, :error_key +class DiscourseChat::RuleSerializer < ApplicationSerializer + attributes :id, :channel_id, :category_id, :tags, :filter end \ No newline at end of file diff --git a/app/services/manager.rb b/app/services/manager.rb index 5368acc..78bee22 100644 --- a/app/services/manager.rb +++ b/app/services/manager.rb @@ -22,10 +22,10 @@ module DiscourseChat return if topic.blank? || topic.archetype == Archetype.private_message # Load all the rules that apply to this topic's category - matching_rules = DiscourseChat::Rule.with_category(topic.category_id) + 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(nil) + matching_rules += DiscourseChat::Rule.with_category_id(nil) end # If tagging is enabled, thow away rules that don't apply to this topic @@ -44,7 +44,7 @@ module DiscourseChat matching_rules = matching_rules.sort(&sort_func) # Take the first rule for each channel - uniq_func = proc { |rule| [rule.provider, rule.channel] } + uniq_func = proc { |rule| [rule.channel_id] } matching_rules = matching_rules.uniq(&uniq_func) # If a matching rule is set to mute, we can discard it now @@ -61,34 +61,31 @@ module DiscourseChat # Loop through each rule, and trigger appropriate notifications matching_rules.each do |rule| - provider = ::DiscourseChat::Provider.get_by_name(rule.provider) - is_enabled = ::DiscourseChat::Provider.is_enabled(provider) + # If there are any issues, skip to the next rule + next unless channel = rule.channel + next unless provider = ::DiscourseChat::Provider.get_by_name(channel.provider) + next unless is_enabled = ::DiscourseChat::Provider.is_enabled(provider) - if provider and is_enabled - begin - provider.trigger_notification(post, rule.channel) - rule.update_attribute('error_key', nil) if rule.error_key - rescue => e - if e.class == DiscourseChat::ProviderError and e.info.key?(:error_key) and !e.info[:error_key].nil? - rule.update_attribute('error_key', e.info[:error_key]) - else - rule.update_attribute('error_key','chat_integration.rule_exception') - end - - # Log the error - Discourse.handle_job_exception(e, - message: "Triggering notifications failed", - extra: { provider_name: provider::PROVIDER_NAME, - channel: rule.channel, - post_id: post.id, - error_info: e.class == DiscourseChat::ProviderError ? e.info : nil } - ) + begin + provider.trigger_notification(post, channel) + channel.update_attribute('error_key', nil) if channel.error_key + rescue => e + if e.class == DiscourseChat::ProviderError and e.info.key?(:error_key) and !e.info[:error_key].nil? + channel.update_attribute('error_key', e.info[:error_key]) + else + channel.update_attribute('error_key','chat_integration.channel_exception') end - elsif provider - # Provider is disabled, don't do anything - else - # TODO: Handle when the provider does not exist + + # Log the error + Discourse.handle_job_exception(e, + message: "Triggering notifications failed", + extra: { provider_name: provider::PROVIDER_NAME, + channel: rule.channel, + post_id: post.id, + error_info: e.class == DiscourseChat::ProviderError ? e.info : nil } + ) end + end end diff --git a/assets/javascripts/admin/adapters/channel.js.es6 b/assets/javascripts/admin/adapters/channel.js.es6 new file mode 100644 index 0000000..8287b75 --- /dev/null +++ b/assets/javascripts/admin/adapters/channel.js.es6 @@ -0,0 +1,7 @@ +import buildPluginAdapter from 'admin/adapters/build-plugin'; +import Rule from 'discourse/plugins/discourse-chat-integration/admin/models/rule' + +export default buildPluginAdapter('chat').extend({ + + +}); \ 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 new file mode 100644 index 0000000..08fcd1b --- /dev/null +++ b/assets/javascripts/admin/components/channel-details.js.es6 @@ -0,0 +1,38 @@ +import { popupAjaxError } from 'discourse/lib/ajax-error'; + +export default Ember.Component.extend({ + classNames: ['channel-details'], + actions: { + refresh: function(){ + this.sendAction('refresh'); + }, + + delete(channel){ + bootbox.confirm(I18n.t("chat_integration.channel_delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => { + if (result) { + channel.destroyRecord().then(() => { + this.send('refresh'); + }).catch(popupAjaxError) + } + }); + }, + + edit(channel){ + this.sendAction('edit', channel) + }, + + test(channel){ + this.sendAction('test', channel) + }, + + createRule(channel){ + var newRule = this.get('store').createRecord('rule',{channel_id: channel.id}); + channel.rules.pushObject(newRule) + }, + + showError(error_key){ + bootbox.alert(I18n.t(error_key)); + }, + + } +}); \ No newline at end of file diff --git a/assets/javascripts/admin/components/rule-row.js.es6 b/assets/javascripts/admin/components/rule-row.js.es6 new file mode 100644 index 0000000..7622fa1 --- /dev/null +++ b/assets/javascripts/admin/components/rule-row.js.es6 @@ -0,0 +1,38 @@ +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); + }, + + 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 5fd9341..f52965c 100644 --- a/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 +++ b/assets/javascripts/admin/controllers/admin-plugins-chat-provider.js.es6 @@ -7,42 +7,33 @@ import { popupAjaxError } from 'discourse/lib/ajax-error'; export default Ember.Controller.extend({ modalShowing: false, - + anyErrors: function(){ var anyErrors = false; - this.get('model.rules').forEach(function(rule){ - if(rule.error_key){ + this.get('model.channels').forEach(function(channel){ + if(channel.error_key){ anyErrors = true; } }); return anyErrors; - }.property('model.rules'), + }.property('model.channels'), actions:{ - create(){ + createChannel(){ this.set('modalShowing', true); - var model = {rule: this.store.createRecord('rule',{provider: this.get('model.provider').id}), provider:this.get('model.provider')}; - showModal('admin-plugins-chat-edit-rule', { model: model, admin: true }); + var model = {channel: this.store.createRecord('channel',{provider: this.get('model.provider').id, data:{}},), provider:this.get('model.provider')}; + showModal('admin-plugins-chat-edit-channel', { model: model, admin: true }); }, - edit(rule){ + editChannel(channel){ this.set('modalShowing', true); - var model = {rule: rule, provider:this.get('model.provider')}; - showModal('admin-plugins-chat-edit-rule', { model: model, admin: true }); + var model = {channel: channel, provider: this.get('model.provider')}; + showModal('admin-plugins-chat-edit-channel', { model: model, admin: true }); }, - delete(rule){ - const self = this; - rule.destroyRecord().then(function() { - self.send('refresh'); - }).catch(popupAjaxError) - }, - showError(error_key){ - bootbox.alert(I18n.t(error_key)); - }, - test(){ + testChannel(channel){ this.set('modalShowing', true); - var model = {provider:this.get('model.provider'), channel:''} + var model = {channel:channel} showModal('admin-plugins-chat-test', { model: model, admin: true }); - } + }, } diff --git a/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-channel.js.es6 b/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-channel.js.es6 new file mode 100644 index 0000000..ca11b66 --- /dev/null +++ b/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-channel.js.es6 @@ -0,0 +1,93 @@ +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, { + + // The validation property must be defined at runtime since the possible parameters vary by provider + setupValidations: function(){ + if(this.get('model.provider')){ + var theKeys = this.get('model.provider.channel_parameters').map( ( param ) => param['key'] ); + Ember.defineProperty(this,'paramValidation',Ember.computed('model.channel.data.{' + theKeys.join(',') + '}',this._paramValidation)); + } + }.observes('model'), + + validate(parameter){ + var regString = parameter.regex; + var regex = new RegExp(regString); + var val = this.get('model.channel.data.'+parameter.key); + + if(val==undefined){ + val = ""; + } + + if(val == ""){ // Fail silently if field blank + return InputValidation.create({ + failed: true, + }); + }else if(!regString){ // Pass silently if no regex available for provider + return InputValidation.create({ + ok: true, + }); + }else if(regex.test(val)){ // Test against regex + return InputValidation.create({ + ok: true, + reason: I18n.t('chat_integration.edit_channel_modal.channel_validation.ok') + }); + }else{ // Failed regex + return InputValidation.create({ + failed: true, + reason: I18n.t('chat_integration.edit_channel_modal.channel_validation.fail') + }); + } + + }, + + _paramValidation: function(){ + var response = {} + var parameters = this.get('model.provider.channel_parameters'); + parameters.forEach(parameter => { + response[parameter.key] = this.validate(parameter); + }); + return response; + }, + + saveDisabled: function(){ + var validations = this.get('paramValidation'); + + if(!validations){ return true } + + var invalid = false; + + Object.keys(validations).forEach(key =>{ + if(!validations[key]){ + invalid = true; + } + if(!validations[key]['ok']){ + invalid = true; + } + }); + + return invalid; + }.property('paramValidation'), + + actions: { + cancel: function(){ + this.send('closeModal'); + }, + + save: function(){ + + const self = this; + + this.get('model.channel').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/controllers/modals/admin-plugins-chat-edit-rule.js.es6 b/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 deleted file mode 100644 index 2093a03..0000000 --- a/assets/javascripts/admin/controllers/modals/admin-plugins-chat-edit-rule.js.es6 +++ /dev/null @@ -1,61 +0,0 @@ -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, { - - model: Rule.create({}), - - channelValidation: function(){ - - var regString = this.get('model.provider.channel_regex'); - var regex = new RegExp(regString); - var val = this.get('model.rule.channel'); - - if(val == ""){ // Fail silently if field blank - return InputValidation.create({ - failed: true, - }); - }else if(!regString){ // Pass silently if no regex available for provider - return InputValidation.create({ - ok: true, - }); - }else if(regex.test(val)){ // Test against regex - return InputValidation.create({ - ok: true, - reason: I18n.t('chat_integration.edit_rule_modal.channel_validation.ok') - }); - }else{ // Failed regex - return InputValidation.create({ - failed: true, - reason: I18n.t('chat_integration.edit_rule_modal.channel_validation.fail') - }); - } - }.property('model.rule.channel'), - - saveDisabled: function(){ - if(this.get('channelValidation.failed')){ return true } - - return false; - }.property('channelValidation.failed'), - - actions: { - cancel: function(){ - this.send('closeModal'); - }, - - save: function(){ - - const self = this; - - this.get('model.rule').update().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/controllers/modals/admin-plugins-chat-test.js.es6 b/assets/javascripts/admin/controllers/modals/admin-plugins-chat-test.js.es6 index 1eacb71..b6a5ba5 100644 --- a/assets/javascripts/admin/controllers/modals/admin-plugins-chat-test.js.es6 +++ b/assets/javascripts/admin/controllers/modals/admin-plugins-chat-test.js.es6 @@ -3,11 +3,11 @@ import { ajax } from 'discourse/lib/ajax'; export default Ember.Controller.extend(ModalFunctionality, { sendDisabled: function(){ - if(this.get('model').topic_id && this.get('model').channel){ + if(this.get('model').topic_id){ return false } return true - }.property('model.topic_id', 'model.channel'), + }.property('model.topic_id'), actions: { @@ -15,8 +15,7 @@ export default Ember.Controller.extend(ModalFunctionality, { self = this; this.set('loading', true); ajax("/admin/plugins/chat/test", { - data: { provider: this.get('model.provider.name'), - channel: this.get('model.channel'), + data: { channel_id: this.get('model.channel.id'), topic_id: this.get('model.topic_id') }, type: 'POST' diff --git a/assets/javascripts/admin/models/channel.js.es6 b/assets/javascripts/admin/models/channel.js.es6 new file mode 100644 index 0000000..b21399c --- /dev/null +++ b/assets/javascripts/admin/models/channel.js.es6 @@ -0,0 +1,14 @@ +import RestModel from 'discourse/models/rest'; + +export default RestModel.extend({ + + updateProperties() { + var prop_names = ['data']; + return this.getProperties(prop_names); + }, + + createProperties() { + var prop_names = ['provider','data']; + return this.getProperties(prop_names); + } +}); diff --git a/assets/javascripts/admin/models/rule.js.es6 b/assets/javascripts/admin/models/rule.js.es6 index 2ee1523..44fe2c8 100644 --- a/assets/javascripts/admin/models/rule.js.es6 +++ b/assets/javascripts/admin/models/rule.js.es6 @@ -11,9 +11,8 @@ export default RestModel.extend({ category_id: null, tags: null, - provider: '', - channel: '', - filter: null, + channel_id: null, + filter: 'watch', error_key: null, @computed('category_id') @@ -31,12 +30,13 @@ export default RestModel.extend({ }, updateProperties() { - var prop_names = ['category_id','provider','channel', 'tags','filter']; + var prop_names = ['category_id','tags','filter']; return this.getProperties(prop_names); }, createProperties() { - return this.updateProperties(); + var prop_names = ['channel_id', 'category_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 07b7b0a..7889816 100644 --- a/assets/javascripts/admin/routes/admin-plugins-chat-provider.js.es6 +++ b/assets/javascripts/admin/routes/admin-plugins-chat-provider.js.es6 @@ -1,12 +1,20 @@ -import Rule from 'discourse/plugins/discourse-chat-integration/admin/models/rule' import { ajax } from 'discourse/lib/ajax'; export default Discourse.Route.extend({ model(params, transition) { return Ember.RSVP.hash({ - rules: this.store.find('rule', {provider: params.provider}), + channels: this.store.findAll('channel', {provider: params.provider}), provider: this.modelFor("admin-plugins-chat").findBy('id',params.provider) + }).then(value => { + value.channels.forEach(channel => { + channel.set('rules', channel.rules.map(rule => { + rule = this.store.createRecord('rule', rule); + rule.channel = channel; + return rule; + })); + }); + return value; }); }, diff --git a/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-channel.hbs b/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-channel.hbs new file mode 100644 index 0000000..579d071 --- /dev/null +++ b/assets/javascripts/admin/templates/modal/admin-plugins-chat-edit-channel.hbs @@ -0,0 +1,49 @@ +{{#d-modal-body id="chat_integration_edit_channel_modal" title="chat_integration.edit_channel_modal.title"}} +