Class: ChatSDK::Slack::Adapter
- Inherits:
-
Adapter::Base
- Object
- Adapter::Base
- ChatSDK::Slack::Adapter
- Defined in:
- lib/chat_sdk/slack/adapter.rb
Instance Attribute Summary collapse
-
#client ⇒ Object
readonly
Returns the value of attribute client.
Instance Method Summary collapse
- #ack_response(rack_request) ⇒ Object
- #add_reaction(channel_id:, message_id:, emoji:) ⇒ Object
- #delete_message(channel_id:, message_id:) ⇒ Object
- #edit_message(channel_id:, message_id:, message:) ⇒ Object
- #fetch_messages(channel_id:, thread_id: nil, cursor: nil, limit: 50) ⇒ Object
-
#initialize(bot_token: nil, signing_secret: nil) ⇒ Adapter
constructor
A new instance of Adapter.
- #mention(user_id) ⇒ Object
- #name ⇒ Object
- #open_dm(user_id) ⇒ Object
- #open_modal(trigger_id:, modal:) ⇒ Object
- #parse_events(rack_request) ⇒ Object
- #post_ephemeral(channel_id:, user_id:, message:, thread_id: nil) ⇒ Object
-
#post_message(channel_id:, message:, thread_id: nil) ⇒ Object
Outbound.
- #remove_reaction(channel_id:, message_id:, emoji:) ⇒ Object
- #render(postable_message) ⇒ Object
- #start_typing(channel_id:, thread_id: nil) ⇒ Object
- #upload_file(channel_id:, io:, filename:, thread_id: nil, comment: nil) ⇒ Object
-
#verify_request!(rack_request) ⇒ Object
Inbound.
Constructor Details
#initialize(bot_token: nil, signing_secret: nil) ⇒ Adapter
Returns a new instance of Adapter.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/chat_sdk/slack/adapter.rb', line 12 def initialize(bot_token: nil, signing_secret: nil) @bot_token = bot_token || ENV["SLACK_BOT_TOKEN"] @signing_secret = signing_secret || ENV["SLACK_SIGNING_SECRET"] raise ChatSDK::ConfigurationError, "Slack bot_token required" unless @bot_token raise ChatSDK::ConfigurationError, "Slack signing_secret required" unless @signing_secret ::Slack.configure do |config| config.token = @bot_token end @client = ::Slack::Web::Client.new(token: @bot_token) @renderer = BlockKitRenderer.new @modal_renderer = ModalRenderer.new end |
Instance Attribute Details
#client ⇒ Object (readonly)
Returns the value of attribute client.
10 11 12 |
# File 'lib/chat_sdk/slack/adapter.rb', line 10 def client @client end |
Instance Method Details
#ack_response(rack_request) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/chat_sdk/slack/adapter.rb', line 57 def ack_response(rack_request) body = rack_request.body.read rack_request.body.rewind parsed = parse_body(body, rack_request.content_type) return nil unless parsed if parsed["type"] == "url_verification" [200, {"content-type" => "text/plain"}, [parsed["challenge"]]] end end |
#add_reaction(channel_id:, message_id:, emoji:) ⇒ Object
130 131 132 |
# File 'lib/chat_sdk/slack/adapter.rb', line 130 def add_reaction(channel_id:, message_id:, emoji:) @client.reactions_add(channel: channel_id, timestamp: , name: emoji) end |
#delete_message(channel_id:, message_id:) ⇒ Object
109 110 111 |
# File 'lib/chat_sdk/slack/adapter.rb', line 109 def (channel_id:, message_id:) @client.chat_delete(channel: channel_id, ts: ) end |
#edit_message(channel_id:, message_id:, message:) ⇒ Object
100 101 102 103 104 105 106 107 |
# File 'lib/chat_sdk/slack/adapter.rb', line 100 def (channel_id:, message_id:, message:) msg = ChatSDK::PostableMessage.from() params = {channel: channel_id, ts: } (params, msg) @client.chat_update(**params) end |
#fetch_messages(channel_id:, thread_id: nil, cursor: nil, limit: 50) ⇒ Object
143 144 145 146 147 148 149 150 151 |
# File 'lib/chat_sdk/slack/adapter.rb', line 143 def (channel_id:, thread_id: nil, cursor: nil, limit: 50) result = if thread_id @client.conversations_replies(channel: channel_id, ts: thread_id, cursor: cursor, limit: limit) else @client.conversations_history(channel: channel_id, cursor: cursor, limit: limit) end = result["messages"].map { |m| (m, channel_id) } [, result["response_metadata"]&.dig("next_cursor")] end |
#mention(user_id) ⇒ Object
163 164 165 |
# File 'lib/chat_sdk/slack/adapter.rb', line 163 def mention(user_id) "<@#{user_id}>" end |
#name ⇒ Object
28 29 30 |
# File 'lib/chat_sdk/slack/adapter.rb', line 28 def name :slack end |
#open_dm(user_id) ⇒ Object
138 139 140 141 |
# File 'lib/chat_sdk/slack/adapter.rb', line 138 def open_dm(user_id) result = @client.conversations_open(users: user_id) result["channel"]["id"] end |
#open_modal(trigger_id:, modal:) ⇒ Object
153 154 155 156 |
# File 'lib/chat_sdk/slack/adapter.rb', line 153 def open_modal(trigger_id:, modal:) view = @modal_renderer.render(modal) @client.views_open(trigger_id: trigger_id, view: view) end |
#parse_events(rack_request) ⇒ Object
69 70 71 72 73 74 75 76 77 |
# File 'lib/chat_sdk/slack/adapter.rb', line 69 def parse_events(rack_request) body = rack_request.body.read rack_request.body.rewind parsed = parse_body(body, rack_request.content_type) return [] unless parsed EventParser.parse(parsed) end |
#post_ephemeral(channel_id:, user_id:, message:, thread_id: nil) ⇒ Object
113 114 115 116 117 118 119 120 121 |
# File 'lib/chat_sdk/slack/adapter.rb', line 113 def post_ephemeral(channel_id:, user_id:, message:, thread_id: nil) msg = ChatSDK::PostableMessage.from() params = {channel: channel_id, user: user_id} params[:thread_ts] = thread_id if thread_id (params, msg) @client.chat_postEphemeral(**params) end |
#post_message(channel_id:, message:, thread_id: nil) ⇒ Object
Outbound
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/chat_sdk/slack/adapter.rb', line 80 def (channel_id:, message:, thread_id: nil) msg = ChatSDK::PostableMessage.from() params = {channel: channel_id} params[:thread_ts] = thread_id if thread_id (params, msg) result = @client.chat_postMessage(**params) ChatSDK::Message.new( id: result["ts"], text: msg.text || "", author: ChatSDK::Author.new(id: "bot", name: "bot", platform: :slack, bot: true), thread_id: thread_id || result["ts"], channel_id: channel_id, platform: :slack, raw: result ) end |
#remove_reaction(channel_id:, message_id:, emoji:) ⇒ Object
134 135 136 |
# File 'lib/chat_sdk/slack/adapter.rb', line 134 def remove_reaction(channel_id:, message_id:, emoji:) @client.reactions_remove(channel: channel_id, timestamp: , name: emoji) end |
#render(postable_message) ⇒ Object
167 168 169 170 171 172 173 |
# File 'lib/chat_sdk/slack/adapter.rb', line 167 def render() if .card? @renderer.render(.card) else .text end end |
#start_typing(channel_id:, thread_id: nil) ⇒ Object
158 159 160 161 |
# File 'lib/chat_sdk/slack/adapter.rb', line 158 def start_typing(channel_id:, thread_id: nil) # Slack doesn't have a native typing indicator API for bots # This is a no-op but the capability is declared for streaming support end |
#upload_file(channel_id:, io:, filename:, thread_id: nil, comment: nil) ⇒ Object
123 124 125 126 127 128 |
# File 'lib/chat_sdk/slack/adapter.rb', line 123 def upload_file(channel_id:, io:, filename:, thread_id: nil, comment: nil) params = {channels: channel_id, file: Faraday::Multipart::FilePart.new(io, nil, filename)} params[:thread_ts] = thread_id if thread_id params[:initial_comment] = comment if comment @client.files_upload(**params) end |
#verify_request!(rack_request) ⇒ Object
Inbound
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/chat_sdk/slack/adapter.rb', line 33 def verify_request!(rack_request) body = rack_request.body.read rack_request.body.rewind = rack_request.env["HTTP_X_SLACK_REQUEST_TIMESTAMP"] signature = rack_request.env["HTTP_X_SLACK_SIGNATURE"] raise ChatSDK::SignatureVerificationError, "Missing Slack signature headers" unless && signature sig_basestring = "v0:#{}:#{body}" hex_digest = OpenSSL::HMAC.hexdigest("SHA256", @signing_secret, sig_basestring) computed = "v0=#{hex_digest}" unless Rack::Utils.secure_compare(computed, signature) raise ChatSDK::SignatureVerificationError, "Invalid Slack signature" end age = Time.now.to_i - .to_i if age.abs > 300 raise ChatSDK::SignatureVerificationError, "Slack request too old (#{age}s)" end true end |