mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-02-22 04:30:33 +09:00
80 lines
2.7 KiB
Ruby
80 lines
2.7 KiB
Ruby
require "net/http"
|
|
require "uri"
|
|
|
|
class Webhook < ApplicationRecord
|
|
ENDPOINT_TIMEOUT = 7.seconds
|
|
|
|
belongs_to :user
|
|
|
|
def deliver(message)
|
|
post(payload(message)).tap do |response|
|
|
if text = extract_text_from(response)
|
|
receive_text_reply_to(message.room, text: text)
|
|
elsif attachment = extract_attachment_from(response)
|
|
receive_attachment_reply_to(message.room, attachment: attachment)
|
|
end
|
|
end
|
|
rescue Net::OpenTimeout, Net::ReadTimeout
|
|
receive_text_reply_to message.room, text: "Failed to respond within #{ENDPOINT_TIMEOUT} seconds"
|
|
end
|
|
|
|
private
|
|
def post(payload)
|
|
http.request \
|
|
Net::HTTP::Post.new(uri, "Content-Type" => "application/json").tap { |request| request.body = payload }
|
|
end
|
|
|
|
def http
|
|
Net::HTTP.new(uri.host, uri.port).tap do |http|
|
|
http.use_ssl = (uri.scheme == "https")
|
|
http.open_timeout = ENDPOINT_TIMEOUT
|
|
http.read_timeout = ENDPOINT_TIMEOUT
|
|
end
|
|
end
|
|
|
|
def uri
|
|
@uri ||= URI(url)
|
|
end
|
|
|
|
def payload(message)
|
|
{
|
|
user: { id: message.creator.id, name: message.creator.name },
|
|
room: { id: message.room.id, name: message.room.name, path: room_bot_messages_path(message) },
|
|
message: { id: message.id, body: { html: message.body.body, plain: without_recipient_mentions(message.plain_text_body) }, path: message_path(message) }
|
|
}.to_json
|
|
end
|
|
|
|
def message_path(message)
|
|
Rails.application.routes.url_helpers.room_at_message_path(message.room, message)
|
|
end
|
|
|
|
def room_bot_messages_path(message)
|
|
Rails.application.routes.url_helpers.room_bot_messages_path(message.room, user.bot_key)
|
|
end
|
|
|
|
def extract_text_from(response)
|
|
String.new(response.body).force_encoding("UTF-8") if response.code == "200" && response.content_type.in?(%w[ text/html text/plain ])
|
|
end
|
|
|
|
def receive_text_reply_to(room, text:)
|
|
room.messages.create!(body: text, creator: user).broadcast_create
|
|
end
|
|
|
|
def extract_attachment_from(response)
|
|
if response.content_type && mime_type = Mime::Type.lookup(response.content_type)
|
|
ActiveStorage::Blob.create_and_upload! \
|
|
io: StringIO.new(response.body), filename: "attachment.#{mime_type.symbol}", content_type: mime_type.to_s
|
|
end
|
|
end
|
|
|
|
def receive_attachment_reply_to(room, attachment:)
|
|
room.messages.create_with_attachment!(attachment: attachment, creator: user).broadcast_create
|
|
end
|
|
|
|
def without_recipient_mentions(body)
|
|
body \
|
|
.gsub(user.attachable_plain_text_representation(nil), "") # Remove mentions of the recipient user
|
|
.gsub(/\A\p{Space}+|\p{Space}+\z/, "") # Remove leading and trailing whitespace uncluding unicode spaces
|
|
end
|
|
end
|