mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 04:02:30 +08:00
## What changed Adds `chat_integration_telegram_api_base_url` setting for the Telegram chat integration (discourse-chat-integration plugin) The setting defaults to `https://api.telegram.org`, so existing installations keep their current behavior. ## Why Some Discourse installations cannot reach `api.telegram.org` directly because Telegram is blocked or restricted by local network providers. This setting allows administrators to route Telegram Bot API requests through a trusted reverse proxy, such as a Cloudflare Worker, without patching the plugin. ## Cloudflare Worker example The following Worker can be deployed as a small Telegram Bot API proxy: ```js export default { async fetch(request) { const url = new URL(request.url); if ( !url.pathname.startsWith("/bot") && !url.pathname.startsWith("/file/bot") ) { return new Response("Not found", { status: 404 }); } url.hostname = "api.telegram.org"; url.protocol = "https:"; url.port = ""; return fetch(new Request(url, request)); }, }; ``` The proxy must be trusted because Telegram bot tokens are included in Bot API request paths. --------- Co-authored-by: Régis Hanol <regis@hanol.fr>
137 lines
4.7 KiB
Ruby
Vendored
137 lines
4.7 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
# name: discourse-chat-integration
|
|
# about: Allows integration with several external chat system providers
|
|
# meta_topic_id: 66522
|
|
# version: 0.1
|
|
# author: David Taylor
|
|
# url: https://github.com/discourse/discourse/tree/main/plugins/discourse-chat-integration
|
|
|
|
enabled_site_setting :chat_integration_enabled
|
|
|
|
register_asset "stylesheets/chat-integration.scss"
|
|
|
|
register_svg_icon "rocket"
|
|
register_svg_icon "arrow-circle-o-right"
|
|
|
|
module ::DiscourseChatIntegration
|
|
PLUGIN_NAME = "discourse-chat-integration"
|
|
end
|
|
|
|
# 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/telegram/telegram_api_base_url_setting_validator"
|
|
require_relative "lib/discourse_chat_integration/chat_integration_reference_post"
|
|
|
|
after_initialize do
|
|
require_relative "app/initializers/discourse_chat_integration"
|
|
|
|
require_relative "app/services/problem_check/channel_errors"
|
|
|
|
register_problem_check ProblemCheck::ChannelErrors
|
|
|
|
on(:post_created) do |post|
|
|
# This will run for every post, even PMs. Don't worry, they're filtered out later.
|
|
Jobs.enqueue_in(
|
|
SiteSetting.chat_integration_delay_seconds.seconds,
|
|
:notify_chats,
|
|
post_id: post.id,
|
|
)
|
|
end
|
|
|
|
add_admin_route "chat_integration.menu_title",
|
|
"discourse-chat-integration",
|
|
use_new_show_route: true
|
|
|
|
DiscourseChatIntegration::Provider.mount_engines
|
|
|
|
if defined?(DiscourseAutomation)
|
|
add_automation_scriptable("send_slack_message") do
|
|
field :message, component: :message, required: true, accepts_placeholders: true
|
|
field :url, component: :text, required: true
|
|
field :channel, component: :text, required: true
|
|
|
|
version 1
|
|
|
|
triggerables %i[point_in_time recurring topic_tags_changed]
|
|
|
|
script do |context, fields, automation|
|
|
channel_name = fields.dig("channel", "value")
|
|
channel =
|
|
DiscourseChatIntegration::Channel.new(
|
|
provider: "slack",
|
|
data: {
|
|
identifier: "##{channel_name}",
|
|
},
|
|
)
|
|
|
|
begin
|
|
message =
|
|
DiscourseChatIntegration::Provider::SlackProvider.create_slack_message(
|
|
context: context,
|
|
content: fields.dig("message", "value"),
|
|
url: fields.dig("url", "value"),
|
|
channel_name: channel_name,
|
|
)
|
|
DiscourseChatIntegration::Provider::SlackProvider.send_via_api(nil, channel, message)
|
|
rescue StandardError => _
|
|
# StandardError here is when there are no tags but content includes reference to them.
|
|
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|
|
|
# DiscourseTagging.tag_topic_by_names runs on topic creation and on tags change
|
|
# we only want to send a message when tags change
|
|
next if context["topic"].new_record?
|
|
|
|
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)
|
|
|
|
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 => e
|
|
Rails.logger.warn "[discourse-automation] Error while sending chat integration message. Automation ID: #{automation.id}"
|
|
Rails.logger.warn "[discourse-chat-integration] Error: #{e.inspect}"
|
|
Rails.logger.warn "[discourse-chat-integration] Channel: #{channel_name}"
|
|
Rails.logger.warn "[discourse-chat-integration] Reference post: #{post.inspect}"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|