Files
once-campfire/app/models/webhook.rb
Stanko Krtalić eecdb29332 Upgrade to Rails 8 and Ruby 3.4.5 (#1)
* Bump Ruby to 3.4.5
* Update dependencies
* Adjust for Rails 8 and Ruby 3.5 API changes
* Mark params strings as mutable in prepapration for frozen strings in Ruby 3.5
* Update test for HTML5 sanitizer
    With Rails 7.1 the HTML5 sanitizer became the default, this breakts this test because the old sanitizer used to delete unpermitted nodes, while the new one returns their content
    The final string is safe, but different then it used to be in Rails 7.0
* Remove direct Turbo tesh helpers require & parallelize tests
* Fix Zeitwerk issues with rails extensions
* Update Resque setup for Redis 5+
* Remove unused views
* Remove GID v1 handler
2025-09-02 17:02:41 +02:00

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)
response.body.dup.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