Feature: add chat integration reference post (#216)
* FEATURE: Add chat integration reference post This class works similar to a post but it is not a post. * DEV: change how `excerpt` method works * feature: Add `send_chat_integration_message` scriptable add `send_chat_integration_message` scriptable that uses the rules to send a message to the chat provider add locale strings for the new scriptable update `ChatIntegrationReferencePost` `excerpt` method add tests for `ChatIntegrationReferencePost` * DEV: Add `get_channel_by_name` to every provider This makes using `trigger_notification` easier with every provider as well. * DEV: Add `get_channel_name` to all providers This method gets the name of the channel based on how the provider identifies it. Updates channel_name in locales yaml Adds migrate_tag_added_filter_to_all_providers.rb to move all existing rules to use Automation * DEV: Add removal of old migration data Update small action locales with strings from core * DEV: solve review comments * DEV: update test locale strings * DEV: remove empty line to trigger lint * DEV: lint applied * DEV: Add tests for automation integration * DEV: add rails logger for when automatio error occurs * DEV: move migration to be SQL only Update provider helper to use hashes instead of dot notation * DEV: update migration with correct table names * DEV: Update migrate_tag_added_filter_to_all_providers to use smaller SQL queries Commented out migrate_tag_added_from_filter_to_automation.rb * DEV: update comments in migration file * DEV: update indentation in client.en.yml * DEV: update with review comments * Update spec/lib/discourse_chat_integration/chat_integration_reference_post_spec.rb Co-authored-by: Jarek Radosz <jradosz@gmail.com> * Update spec/lib/discourse_chat_integration/chat_integration_reference_post_spec.rb Co-authored-by: Jarek Radosz <jradosz@gmail.com> * Update spec/lib/discourse_chat_integration/chat_integration_reference_post_spec.rb Co-authored-by: Jarek Radosz <jradosz@gmail.com> * Update spec/integration/automation_spec.rb Co-authored-by: Jarek Radosz <jradosz@gmail.com> * Update lib/discourse_chat_integration/chat_integration_reference_post.rb Co-authored-by: Jarek Radosz <jradosz@gmail.com> * DEV: update specs with review comments * DEV: update typos in tests * DEV: inlined functions for getting channel name for provider in migration --------- Co-authored-by: Jarek Radosz <jradosz@gmail.com>
This commit is contained in:
parent
b36ddedb1a
commit
3f8b67d1c1
|
@ -281,3 +281,12 @@ en:
|
||||||
label: URL
|
label: URL
|
||||||
channel:
|
channel:
|
||||||
label: Channel
|
label: Channel
|
||||||
|
|
||||||
|
send_chat_integration_message:
|
||||||
|
title: Send Chat-Integration message
|
||||||
|
fields:
|
||||||
|
channel_name:
|
||||||
|
label: Channel name
|
||||||
|
description: "You can find the channel name in the Chat Integration settings"
|
||||||
|
provider:
|
||||||
|
label: Provider
|
||||||
|
|
|
@ -125,6 +125,8 @@ en:
|
||||||
scriptables:
|
scriptables:
|
||||||
send_slack_message:
|
send_slack_message:
|
||||||
title: Send Slack message
|
title: Send Slack message
|
||||||
|
send_chat_integration_message:
|
||||||
|
title: Send Chat-Integration message
|
||||||
chat_integration:
|
chat_integration:
|
||||||
|
|
||||||
all_categories: "(all categories)"
|
all_categories: "(all categories)"
|
||||||
|
@ -134,6 +136,12 @@ en:
|
||||||
group_mention_template: "mentions of: @%{name}"
|
group_mention_template: "mentions of: @%{name}"
|
||||||
group_message_template: "messages to: @%{name}"
|
group_message_template: "messages to: @%{name}"
|
||||||
|
|
||||||
|
|
||||||
|
topic_tag_changed:
|
||||||
|
added_and_removed: "Added %{added} and removed %{removed}"
|
||||||
|
added: "Added %{added}"
|
||||||
|
removed: "Removed %{removed}"
|
||||||
|
|
||||||
provider:
|
provider:
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
|
|
|
@ -1,92 +1,96 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# The next migration file is a migration that migrates the tag_added filter to an automation.
|
||||||
|
# this one uses ActiveRecord which is not recommended for migrations.
|
||||||
|
|
||||||
class MigrateTagAddedFromFilterToAutomation < ActiveRecord::Migration[7.1]
|
class MigrateTagAddedFromFilterToAutomation < ActiveRecord::Migration[7.1]
|
||||||
def up
|
def up
|
||||||
if defined?(DiscourseAutomation) &&
|
# if defined?(DiscourseAutomation) &&
|
||||||
DiscourseChatIntegration::Channel.with_provider("slack").exists?
|
# DiscourseChatIntegration::Channel.with_provider("slack").exists?
|
||||||
begin
|
# begin
|
||||||
DiscourseChatIntegration::Rule
|
# DiscourseChatIntegration::Rule
|
||||||
.where("value::json->>'filter'=?", "tag_added")
|
# .where("value::json->>'filter'=?", "tag_added")
|
||||||
.each do |rule|
|
# .each do |rule|
|
||||||
channel_id = rule.value["channel_id"]
|
# channel_id = rule.value["channel_id"]
|
||||||
channel_name =
|
# channel_name =
|
||||||
DiscourseChatIntegration::Channel.find(channel_id).value["data"]["identifier"] # it _must_ have a channel_id
|
# DiscourseChatIntegration::Channel.find(channel_id).value["data"]["identifier"] # it _must_ have a channel_id
|
||||||
|
|
||||||
category_id = rule.value["category_id"]
|
# category_id = rule.value["category_id"]
|
||||||
tags = rule.value["tags"]
|
# tags = rule.value["tags"]
|
||||||
|
|
||||||
automation =
|
# automation =
|
||||||
DiscourseAutomation::Automation.new(
|
# DiscourseAutomation::Automation.new(
|
||||||
script: "send_slack_message",
|
# script: "send_slack_message",
|
||||||
trigger: "topic_tags_changed",
|
# trigger: "topic_tags_changed",
|
||||||
name: "When tags change in topic",
|
# name: "When tags change in topic",
|
||||||
enabled: true,
|
# enabled: true,
|
||||||
last_updated_by_id: Discourse.system_user.id,
|
# last_updated_by_id: Discourse.system_user.id,
|
||||||
)
|
# )
|
||||||
|
|
||||||
automation.save!
|
# automation.save!
|
||||||
|
|
||||||
# Triggers:
|
# # Triggers:
|
||||||
# Watching categories
|
# # Watching categories
|
||||||
|
|
||||||
metadata = (category_id ? { "value" => [category_id] } : {})
|
# metadata = (category_id ? { "value" => [category_id] } : {})
|
||||||
|
|
||||||
automation.upsert_field!(
|
# automation.upsert_field!(
|
||||||
"watching_categories",
|
# "watching_categories",
|
||||||
"categories",
|
# "categories",
|
||||||
metadata,
|
# metadata,
|
||||||
target: "trigger",
|
# target: "trigger",
|
||||||
)
|
# )
|
||||||
|
|
||||||
# Watching tags
|
# # Watching tags
|
||||||
|
|
||||||
metadata = (tags ? { "value" => tags } : {})
|
# metadata = (tags ? { "value" => tags } : {})
|
||||||
|
|
||||||
automation.upsert_field!("watching_tags", "tags", metadata, target: "trigger")
|
# automation.upsert_field!("watching_tags", "tags", metadata, target: "trigger")
|
||||||
|
|
||||||
# Script options:
|
# # Script options:
|
||||||
# Message
|
# # Message
|
||||||
automation.upsert_field!(
|
# automation.upsert_field!(
|
||||||
"message",
|
# "message",
|
||||||
"message",
|
# "message",
|
||||||
{ "value" => "${ADDED_AND_REMOVED}" },
|
# { "value" => "${ADDED_AND_REMOVED}" },
|
||||||
target: "script",
|
# target: "script",
|
||||||
)
|
# )
|
||||||
|
|
||||||
# URL
|
# # URL
|
||||||
automation.upsert_field!(
|
# automation.upsert_field!(
|
||||||
"url",
|
# "url",
|
||||||
"text",
|
# "text",
|
||||||
{ "value" => Discourse.current_hostname },
|
# { "value" => Discourse.current_hostname },
|
||||||
target: "script",
|
# target: "script",
|
||||||
)
|
# )
|
||||||
|
|
||||||
# Channel
|
# # Channel
|
||||||
automation.upsert_field!(
|
# automation.upsert_field!(
|
||||||
"channel",
|
# "channel",
|
||||||
"text",
|
# "text",
|
||||||
{ "value" => channel_name },
|
# { "value" => channel_name },
|
||||||
target: "script",
|
# target: "script",
|
||||||
)
|
# )
|
||||||
end
|
# end
|
||||||
rescue StandardError
|
# rescue StandardError
|
||||||
Rails.logger.warn("Failed to migrate tag_added rules to automations")
|
# Rails.logger.warn("Failed to migrate tag_added rules to automations")
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
end
|
end
|
||||||
|
|
||||||
def down
|
def down
|
||||||
if defined?(DiscourseAutomation) &&
|
# if defined?(DiscourseAutomation) &&
|
||||||
DiscourseChatIntegration::Channel.with_provider("slack").exists?
|
# DiscourseChatIntegration::Channel.with_provider("slack").exists?
|
||||||
DiscourseAutomation::Automation
|
# DiscourseAutomation::Automation
|
||||||
.where(script: "send_slack_message", trigger: "topic_tags_changed")
|
# .where(script: "send_slack_message", trigger: "topic_tags_changed")
|
||||||
.each do |automation|
|
# .each do |automation|
|
||||||
# if is the same name as created and message is the same
|
# # if is the same name as created and message is the same
|
||||||
if automation.name == "When tags change in topic" &&
|
# if automation.name == "When tags change in topic" &&
|
||||||
automation.fields.where(name: "message").first.metadata["value"] ==
|
# automation.fields.where(name: "message").first.metadata["value"] ==
|
||||||
"${ADDED_AND_REMOVED}"
|
# "${ADDED_AND_REMOVED}"
|
||||||
automation.destroy!
|
# automation.destroy!
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class MigrateTagAddedFilterToAllProviders < ActiveRecord::Migration[7.1]
|
||||||
|
def up
|
||||||
|
if defined?(DiscourseAutomation)
|
||||||
|
begin
|
||||||
|
slack_usage_rows = DB.query <<~SQL
|
||||||
|
SELECT plugin_store_rows.* FROM plugin_store_rows
|
||||||
|
WHERE plugin_store_rows.type_name = 'JSON'
|
||||||
|
AND plugin_store_rows.plugin_name = 'discourse-chat-integration'
|
||||||
|
AND (key LIKE 'channel:%')
|
||||||
|
AND (value::json->>'provider'='slack')
|
||||||
|
SQL
|
||||||
|
|
||||||
|
old_migration_delete = <<~SQL
|
||||||
|
DELETE FROM discourse_automation_automations
|
||||||
|
WHERE id IN (
|
||||||
|
SELECT a.id
|
||||||
|
FROM discourse_automation_automations a
|
||||||
|
JOIN discourse_automation_fields f ON f.automation_id = a.id
|
||||||
|
WHERE a.script = 'send_slack_message'
|
||||||
|
AND a.trigger = 'topic_tags_changed'
|
||||||
|
AND a.name = 'When tags change in topic'
|
||||||
|
AND f.name = 'message'
|
||||||
|
AND f.metadata->>'value' = '${ADDED_AND_REMOVED}'
|
||||||
|
)
|
||||||
|
SQL
|
||||||
|
# Trash old migration
|
||||||
|
DB.exec old_migration_delete if slack_usage_rows.count > 0
|
||||||
|
|
||||||
|
rules_with_tag_added = <<~SQL
|
||||||
|
SELECT value
|
||||||
|
FROM plugin_store_rows
|
||||||
|
WHERE plugin_name = 'discourse-chat-integration'
|
||||||
|
AND key LIKE 'rule:%'
|
||||||
|
AND value::json->>'filter' = 'tag_added'
|
||||||
|
SQL
|
||||||
|
|
||||||
|
channel_query = <<~SQL
|
||||||
|
SELECT *
|
||||||
|
FROM plugin_store_rows
|
||||||
|
WHERE type_name = 'JSON'
|
||||||
|
AND plugin_name = 'discourse-chat-integration'
|
||||||
|
AND key LIKE 'channel:%'
|
||||||
|
AND id = :channel_id
|
||||||
|
LIMIT 1
|
||||||
|
SQL
|
||||||
|
|
||||||
|
automation_creation = <<~SQL
|
||||||
|
INSERT INTO discourse_automation_automations (script, trigger, name, enabled, last_updated_by_id, created_at, updated_at)
|
||||||
|
VALUES ('send_chat_integration_message', 'topic_tags_changed', 'When tags change in topic', true, -1, NOW(), NOW())
|
||||||
|
RETURNING id
|
||||||
|
SQL
|
||||||
|
|
||||||
|
create_automation_field = <<~SQL
|
||||||
|
INSERT INTO discourse_automation_fields (automation_id, name, component, metadata, target, created_at, updated_at)
|
||||||
|
VALUES (:automation_id, :name, :component, :metadata, :target, NOW(), NOW())
|
||||||
|
SQL
|
||||||
|
|
||||||
|
provider_identifier_map = {
|
||||||
|
"groupme" => "groupme_instance_name",
|
||||||
|
"discord" => "name",
|
||||||
|
"guilded" => "name",
|
||||||
|
"mattermost" => "identifier",
|
||||||
|
"matrix" => "name",
|
||||||
|
"teams" => "name",
|
||||||
|
"zulip" => "stream",
|
||||||
|
"powerautomate" => "name",
|
||||||
|
"rocketchat" => "identifier",
|
||||||
|
"gitter" => "name",
|
||||||
|
"telegram" => "name",
|
||||||
|
"flowdock" => "flow_token",
|
||||||
|
"google" => "name",
|
||||||
|
"webex" => "name",
|
||||||
|
"slack" => "identifier",
|
||||||
|
}
|
||||||
|
|
||||||
|
DB
|
||||||
|
.query(rules_with_tag_added)
|
||||||
|
.each do |row|
|
||||||
|
rule = JSON.parse(row.value).with_indifferent_access
|
||||||
|
|
||||||
|
channel =
|
||||||
|
JSON.parse(
|
||||||
|
DB.query(channel_query, channel_id: rule[:channel_id]).first.value,
|
||||||
|
).with_indifferent_access
|
||||||
|
|
||||||
|
provider_name = channel[:provider]
|
||||||
|
channel_name = channel[:data][provider_identifier_map[provider_name]]
|
||||||
|
|
||||||
|
category_id = rule[:category_id]
|
||||||
|
tags = rule[:tags]
|
||||||
|
|
||||||
|
automation_id = DB.query(automation_creation).first.id
|
||||||
|
|
||||||
|
# Triggers:
|
||||||
|
# Watching categories
|
||||||
|
metadata = (category_id ? { "value" => [category_id] } : {}).to_json
|
||||||
|
DB.exec(
|
||||||
|
create_automation_field,
|
||||||
|
automation_id: automation_id,
|
||||||
|
name: "watching_categories",
|
||||||
|
component: "categories",
|
||||||
|
metadata: metadata,
|
||||||
|
target: "trigger",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Watching tags
|
||||||
|
metadata = (tags.present? ? { "value" => tags } : {}).to_json
|
||||||
|
DB.exec(
|
||||||
|
create_automation_field,
|
||||||
|
automation_id: automation_id,
|
||||||
|
name: "watching_tags",
|
||||||
|
component: "tags",
|
||||||
|
metadata: metadata,
|
||||||
|
target: "trigger",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Script options:
|
||||||
|
# Provider
|
||||||
|
DB.exec(
|
||||||
|
create_automation_field,
|
||||||
|
automation_id: automation_id,
|
||||||
|
name: "provider",
|
||||||
|
component: "choices",
|
||||||
|
metadata: { "value" => provider_name }.to_json,
|
||||||
|
target: "script",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Channel name
|
||||||
|
DB.exec(
|
||||||
|
create_automation_field,
|
||||||
|
automation_id: automation_id,
|
||||||
|
name: "channel_name",
|
||||||
|
component: "text",
|
||||||
|
metadata: { "value" => channel_name }.to_json,
|
||||||
|
target: "script",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
rescue StandardError
|
||||||
|
puts "Error migrating tag_added filters to all providers"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
DB.exec <<~SQL if defined?(DiscourseAutomation)
|
||||||
|
DELETE FROM discourse_automation_automations
|
||||||
|
WHERE script = 'send_chat_integration_message'
|
||||||
|
AND trigger = 'topic_tags_changed'
|
||||||
|
AND name = 'When tags change in topic'
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,75 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module DiscourseChatIntegration
|
||||||
|
class ChatIntegrationReferencePost
|
||||||
|
def initialize(user:, topic:, kind:, raw: nil, context: {})
|
||||||
|
@user = user
|
||||||
|
@topic = topic
|
||||||
|
@kind = kind
|
||||||
|
@raw = raw if raw.present?
|
||||||
|
@context = context
|
||||||
|
@created_at = Time.current
|
||||||
|
end
|
||||||
|
|
||||||
|
def id
|
||||||
|
@topic.posts.empty? ? @topic.id : @topic.posts.first.id
|
||||||
|
end
|
||||||
|
|
||||||
|
def user
|
||||||
|
@user
|
||||||
|
end
|
||||||
|
|
||||||
|
def topic
|
||||||
|
@topic
|
||||||
|
end
|
||||||
|
|
||||||
|
def full_url
|
||||||
|
@topic.posts.empty? ? @topic.full_url : @topic.posts.first.full_url
|
||||||
|
end
|
||||||
|
|
||||||
|
def excerpt(maxlength = nil, options = {})
|
||||||
|
cooked = PrettyText.cook(raw, { user_id: user.id })
|
||||||
|
maxlength ||= SiteSetting.post_excerpt_maxlength
|
||||||
|
PrettyText.excerpt(cooked, maxlength, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_first_post?
|
||||||
|
topic.try(:highest_post_number) == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def created_at
|
||||||
|
@created_at
|
||||||
|
end
|
||||||
|
|
||||||
|
def raw
|
||||||
|
if @raw.nil? && @kind == DiscourseAutomation::Triggers::TOPIC_TAGS_CHANGED
|
||||||
|
tag_list_to_raw = ->(tag_list) do
|
||||||
|
tag_list.sort.map { |tag_name| "##{tag_name}" }.join(", ")
|
||||||
|
end
|
||||||
|
|
||||||
|
added_tags = @context["added_tags"]
|
||||||
|
removed_tags = @context["removed_tags"]
|
||||||
|
|
||||||
|
@raw =
|
||||||
|
if added_tags.present? && removed_tags.present?
|
||||||
|
I18n.t(
|
||||||
|
"chat_integration.topic_tag_changed.added_and_removed",
|
||||||
|
added: tag_list_to_raw.call(added_tags),
|
||||||
|
removed: tag_list_to_raw.call(removed_tags),
|
||||||
|
)
|
||||||
|
elsif added_tags.present?
|
||||||
|
I18n.t(
|
||||||
|
"chat_integration.topic_tag_changed.added",
|
||||||
|
added: tag_list_to_raw.call(added_tags),
|
||||||
|
)
|
||||||
|
elsif removed_tags.present?
|
||||||
|
I18n.t(
|
||||||
|
"chat_integration.topic_tag_changed.removed",
|
||||||
|
removed: tag_list_to_raw.call(removed_tags),
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@raw
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,7 +5,7 @@ module DiscourseChatIntegration
|
||||||
module DiscordProvider
|
module DiscordProvider
|
||||||
PROVIDER_NAME = "discord".freeze
|
PROVIDER_NAME = "discord".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_discord_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_discord_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "name".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "name", regex: '^\S+' },
|
{ key: "name", regex: '^\S+' },
|
||||||
{
|
{
|
||||||
|
@ -94,6 +94,13 @@ module DiscourseChatIntegration
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
module DiscourseChatIntegration::Provider::FlowdockProvider
|
module DiscourseChatIntegration::Provider::FlowdockProvider
|
||||||
PROVIDER_NAME = "flowdock".freeze
|
PROVIDER_NAME = "flowdock".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_flowdock_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_flowdock_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "flow_token".freeze # this is really weird but is the only way to identify a channel in this provider
|
||||||
CHANNEL_PARAMETERS = [{ key: "flow_token", regex: '^\S+', unique: true, hidden: true }]
|
CHANNEL_PARAMETERS = [{ key: "flow_token", regex: '^\S+', unique: true, hidden: true }]
|
||||||
|
|
||||||
def self.send_message(url, message)
|
def self.send_message(url, message)
|
||||||
|
@ -60,4 +61,11 @@ module DiscourseChatIntegration::Provider::FlowdockProvider
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ module DiscourseChatIntegration
|
||||||
module GitterProvider
|
module GitterProvider
|
||||||
PROVIDER_NAME = "gitter".freeze
|
PROVIDER_NAME = "gitter".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_gitter_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_gitter_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "name".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "name", regex: '^\S+$', unique: true },
|
{ key: "name", regex: '^\S+$', unique: true },
|
||||||
{
|
{
|
||||||
|
@ -43,6 +44,13 @@ module DiscourseChatIntegration
|
||||||
|
|
||||||
"[__#{display_name}__ - #{topic.title} - #{category_name}](#{post.full_url})"
|
"[__#{display_name}__ - #{topic.title} - #{category_name}](#{post.full_url})"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ module DiscourseChatIntegration
|
||||||
module GoogleProvider
|
module GoogleProvider
|
||||||
PROVIDER_NAME = "google".freeze
|
PROVIDER_NAME = "google".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_google_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_google_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "name".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "name", regex: '^\S+$', unique: true },
|
{ key: "name", regex: '^\S+$', unique: true },
|
||||||
{
|
{
|
||||||
|
@ -107,6 +108,13 @@ module DiscourseChatIntegration
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
module DiscourseChatIntegration::Provider::GroupmeProvider
|
module DiscourseChatIntegration::Provider::GroupmeProvider
|
||||||
PROVIDER_NAME = "groupme".freeze
|
PROVIDER_NAME = "groupme".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_groupme_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_groupme_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "groupme_instance_name".freeze
|
||||||
CHANNEL_PARAMETERS = [{ key: "groupme_instance_name", regex: '[\s\S]*', unique: true }]
|
CHANNEL_PARAMETERS = [{ key: "groupme_instance_name", regex: '[\s\S]*', unique: true }]
|
||||||
|
|
||||||
def self.generate_groupme_message(post)
|
def self.generate_groupme_message(post)
|
||||||
|
@ -84,4 +85,11 @@ module DiscourseChatIntegration::Provider::GroupmeProvider
|
||||||
data_package = generate_groupme_message(post)
|
data_package = generate_groupme_message(post)
|
||||||
self.send_via_webhook(data_package, channel)
|
self.send_via_webhook(data_package, channel)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ module DiscourseChatIntegration
|
||||||
module GuildedProvider
|
module GuildedProvider
|
||||||
PROVIDER_NAME = "guilded".freeze
|
PROVIDER_NAME = "guilded".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_guilded_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_guilded_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "name".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "name", regex: '^\S+' },
|
{ key: "name", regex: '^\S+' },
|
||||||
{
|
{
|
||||||
|
@ -92,6 +92,13 @@ module DiscourseChatIntegration
|
||||||
return url if !url.start_with?("//")
|
return url if !url.start_with?("//")
|
||||||
"http:#{url}"
|
"http:#{url}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ module DiscourseChatIntegration
|
||||||
module MatrixProvider
|
module MatrixProvider
|
||||||
PROVIDER_NAME = "matrix".freeze
|
PROVIDER_NAME = "matrix".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_matrix_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_matrix_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "name".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "name", regex: '^\S+' },
|
{ key: "name", regex: '^\S+' },
|
||||||
{ key: "room_id", regex: '^\!\S+:\S+$', unique: true, hidden: true },
|
{ key: "room_id", regex: '^\!\S+:\S+$', unique: true, hidden: true },
|
||||||
|
@ -88,6 +89,13 @@ module DiscourseChatIntegration
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ module DiscourseChatIntegration
|
||||||
module MattermostProvider
|
module MattermostProvider
|
||||||
PROVIDER_NAME = "mattermost".freeze
|
PROVIDER_NAME = "mattermost".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_mattermost_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_mattermost_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "identifier".freeze
|
||||||
CHANNEL_PARAMETERS = [{ key: "identifier", regex: '^[@#]\S*$', unique: true }]
|
CHANNEL_PARAMETERS = [{ key: "identifier", regex: '^[@#]\S*$', unique: true }]
|
||||||
|
|
||||||
def self.send_via_webhook(message)
|
def self.send_via_webhook(message)
|
||||||
|
@ -93,6 +94,13 @@ module DiscourseChatIntegration
|
||||||
|
|
||||||
self.send_via_webhook(message)
|
self.send_via_webhook(message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
module DiscourseChatIntegration::Provider::PowerAutomateProvider
|
module DiscourseChatIntegration::Provider::PowerAutomateProvider
|
||||||
PROVIDER_NAME = "powerautomate"
|
PROVIDER_NAME = "powerautomate"
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_powerautomate_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_powerautomate_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "name".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "name", regex: '^\S+$', unique: true },
|
{ key: "name", regex: '^\S+$', unique: true },
|
||||||
{ key: "webhook_url", regex: '^https:\/\/\S+$', unique: true, hidden: true },
|
{ key: "webhook_url", regex: '^https:\/\/\S+$', unique: true, hidden: true },
|
||||||
|
@ -130,4 +131,11 @@ module DiscourseChatIntegration::Provider::PowerAutomateProvider
|
||||||
|
|
||||||
message
|
message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ module DiscourseChatIntegration::Provider::RocketchatProvider
|
||||||
PROVIDER_NAME = "rocketchat".freeze
|
PROVIDER_NAME = "rocketchat".freeze
|
||||||
|
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_rocketchat_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_rocketchat_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "identifier".freeze
|
||||||
CHANNEL_PARAMETERS = [{ key: "identifier", regex: '^[@#]\S*$', unique: true }]
|
CHANNEL_PARAMETERS = [{ key: "identifier", regex: '^[@#]\S*$', unique: true }]
|
||||||
|
|
||||||
def self.rocketchat_message(post, channel)
|
def self.rocketchat_message(post, channel)
|
||||||
|
@ -82,4 +82,11 @@ module DiscourseChatIntegration::Provider::RocketchatProvider
|
||||||
|
|
||||||
self.send_via_webhook(message)
|
self.send_via_webhook(message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,7 @@ module DiscourseChatIntegration::Provider::SlackProvider
|
||||||
THREAD_LEGACY = "thread"
|
THREAD_LEGACY = "thread"
|
||||||
|
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_slack_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_slack_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "identifier".freeze
|
||||||
CHANNEL_PARAMETERS = [{ key: "identifier", regex: '^[@#]?\S*$', unique: true }]
|
CHANNEL_PARAMETERS = [{ key: "identifier", regex: '^[@#]?\S*$', unique: true }]
|
||||||
|
|
||||||
require_dependency "topic"
|
require_dependency "topic"
|
||||||
|
@ -339,6 +339,13 @@ module DiscourseChatIntegration::Provider::SlackProvider
|
||||||
def self.create_tag_list(tag_list)
|
def self.create_tag_list(tag_list)
|
||||||
tag_list.map { |tag_name| "<#{Tag.find_by_name(tag_name).full_url}|#{tag_name}>" }.join(", ")
|
tag_list.map { |tag_name| "<#{Tag.find_by_name(tag_name).full_url}|#{tag_name}>" }.join(", ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
require_relative "slack_message_formatter"
|
require_relative "slack_message_formatter"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
module DiscourseChatIntegration::Provider::TeamsProvider
|
module DiscourseChatIntegration::Provider::TeamsProvider
|
||||||
PROVIDER_NAME = "teams".freeze
|
PROVIDER_NAME = "teams".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_teams_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_teams_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "name".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "name", regex: '^\S+$', unique: true },
|
{ key: "name", regex: '^\S+$', unique: true },
|
||||||
{ key: "webhook_url", regex: '^https:\/\/\S+$', unique: true, hidden: true },
|
{ key: "webhook_url", regex: '^https:\/\/\S+$', unique: true, hidden: true },
|
||||||
|
@ -82,4 +83,11 @@ module DiscourseChatIntegration::Provider::TeamsProvider
|
||||||
|
|
||||||
message
|
message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ module DiscourseChatIntegration
|
||||||
module TelegramProvider
|
module TelegramProvider
|
||||||
PROVIDER_NAME = "telegram".freeze
|
PROVIDER_NAME = "telegram".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_telegram_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_telegram_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "name".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "name", regex: '^\S+' },
|
{ key: "name", regex: '^\S+' },
|
||||||
{ key: "chat_id", regex: '^(-?[0-9]+|@\S+)$', unique: true },
|
{ key: "chat_id", regex: '^(-?[0-9]+|@\S+)$', unique: true },
|
||||||
|
@ -110,6 +111,13 @@ module DiscourseChatIntegration
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
module DiscourseChatIntegration::Provider::WebexProvider
|
module DiscourseChatIntegration::Provider::WebexProvider
|
||||||
PROVIDER_NAME = "webex".freeze
|
PROVIDER_NAME = "webex".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_webex_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_webex_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "name".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "name", regex: '^\S+$', unique: true },
|
{ key: "name", regex: '^\S+$', unique: true },
|
||||||
{
|
{
|
||||||
|
@ -71,4 +72,11 @@ module DiscourseChatIntegration::Provider::WebexProvider
|
||||||
|
|
||||||
{ markdown: markdown }
|
{ markdown: markdown }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ module DiscourseChatIntegration
|
||||||
module ZulipProvider
|
module ZulipProvider
|
||||||
PROVIDER_NAME = "zulip".freeze
|
PROVIDER_NAME = "zulip".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_zulip_enabled
|
PROVIDER_ENABLED_SETTING = :chat_integration_zulip_enabled
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "stream".freeze
|
||||||
CHANNEL_PARAMETERS = [
|
CHANNEL_PARAMETERS = [
|
||||||
{ key: "stream", unique: true, regex: '^\S+' },
|
{ key: "stream", unique: true, regex: '^\S+' },
|
||||||
{ key: "subject", unique: true, regex: '^\S+' },
|
{ key: "subject", unique: true, regex: '^\S+' },
|
||||||
|
@ -71,6 +72,13 @@ module DiscourseChatIntegration
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
48
plugin.rb
48
plugin.rb
|
@ -16,6 +16,7 @@ register_svg_icon "fa-arrow-circle-o-right" if respond_to?(:register_svg_icon)
|
||||||
|
|
||||||
# Site setting validators must be loaded before initialize
|
# Site setting validators must be loaded before initialize
|
||||||
require_relative "lib/discourse_chat_integration/provider/slack/slack_enabled_setting_validator"
|
require_relative "lib/discourse_chat_integration/provider/slack/slack_enabled_setting_validator"
|
||||||
|
require_relative "lib/discourse_chat_integration/chat_integration_reference_post"
|
||||||
|
|
||||||
after_initialize do
|
after_initialize do
|
||||||
require_relative "app/initializers/discourse_chat_integration"
|
require_relative "app/initializers/discourse_chat_integration"
|
||||||
|
@ -84,5 +85,52 @@ after_initialize do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_automation_scriptable("send_chat_integration_message") do
|
||||||
|
field :provider,
|
||||||
|
component: :choices,
|
||||||
|
extra: {
|
||||||
|
content:
|
||||||
|
DiscourseChatIntegration::Provider.enabled_provider_names.map do |provider|
|
||||||
|
{ id: provider, name: "chat_integration.provider.#{provider}.title" }
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
required: true
|
||||||
|
field :channel_name, component: :text, required: true
|
||||||
|
|
||||||
|
version 1
|
||||||
|
|
||||||
|
triggerables %i[topic_tags_changed]
|
||||||
|
|
||||||
|
script do |context, fields, automation|
|
||||||
|
provider = fields.dig("provider", "value")
|
||||||
|
channel_name = fields.dig("channel_name", "value")
|
||||||
|
|
||||||
|
post =
|
||||||
|
DiscourseChatIntegration::ChatIntegrationReferencePost.new(
|
||||||
|
user: context["user"],
|
||||||
|
topic: context["topic"],
|
||||||
|
kind: context["kind"],
|
||||||
|
context: {
|
||||||
|
"added_tags" => context["added_tags"],
|
||||||
|
"removed_tags" => context["removed_tags"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
provider = DiscourseChatIntegration::Provider.get_by_name(provider)
|
||||||
|
|
||||||
|
channel = provider.get_channel_by_name(channel_name) # user must have created a channel in /admin/plugins/chat-integration/<provider> page
|
||||||
|
|
||||||
|
if channel.nil?
|
||||||
|
Rails.logger.warn "[discourse-automation] Channel not found. Automation ID: #{automation.id}"
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
provider.trigger_notification(post, channel, nil)
|
||||||
|
rescue StandardError => _
|
||||||
|
Rails.logger.warn "[discourse-automation] Error while sending chat integration message. Automation ID: #{automation.id}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,6 +40,7 @@ RSpec.shared_context "with validated dummy provider" do
|
||||||
module ::DiscourseChatIntegration::Provider::Dummy2Provider
|
module ::DiscourseChatIntegration::Provider::Dummy2Provider
|
||||||
PROVIDER_NAME = "dummy2".freeze
|
PROVIDER_NAME = "dummy2".freeze
|
||||||
PROVIDER_ENABLED_SETTING = :chat_integration_enabled # Tie to main plugin enabled setting
|
PROVIDER_ENABLED_SETTING = :chat_integration_enabled # Tie to main plugin enabled setting
|
||||||
|
CHANNEL_IDENTIFIER_KEY = "val".freeze
|
||||||
CHANNEL_PARAMETERS = [{ key: "val", regex: '^\S+$', unique: true }]
|
CHANNEL_PARAMETERS = [{ key: "val", regex: '^\S+$', unique: true }]
|
||||||
|
|
||||||
@@sent_messages = []
|
@@sent_messages = []
|
||||||
|
@ -51,8 +52,17 @@ RSpec.shared_context "with validated dummy provider" do
|
||||||
def self.sent_messages
|
def self.sent_messages
|
||||||
@@sent_messages
|
@@sent_messages
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_channel_by_name(name)
|
||||||
|
DiscourseChatIntegration::Channel
|
||||||
|
.with_provider(PROVIDER_NAME)
|
||||||
|
.with_data_value(CHANNEL_IDENTIFIER_KEY, name)
|
||||||
|
.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
after(:each) { ::DiscourseChatIntegration::Provider.send(:remove_const, :Dummy2Provider) }
|
after(:each) { ::DiscourseChatIntegration::Provider.send(:remove_const, :Dummy2Provider) }
|
||||||
|
|
||||||
|
let(:validated_provider) { ::DiscourseChatIntegration::Provider::Dummy2Provider }
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
require_relative "../dummy_provider"
|
||||||
|
RSpec.describe "Triggering notifications" do
|
||||||
|
include_context "with validated dummy provider"
|
||||||
|
|
||||||
|
context "with automation installed", if: defined?(DiscourseAutomation) do
|
||||||
|
fab!(:admin)
|
||||||
|
fab!(:category)
|
||||||
|
fab!(:tag)
|
||||||
|
|
||||||
|
fab!(:automation) do
|
||||||
|
Fabricate(
|
||||||
|
:automation,
|
||||||
|
script: "send_chat_integration_message",
|
||||||
|
trigger: "topic_tags_changed",
|
||||||
|
enabled: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
let(:channel1) do
|
||||||
|
DiscourseChatIntegration::Channel.create!(provider: "dummy2", data: { val: "channel" })
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
SiteSetting.chat_integration_enabled = true
|
||||||
|
SiteSetting.discourse_automation_enabled = true
|
||||||
|
|
||||||
|
SiteSetting.tagging_enabled = true
|
||||||
|
SiteSetting.create_tag_allowed_groups = Group::AUTO_GROUPS[:everyone]
|
||||||
|
SiteSetting.tag_topic_allowed_groups = Group::AUTO_GROUPS[:everyone]
|
||||||
|
|
||||||
|
automation.upsert_field!(
|
||||||
|
"watching_categories",
|
||||||
|
"categories",
|
||||||
|
{ "value" => [category.id] },
|
||||||
|
target: "trigger",
|
||||||
|
)
|
||||||
|
automation.upsert_field!(
|
||||||
|
"watching_tags",
|
||||||
|
"tags",
|
||||||
|
{ "value" => [tag.name] },
|
||||||
|
target: "trigger",
|
||||||
|
)
|
||||||
|
automation.upsert_field!(
|
||||||
|
"provider",
|
||||||
|
"choices",
|
||||||
|
{ "value" => channel1.provider },
|
||||||
|
target: "script",
|
||||||
|
)
|
||||||
|
automation.upsert_field!("channel_name", "text", { "value" => "channel" }, target: "script")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "triggers a notification" do
|
||||||
|
topic = Fabricate(:topic, user: admin, tags: [], category: category)
|
||||||
|
|
||||||
|
DiscourseTagging.tag_topic_by_names(topic, Guardian.new(admin), [tag.name])
|
||||||
|
|
||||||
|
expect(validated_provider.sent_messages.length).to eq(1)
|
||||||
|
expect(validated_provider.sent_messages.first[:post]).to eq(topic.id)
|
||||||
|
expect(validated_provider.sent_messages.first[:channel]).to eq(channel1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "only triggers for the correct tag" do
|
||||||
|
topic = Fabricate(:topic, user: admin, tags: [], category: category)
|
||||||
|
|
||||||
|
DiscourseTagging.tag_topic_by_names(topic, Guardian.new(admin), ["other_tag"])
|
||||||
|
|
||||||
|
expect(validated_provider.sent_messages.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "only triggers for the correct category" do
|
||||||
|
topic = Fabricate(:topic, user: admin, tags: [], category: Fabricate(:category))
|
||||||
|
|
||||||
|
DiscourseTagging.tag_topic_by_names(topic, Guardian.new(admin), [tag.name])
|
||||||
|
|
||||||
|
expect(validated_provider.sent_messages.length).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,49 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.describe DiscourseChatIntegration::ChatIntegrationReferencePost do
|
||||||
|
fab!(:topic)
|
||||||
|
fab!(:first_post) { Fabricate(:post, topic: topic) }
|
||||||
|
let!(:context) do
|
||||||
|
{
|
||||||
|
"user" => Fabricate(:user),
|
||||||
|
"topic" => topic,
|
||||||
|
# every rule will add a kind and their context params
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "when creating when topic tags change" do
|
||||||
|
before do
|
||||||
|
context["kind"] = DiscourseAutomation::Triggers::TOPIC_TAGS_CHANGED
|
||||||
|
context["added_tags"] = %w[tag1 tag2]
|
||||||
|
context["removed_tags"] = %w[tag3 tag4]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a post with the correct raw" do
|
||||||
|
post =
|
||||||
|
described_class.new(
|
||||||
|
user: context["user"],
|
||||||
|
topic: context["topic"],
|
||||||
|
kind: context["kind"],
|
||||||
|
context: {
|
||||||
|
"added_tags" => context["added_tags"],
|
||||||
|
"removed_tags" => context["removed_tags"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(post.raw).to eq("Added #tag1, #tag2 and removed #tag3, #tag4")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has a working excerpt" do
|
||||||
|
post =
|
||||||
|
described_class.new(
|
||||||
|
user: context["user"],
|
||||||
|
topic: context["topic"],
|
||||||
|
kind: context["kind"],
|
||||||
|
context: {
|
||||||
|
"added_tags" => context["added_tags"],
|
||||||
|
"removed_tags" => context["removed_tags"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(post.excerpt).to eq("Added #tag1, #tag2 and removed #tag3, #tag4")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -49,4 +49,18 @@ RSpec.describe DiscourseChatIntegration::Provider::DiscordProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "discord",
|
||||||
|
data: {
|
||||||
|
name: "Awesome Channel",
|
||||||
|
webhook_url: "https://discord.com/api/webhooks/1234/abcd",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("Awesome Channel")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,4 +36,19 @@ RSpec.describe DiscourseChatIntegration::Provider::FlowdockProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "flowdock",
|
||||||
|
data: {
|
||||||
|
flow_token: "5d1fe04cf66e078d6a2b579ddb8a465b",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("5d1fe04cf66e078d6a2b579ddb8a465b")).to eq(
|
||||||
|
expected,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,4 +37,18 @@ RSpec.describe DiscourseChatIntegration::Provider::GitterProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "gitter",
|
||||||
|
data: {
|
||||||
|
name: "gitterHQ/services",
|
||||||
|
webhook_url: "https://webhooks.gitter.im/e/a1e2i3o4u5",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("gitterHQ/services")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,4 +33,18 @@ RSpec.describe DiscourseChatIntegration::Provider::GoogleProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "google",
|
||||||
|
data: {
|
||||||
|
name: "discourse",
|
||||||
|
webhook_url: "https://chat.googleapis.com/v1/abcdefg",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("discourse")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,4 +39,17 @@ RSpec.describe DiscourseChatIntegration::Provider::GroupmeProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "groupme",
|
||||||
|
data: {
|
||||||
|
groupme_instance_name: "my instance",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("my instance")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,4 +35,18 @@ RSpec.describe DiscourseChatIntegration::Provider::GuildedProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "guilded",
|
||||||
|
data: {
|
||||||
|
name: "Awesome Channel",
|
||||||
|
webhook_url: "https://media.guilded.gg/webhooks/1234/abcd",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("Awesome Channel")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,4 +44,18 @@ RSpec.describe DiscourseChatIntegration::Provider::MatrixProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "matrix",
|
||||||
|
data: {
|
||||||
|
name: "Awesome Channel",
|
||||||
|
room_id: "!blah:matrix.org",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("Awesome Channel")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,4 +57,17 @@ RSpec.describe DiscourseChatIntegration::Provider::MattermostProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "mattermost",
|
||||||
|
data: {
|
||||||
|
identifier: "#awesomechannel",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("#awesomechannel")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,4 +34,19 @@ RSpec.describe DiscourseChatIntegration::Provider::PowerAutomateProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "powerautomate",
|
||||||
|
data: {
|
||||||
|
name: "discourse",
|
||||||
|
webhook_url:
|
||||||
|
"https://prod-189.westus.logic.azure.com:443/workflows/c94b462906e64fe8a7299043706be96e/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=-cmkg1oG-88dP3Yqdh62yTG1LUtJFcB91rQisorfw_w",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("discourse")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,4 +35,17 @@ RSpec.describe DiscourseChatIntegration::Provider::RocketchatProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "rocketchat",
|
||||||
|
data: {
|
||||||
|
identifier: "#general",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("#general")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -346,4 +346,17 @@ RSpec.describe DiscourseChatIntegration::Provider::SlackProvider do
|
||||||
}.to raise_error(StandardError)
|
}.to raise_error(StandardError)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "slack",
|
||||||
|
data: {
|
||||||
|
identifier: "#general",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("#general")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,4 +44,19 @@ RSpec.describe DiscourseChatIntegration::Provider::TeamsProvider do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "teams",
|
||||||
|
data: {
|
||||||
|
name: "discourse",
|
||||||
|
webhook_url:
|
||||||
|
"https://outlook.office.com/webhook/677980e4-e03b-4a5e-ad29-dc1ee0c32a80@9e9b5238-5ab2-496a-8e6a-e9cf05c7eb5c/IncomingWebhook/e7a1006ded44478992769d0c4f391e34/e028ca8a-e9c8-4c6c-a4d8-578f881a3cff",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("discourse")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,4 +48,18 @@ RSpec.describe DiscourseChatIntegration::Provider::TelegramProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "telegram",
|
||||||
|
data: {
|
||||||
|
name: "Awesome Channel",
|
||||||
|
chat_id: "123",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("Awesome Channel")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,4 +34,19 @@ RSpec.describe DiscourseChatIntegration::Provider::WebexProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
expected =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "webex",
|
||||||
|
data: {
|
||||||
|
name: "discourse",
|
||||||
|
webhook_url:
|
||||||
|
"https://webexapis.com/v1/webhooks/incoming/jAHJjVVQ1cgEwb4ikQQawIrGdUtlocKA9fSNvIyADQoYo0mI70pztWUDOu22gDRPJOEJtCsc688zi1RMa",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(described_class.get_channel_by_name("discourse")).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,4 +42,19 @@ RSpec.describe DiscourseChatIntegration::Provider::ZulipProvider do
|
||||||
expect(stub1).to have_been_requested.once
|
expect(stub1).to have_been_requested.once
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".get_channel_by_name" do
|
||||||
|
it "returns the right channel" do
|
||||||
|
created =
|
||||||
|
DiscourseChatIntegration::Channel.create!(
|
||||||
|
provider: "zulip",
|
||||||
|
data: {
|
||||||
|
stream: "foo",
|
||||||
|
subject: "Discourse Notifications",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
channel = described_class.get_channel_by_name("foo")
|
||||||
|
expect(channel).to eq(created)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue