Store errors per-channel rather than per-rule, and update UI to match

This commit is contained in:
David Taylor 2017-07-18 23:08:06 +01:00
parent d1d333523f
commit c5fdebd1bc
11 changed files with 42 additions and 45 deletions

View File

@ -91,7 +91,7 @@ class DiscourseChat::ChatController < ApplicationController
def update_channel def update_channel
begin begin
channel = DiscourseChat::Channel.find(params[:id].to_i) channel = DiscourseChat::Channel.find(params[:id].to_i)
# rule.error_key = nil # Reset any error on the rule 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} allowed_keys = DiscourseChat::Provider.get_by_name(channel.provider)::CHANNEL_PARAMETERS.map{|p| p[:key].to_sym}
@ -134,7 +134,6 @@ class DiscourseChat::ChatController < ApplicationController
def update_rule def update_rule
begin begin
rule = DiscourseChat::Rule.find(params[:id].to_i) rule = DiscourseChat::Rule.find(params[:id].to_i)
rule.error_key = nil # Reset any error on the rule
hash = params.require(:rule).permit(:filter, :category_id, tags:[]) hash = params.require(:rule).permit(:filter, :category_id, tags:[])
if not rule.update(hash) if not rule.update(hash)

View File

@ -2,7 +2,7 @@ class DiscourseChat::Channel < DiscourseChat::PluginModel
KEY_PREFIX = 'channel:' KEY_PREFIX = 'channel:'
# Setup ActiveRecord::Store to use the JSON field to read/write these values # Setup ActiveRecord::Store to use the JSON field to read/write these values
store :value, accessors: [ :provider, :data ], coder: JSON store :value, accessors: [ :provider, :error_key, :data ], coder: JSON
after_initialize :init_data after_initialize :init_data

View File

@ -2,7 +2,7 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel
KEY_PREFIX = 'rule:' KEY_PREFIX = 'rule:'
# Setup ActiveRecord::Store to use the JSON field to read/write these values # Setup ActiveRecord::Store to use the JSON field to read/write these values
store :value, accessors: [ :channel_id, :category_id, :tags, :filter, :error_key ], coder: JSON store :value, accessors: [ :channel_id, :category_id, :tags, :filter ], coder: JSON
after_initialize :init_filter after_initialize :init_filter
@ -67,9 +67,9 @@ class DiscourseChat::Rule < DiscourseChat::PluginModel
end end
# Mock foreign key # Mock foreign key
# Could raise RecordNotFound # Could return nil
def channel def channel
DiscourseChat::Channel.find(channel_id) DiscourseChat::Channel.find_by(id:channel_id)
end end
def channel=(val) def channel=(val)
self.channel_id = val.id self.channel_id = val.id

View File

@ -1,7 +1,7 @@
require_relative './rule_serializer' require_relative './rule_serializer'
class DiscourseChat::ChannelSerializer < ApplicationSerializer class DiscourseChat::ChannelSerializer < ApplicationSerializer
attributes :id, :provider, :data, :rules attributes :id, :provider, :error_key, :data, :rules
def rules def rules
object.rules.order_by_precedence.map do |rule| object.rules.order_by_precedence.map do |rule|

View File

@ -1,3 +1,3 @@
class DiscourseChat::RuleSerializer < ApplicationSerializer class DiscourseChat::RuleSerializer < ApplicationSerializer
attributes :id, :channel_id, :category_id, :tags, :filter, :error_key attributes :id, :channel_id, :category_id, :tags, :filter
end end

View File

@ -61,35 +61,31 @@ module DiscourseChat
# Loop through each rule, and trigger appropriate notifications # Loop through each rule, and trigger appropriate notifications
matching_rules.each do |rule| matching_rules.each do |rule|
channel = rule.channel # If there are any issues, skip to the next rule
provider = ::DiscourseChat::Provider.get_by_name(channel.provider) next unless channel = rule.channel
is_enabled = ::DiscourseChat::Provider.is_enabled(provider) 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
begin provider.trigger_notification(post, channel)
provider.trigger_notification(post, rule.channel) channel.update_attribute('error_key', nil) if channel.error_key
rule.update_attribute('error_key', nil) if rule.error_key rescue => e
rescue => e if e.class == DiscourseChat::ProviderError and e.info.key?(:error_key) and !e.info[:error_key].nil?
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])
rule.update_attribute('error_key', e.info[:error_key]) else
else channel.update_attribute('error_key','chat_integration.channel_exception')
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 }
)
end end
elsif provider
# Provider is disabled, don't do anything # Log the error
else Discourse.handle_job_exception(e,
# TODO: Handle when the provider does not exist 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 end
end end

View File

@ -28,9 +28,11 @@ export default Ember.Component.extend({
createRule(channel){ createRule(channel){
var newRule = this.get('store').createRecord('rule',{channel_id: channel.id}); var newRule = this.get('store').createRecord('rule',{channel_id: channel.id});
channel.rules.pushObject(newRule) channel.rules.pushObject(newRule)
} },
showError(error_key){
bootbox.alert(I18n.t(error_key));
},
} }
}); });

View File

@ -34,11 +34,6 @@ export default Ember.Controller.extend({
var model = {channel:channel} var model = {channel:channel}
showModal('admin-plugins-chat-test', { model: model, admin: true }); showModal('admin-plugins-chat-test', { model: model, admin: true });
}, },
showError(error_key){
bootbox.alert(I18n.t(error_key));
},
} }

View File

@ -7,6 +7,10 @@
{{d-button class='cancel' action="delete" actionParam=channel icon="trash" title="chat_integration.delete_channel" label="chat_integration.delete_channel"}} {{d-button class='cancel' action="delete" actionParam=channel icon="trash" title="chat_integration.delete_channel" label="chat_integration.delete_channel"}}
</div> </div>
<span class='channel-title'> <span class='channel-title'>
{{#if channel.error_key}}
{{d-button action="showError" actionParam=channel.error_key class="delete btn-danger" icon="exclamation-triangle"}}
{{/if}}
{{# each provider.channel_parameters as |param|}} {{# each provider.channel_parameters as |param|}}
<b>{{i18n (concat 'chat_integration.provider.' channel.provider '.param.' param.key '.title')}}:</b> <b>{{i18n (concat 'chat_integration.provider.' channel.provider '.param.' param.key '.title')}}:</b>

View File

@ -103,7 +103,8 @@ describe 'Chat Controller', type: :request do
"id" => channel.id, "id" => channel.id,
"provider" => 'dummy', "provider" => 'dummy',
"data" => {}, "data" => {},
"rules" => [{"id" => rule.id, "filter" => "follow", "channel_id" => channel.id, "category_id" => category.id, "tags" => [tag.name], "error_key" => nil}] "error_key" => nil,
"rules" => [{"id" => rule.id, "filter" => "follow", "channel_id" => channel.id, "category_id" => category.id, "tags" => [tag.name]}]
) )
end end

View File

@ -28,18 +28,18 @@ RSpec.describe DiscourseChat::Manager do
provider.set_raise_exception(DiscourseChat::ProviderError.new info: {error_key:"hello"}) provider.set_raise_exception(DiscourseChat::ProviderError.new info: {error_key:"hello"})
manager.trigger_notifications(first_post.id) manager.trigger_notifications(first_post.id)
expect(provider.sent_to_channel_ids).to contain_exactly() expect(provider.sent_to_channel_ids).to contain_exactly()
expect(DiscourseChat::Rule.all.first.error_key).to eq('hello') expect(DiscourseChat::Channel.all.first.error_key).to eq('hello')
# Triggering a different error should set the error_key to a generic message # Triggering a different error should set the error_key to a generic message
provider.set_raise_exception(StandardError.new "hello") provider.set_raise_exception(StandardError.new "hello")
manager.trigger_notifications(first_post.id) manager.trigger_notifications(first_post.id)
expect(provider.sent_to_channel_ids).to contain_exactly() expect(provider.sent_to_channel_ids).to contain_exactly()
expect(DiscourseChat::Rule.all.first.error_key).to eq('chat_integration.rule_exception') expect(DiscourseChat::Channel.all.first.error_key).to eq('chat_integration.channel_exception')
provider.set_raise_exception(nil) provider.set_raise_exception(nil)
manager.trigger_notifications(first_post.id) manager.trigger_notifications(first_post.id)
expect(DiscourseChat::Rule.all.first.error_key.nil?).to be true expect(DiscourseChat::Channel.all.first.error_key.nil?).to be true
end end
it "should not send notifications when provider is disabled" do it "should not send notifications when provider is disabled" do