mirror of
https://github.com/discourse/discourse-chat-integration.git
synced 2025-03-09 14:35:34 +00:00
Providers can define their own errors, and these are presented in the user interface. e.g. Slack can define an error that says “That channel doesn’t exist”. Errors in the UI disappear once a message has been sent successfully, or the rule is edited.
99 lines
3.8 KiB
Ruby
99 lines
3.8 KiB
Ruby
module DiscourseChat
|
|
module Manager
|
|
|
|
def self.guardian
|
|
Guardian.new(User.find_by(username: SiteSetting.chat_integration_discourse_username))
|
|
end
|
|
|
|
def self.trigger_notifications(post_id)
|
|
Rails.logger.info("Triggering chat notifications for post #{post_id}")
|
|
|
|
post = Post.find_by(id: post_id)
|
|
|
|
# Abort if the chat_user doesn't have permission to see the post
|
|
return if !guardian.can_see?(post)
|
|
|
|
# Abort if the post is blank, or is non-regular (e.g. a "topic closed" notification)
|
|
return if post.blank? || post.post_type != Post.types[:regular]
|
|
|
|
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
|
|
|
|
# Load all the rules that apply to this topic's category
|
|
matching_rules = DiscourseChat::Rule.all_for_category(topic.category_id)
|
|
|
|
if topic.category # Also load the rules for the wildcard category
|
|
matching_rules += DiscourseChat::Rule.all_for_category(nil)
|
|
end
|
|
|
|
# If tagging is enabled, thow away rules that don't apply to this topic
|
|
if SiteSetting.tagging_enabled
|
|
topic_tags = topic.tags.present? ? topic.tags.pluck(:name) : []
|
|
matching_rules = matching_rules.select do |rule|
|
|
next true if rule.tags.nil? or rule.tags.empty? # Filter has no tags specified
|
|
any_tags_match = !((rule.tags & topic_tags).empty?)
|
|
next any_tags_match # If any tags match, keep this filter, otherwise throw away
|
|
end
|
|
end
|
|
|
|
# Sort by order of precedence (mute always wins; watch beats follow)
|
|
precedence = { 'mute' => 0, 'watch' => 1, 'follow' => 2}
|
|
sort_func = proc { |a, b| precedence[a.filter] <=> precedence[b.filter] }
|
|
matching_rules = matching_rules.sort(&sort_func)
|
|
|
|
# Take the first rule for each channel
|
|
uniq_func = proc { |rule| [rule.provider, rule.channel] }
|
|
matching_rules = matching_rules.uniq(&uniq_func)
|
|
|
|
# If a matching rule is set to mute, we can discard it now
|
|
matching_rules = matching_rules.select { |rule| rule.filter != "mute" }
|
|
|
|
# If this is not the first post, discard all "follow" rules
|
|
if not post.is_first_post?
|
|
matching_rules = matching_rules.select { |rule| rule.filter != "follow" }
|
|
end
|
|
|
|
# All remaining rules now require a notification to be sent
|
|
# If there are none left, abort
|
|
return false if matching_rules.empty?
|
|
|
|
# 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 provider and is_enabled
|
|
begin
|
|
provider.trigger_notification(post, rule.channel)
|
|
rule.update({error_key: nil}, false) if rule.error_key
|
|
rescue => e
|
|
if e.class == DiscourseChat::ProviderError and e.info.key?(:error_key) and !e.info[:error_key].nil?
|
|
rule.error_key = e.info[:error_key]
|
|
else
|
|
rule.error_key = 'chat_integration.rule_exception'
|
|
end
|
|
rule.save(false) # Save without validations
|
|
|
|
# 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
|
|
elsif provider
|
|
# Provider is disabled, don't do anything
|
|
else
|
|
# TODO: Handle when the provider does not exist
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
end
|
|
end |