grape-slack-bot 1.6.11 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +20 -15
- data/grape-slack-bot.gemspec +19 -19
- data/lib/slack_bot/api_client.rb +34 -7
- data/lib/slack_bot/args.rb +7 -2
- data/lib/slack_bot/callback.rb +6 -6
- data/lib/slack_bot/command.rb +2 -2
- data/lib/slack_bot/config.rb +11 -10
- data/lib/slack_bot/dev_console.rb +4 -4
- data/lib/slack_bot/event.rb +4 -8
- data/lib/slack_bot/grape_extension.rb +87 -84
- data/lib/slack_bot/interaction.rb +7 -6
- data/lib/slack_bot/view.rb +5 -4
- data/lib/slack_bot.rb +17 -17
- metadata +47 -33
- data/spec/slack_bot/api_client_spec.rb +0 -479
- data/spec/slack_bot/args_spec.rb +0 -34
- data/spec/slack_bot/callback_spec.rb +0 -141
- data/spec/slack_bot/command_spec.rb +0 -5
- data/spec/slack_bot/config_spec.rb +0 -57
- data/spec/slack_bot/dev_console_spec.rb +0 -95
- data/spec/slack_bot/event_spec.rb +0 -74
- data/spec/slack_bot/grape_extension_spec.rb +0 -5
- data/spec/slack_bot/interaction_spec.rb +0 -5
- data/spec/slack_bot/logger_spec.rb +0 -13
- data/spec/slack_bot/menu_options_spec.rb +0 -5
- data/spec/slack_bot/pager_spec.rb +0 -51
- data/spec/slack_bot/view_spec.rb +0 -5
- data/spec/slack_bot_spec.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf068ba32d5e7319a9e8d96710dfa364fcccedf1e0755b32305409455293b7cc
|
4
|
+
data.tar.gz: 2c7bba45e4a549dcc1ac64b707349244b19dcbc6ef0a069504e192a350c4f10e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b362b4a0a379c2ff986fe11d554e1aaef10b3581190c7487833c2c69b503cc2f57d1e6b393e4afb19442176079bdc472a2717e57c8921d6dc0f51a92d64f0e9e
|
7
|
+
data.tar.gz: f150f3b05dda3a59d8b818bd574dfd5fcb08f688ad2eb6d263bba31bc821351f858a5bb1e05a3ee17199fe1d7dd0c4bab628127251314cbb6d1d7a809bc46bff
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# grape-slack-bot.rb
|
2
2
|
|
3
|
-
[](https://badge.fury.io/rb/grape-slack-bot) [](https://github.com/amkisko/grape-slack-bot.rb/actions/workflows/test.yml)
|
3
|
+
[](https://badge.fury.io/rb/grape-slack-bot) [](https://github.com/amkisko/grape-slack-bot.rb/actions/workflows/test.yml) [](https://codecov.io/gh/amkisko/grape-slack-bot.rb)
|
4
4
|
|
5
5
|
Extensible Slack bot implementation gem for [ruby-grape](https://github.com/ruby-grape/grape)
|
6
6
|
|
@@ -53,6 +53,7 @@ Interactive component is a component that is requested to be opened by bot app f
|
|
53
53
|
|
54
54
|
Characteristics:
|
55
55
|
- Can be associated with slash command
|
56
|
+
- Can be associated with event
|
56
57
|
|
57
58
|
References:
|
58
59
|
- [interaction.rb](lib/slack_bot/interaction.rb)
|
@@ -114,19 +115,19 @@ References:
|
|
114
115
|
|
115
116
|
## Specification
|
116
117
|
|
117
|
-
[x] Create any amount of endpoints that will handle Slack calls
|
118
|
-
[x] Create multiple instances of bots and configure them separately or use the same configuration for all bots
|
119
|
-
[x] Define and reuse slash command handlers for Slack slash commands
|
120
|
-
[x] Define interactive component handlers for Slack interactive components
|
121
|
-
[x] Define and reuse views for slash commands, interactive components and events
|
122
|
-
[x] Define event handlers for Slack events
|
123
|
-
[x] Define menu options handlers for Slack menu options
|
124
|
-
[x] Store interactive component state in cache for usage in other handlers
|
125
|
-
[x] Access current user session and user from any handler
|
126
|
-
[x] Extend API endpoint with custom hooks and helpers within [grape specification](https://github.com/ruby-grape/grape)
|
127
|
-
[x] Supports Slack signature verification
|
128
|
-
[ ] Supports Slack socket mode (?)
|
129
|
-
[ ] Supports Slack token rotation
|
118
|
+
- [x] Create any amount of endpoints that will handle Slack calls
|
119
|
+
- [x] Create multiple instances of bots and configure them separately or use the same configuration for all bots
|
120
|
+
- [x] Define and reuse slash command handlers for Slack slash commands
|
121
|
+
- [x] Define interactive component handlers for Slack interactive components
|
122
|
+
- [x] Define and reuse views for slash commands, interactive components and events
|
123
|
+
- [x] Define event handlers for Slack events
|
124
|
+
- [x] Define menu options handlers for Slack menu options
|
125
|
+
- [x] Store interactive component state in cache for usage in other handlers
|
126
|
+
- [x] Access current user session and user from any handler
|
127
|
+
- [x] Extend API endpoint with custom hooks and helpers within [grape specification](https://github.com/ruby-grape/grape)
|
128
|
+
- [x] Supports Slack signature verification
|
129
|
+
- [ ] Supports Slack socket mode (?)
|
130
|
+
- [ ] Supports Slack token rotation
|
130
131
|
|
131
132
|
## Usage with grape
|
132
133
|
|
@@ -520,10 +521,14 @@ Contribution policy:
|
|
520
521
|
|
521
522
|
## Publishing
|
522
523
|
|
524
|
+
Prefer using script `usr/bin/release.sh`, it will ensure that repository is synced and after publishing gem will create a tag.
|
525
|
+
|
523
526
|
```sh
|
527
|
+
GEM_VERSION=$(grep -Eo "VERSION\s*=\s*\".+\"" lib/slack_bot.rb | grep -Eo "[0-9.]{5,}")
|
524
528
|
rm grape-slack-bot-*.gem
|
525
529
|
gem build grape-slack-bot.gemspec
|
526
|
-
gem push grape-slack-bot
|
530
|
+
gem push grape-slack-bot-$GEM_VERSION.gem
|
531
|
+
git tag $GEM_VERSION && git push --tags
|
527
532
|
```
|
528
533
|
|
529
534
|
## License
|
data/grape-slack-bot.gemspec
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
1
|
Gem::Specification.new do |gem|
|
4
2
|
gem.name = "grape-slack-bot"
|
5
|
-
gem.version = File.read(File.expand_path(
|
3
|
+
gem.version = File.read(File.expand_path("../lib/slack_bot.rb", __FILE__)).match(/VERSION\s*=\s*"(.*?)"/)[1]
|
6
4
|
|
7
5
|
repository_url = "https://github.com/amkisko/grape-slack-bot.rb"
|
8
|
-
root_files = %w
|
6
|
+
root_files = %w[CHANGELOG.md LICENSE.md README.md]
|
9
7
|
root_files << "#{gem.name}.gemspec"
|
10
8
|
|
11
9
|
gem.license = "MIT"
|
@@ -15,7 +13,7 @@ Gem::Specification.new do |gem|
|
|
15
13
|
gem.authors = ["Andrei Makarov"]
|
16
14
|
gem.email = ["andrei@kiskolabs.com"]
|
17
15
|
gem.homepage = repository_url
|
18
|
-
gem.summary =
|
16
|
+
gem.summary = "Slack bot implementation for ruby-grape"
|
19
17
|
gem.description = gem.summary
|
20
18
|
gem.metadata = {
|
21
19
|
"homepage" => repository_url,
|
@@ -25,22 +23,24 @@ Gem::Specification.new do |gem|
|
|
25
23
|
"rubygems_mfa_required" => "true"
|
26
24
|
}
|
27
25
|
|
28
|
-
gem.executables = Dir.glob("bin/*").map{ |f| File.basename(f) }
|
26
|
+
gem.executables = Dir.glob("bin/*").map { |f| File.basename(f) }
|
29
27
|
gem.files = Dir.glob("lib/**/*.rb") + Dir.glob("bin/**/*") + root_files
|
30
|
-
gem.test_files = Dir.glob("spec/**/*_spec.rb")
|
31
28
|
|
32
|
-
gem.required_ruby_version = ">=
|
29
|
+
gem.required_ruby_version = ">= 3"
|
33
30
|
gem.require_paths = ["lib"]
|
34
31
|
|
35
|
-
gem.add_runtime_dependency
|
36
|
-
gem.add_runtime_dependency
|
37
|
-
gem.add_runtime_dependency
|
38
|
-
gem.add_runtime_dependency
|
39
|
-
|
40
|
-
gem.add_development_dependency
|
41
|
-
gem.add_development_dependency
|
42
|
-
gem.add_development_dependency
|
43
|
-
gem.add_development_dependency
|
44
|
-
gem.add_development_dependency
|
45
|
-
gem.add_development_dependency
|
32
|
+
gem.add_runtime_dependency "rack", "> 2"
|
33
|
+
gem.add_runtime_dependency "grape", "> 1"
|
34
|
+
gem.add_runtime_dependency "faraday", "> 1"
|
35
|
+
gem.add_runtime_dependency "activesupport", "> 5"
|
36
|
+
|
37
|
+
gem.add_development_dependency "bundler", "~> 2"
|
38
|
+
gem.add_development_dependency "pry", "~> 0.14"
|
39
|
+
gem.add_development_dependency "rspec", "~> 3"
|
40
|
+
gem.add_development_dependency "webmock", "~> 3"
|
41
|
+
gem.add_development_dependency "simplecov", "~> 0.21"
|
42
|
+
gem.add_development_dependency "simplecov-cobertura", "~> 2"
|
43
|
+
gem.add_development_dependency "standard", "~> 1"
|
44
|
+
gem.add_development_dependency "standard-performance", "~> 1"
|
45
|
+
gem.add_development_dependency "standard-rspec", "~> 0.2"
|
46
46
|
end
|
data/lib/slack_bot/api_client.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "faraday"
|
2
2
|
|
3
3
|
module SlackBot
|
4
4
|
class ApiResponse
|
@@ -20,6 +20,7 @@ module SlackBot
|
|
20
20
|
JSON.parse(response.body)
|
21
21
|
end
|
22
22
|
end
|
23
|
+
|
23
24
|
class ApiClient
|
24
25
|
attr_reader :client
|
25
26
|
def initialize(authorization_token: ENV["SLACK_BOT_API_TOKEN"])
|
@@ -37,27 +38,53 @@ module SlackBot
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def views_open(trigger_id:, view:)
|
40
|
-
ApiResponse.new { client.post("views.open", {
|
41
|
+
ApiResponse.new { client.post("views.open", {trigger_id: trigger_id, view: view}.to_json) }
|
41
42
|
end
|
42
43
|
|
43
44
|
def views_update(view_id:, view:)
|
44
|
-
ApiResponse.new { client.post("views.update", {
|
45
|
+
ApiResponse.new { client.post("views.update", {view_id: view_id, view: view}.to_json) }
|
45
46
|
end
|
46
47
|
|
47
48
|
def chat_post_message(channel:, text:, blocks:)
|
48
|
-
ApiResponse.new { client.post("chat.postMessage", {
|
49
|
+
ApiResponse.new { client.post("chat.postMessage", {channel: channel, text: text, blocks: blocks}.to_json) }
|
49
50
|
end
|
50
51
|
|
51
52
|
def chat_update(channel:, ts:, text:, blocks:)
|
52
|
-
ApiResponse.new { client.post("chat.update", {
|
53
|
+
ApiResponse.new { client.post("chat.update", {channel: channel, ts: ts, text: text, blocks: blocks}.to_json) }
|
53
54
|
end
|
54
55
|
|
55
56
|
def users_info(user_id:)
|
56
|
-
ApiResponse.new { client.post("users.info", {
|
57
|
+
ApiResponse.new { client.post("users.info", {user: user_id}.to_json) }
|
57
58
|
end
|
58
59
|
|
59
60
|
def views_publish(user_id:, view:)
|
60
|
-
ApiResponse.new { client.post("views.publish", {
|
61
|
+
ApiResponse.new { client.post("views.publish", {user_id: user_id, view: view}.to_json) }
|
62
|
+
end
|
63
|
+
|
64
|
+
def users_list(cursor: nil, limit: 200, include_locale: nil, team_id: nil)
|
65
|
+
args = {}
|
66
|
+
args[:cursor] = cursor if cursor
|
67
|
+
args[:limit] = limit if limit
|
68
|
+
args[:include_locale] = include_locale if include_locale
|
69
|
+
args[:team_id] = team_id if team_id
|
70
|
+
ApiResponse.new { client.post("users.list", args.to_json) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def chat_post_ephemeral(channel:, user:, text:, as_user: nil, attachments: nil, blocks: nil, icon_emoji: nil, icon_url: nil, link_names: nil, parse: nil, thread_ts: nil, username: nil)
|
74
|
+
args = {}
|
75
|
+
args[:channel] = channel
|
76
|
+
args[:user] = user
|
77
|
+
args[:text] = text if text
|
78
|
+
args[:as_user] = as_user if as_user
|
79
|
+
args[:attachments] = attachments if attachments
|
80
|
+
args[:blocks] = blocks if blocks
|
81
|
+
args[:icon_emoji] = icon_emoji if icon_emoji
|
82
|
+
args[:icon_url] = icon_url if icon_url
|
83
|
+
args[:link_names] = link_names if link_names
|
84
|
+
args[:parse] = parse if parse
|
85
|
+
args[:thread_ts] = thread_ts if thread_ts
|
86
|
+
args[:username] = username if username
|
87
|
+
ApiResponse.new { client.post("chat.postEphemeral", args.to_json) }
|
61
88
|
end
|
62
89
|
end
|
63
90
|
end
|
data/lib/slack_bot/args.rb
CHANGED
@@ -1,23 +1,28 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "rack/utils"
|
2
|
+
require "active_support"
|
3
|
+
require "active_support/core_ext/hash/indifferent_access"
|
3
4
|
|
4
5
|
module SlackBot
|
5
6
|
class ArgsParser
|
6
7
|
def initialize(args)
|
7
8
|
@args = args
|
8
9
|
end
|
10
|
+
|
9
11
|
def call
|
10
12
|
Rack::Utils.parse_query(@args)
|
11
13
|
end
|
12
14
|
end
|
15
|
+
|
13
16
|
class ArgsBuilder
|
14
17
|
def initialize(args)
|
15
18
|
@args = args
|
16
19
|
end
|
20
|
+
|
17
21
|
def call
|
18
22
|
Rack::Utils.build_query(@args)
|
19
23
|
end
|
20
24
|
end
|
25
|
+
|
21
26
|
class Args
|
22
27
|
attr_accessor :args
|
23
28
|
def initialize(builder: ArgsBuilder, parser: ArgsParser)
|
data/lib/slack_bot/callback.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "active_support/core_ext/object"
|
2
|
+
require "active_support/core_ext/numeric/time"
|
3
3
|
|
4
4
|
module SlackBot
|
5
5
|
class Callback
|
@@ -23,7 +23,7 @@ module SlackBot
|
|
23
23
|
find(callback_id, user: user, config: config)
|
24
24
|
end
|
25
25
|
|
26
|
-
def self.create(id: nil,
|
26
|
+
def self.create(class_name:, user:, id: nil, channel_id: nil, config: nil, payload: nil, expires_in: nil, user_scope: nil)
|
27
27
|
callback =
|
28
28
|
new(id: id, class_name: class_name, user: user, channel_id: channel_id, payload: payload, config: config, expires_in: expires_in, user_scope: user_scope)
|
29
29
|
callback.save
|
@@ -75,10 +75,10 @@ module SlackBot
|
|
75
75
|
return if id.blank?
|
76
76
|
return if data.blank?
|
77
77
|
|
78
|
-
if @data[:payload].is_a?(Hash)
|
79
|
-
@data[:payload]
|
78
|
+
@data[:payload] = if @data[:payload].is_a?(Hash)
|
79
|
+
@data[:payload].merge(payload)
|
80
80
|
else
|
81
|
-
|
81
|
+
payload
|
82
82
|
end
|
83
83
|
|
84
84
|
save
|
data/lib/slack_bot/command.rb
CHANGED
data/lib/slack_bot/config.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
|
-
require
|
1
|
+
require "active_support"
|
2
|
+
require "active_support/core_ext/object"
|
2
3
|
|
3
4
|
module SlackBot
|
4
5
|
class Config
|
5
6
|
def self.current_instance
|
6
7
|
@@current_instances ||= {}
|
7
|
-
@@current_instances[
|
8
|
+
@@current_instances[name] ||= new
|
8
9
|
end
|
9
10
|
|
10
|
-
def self.configure(&
|
11
|
-
current_instance.instance_eval(&
|
11
|
+
def self.configure(&)
|
12
|
+
current_instance.instance_eval(&)
|
12
13
|
end
|
13
14
|
|
14
15
|
attr_reader :callback_storage_instance
|
@@ -40,7 +41,7 @@ module SlackBot
|
|
40
41
|
event_handlers[event_type.to_sym]
|
41
42
|
end
|
42
43
|
|
43
|
-
def slash_command_endpoint(url_token, command_klass = nil, handler_name: nil, &
|
44
|
+
def slash_command_endpoint(url_token, command_klass = nil, handler_name: nil, &)
|
44
45
|
@slash_command_endpoints ||= {}
|
45
46
|
@slash_command_endpoints[url_token.to_sym] ||=
|
46
47
|
begin
|
@@ -51,7 +52,7 @@ module SlackBot
|
|
51
52
|
config: self,
|
52
53
|
handler_name: handler_name
|
53
54
|
)
|
54
|
-
endpoint.instance_eval(&
|
55
|
+
endpoint.instance_eval(&) if block
|
55
56
|
endpoint
|
56
57
|
end
|
57
58
|
end
|
@@ -104,7 +105,7 @@ module SlackBot
|
|
104
105
|
end
|
105
106
|
end
|
106
107
|
|
107
|
-
def command(command_token, command_klass, handler_name: nil, &
|
108
|
+
def command(command_token, command_klass, handler_name: nil, &)
|
108
109
|
@command_configs ||= {}
|
109
110
|
@command_configs[command_token.to_sym] ||=
|
110
111
|
begin
|
@@ -115,7 +116,7 @@ module SlackBot
|
|
115
116
|
endpoint: self,
|
116
117
|
handler_name: handler_name
|
117
118
|
)
|
118
|
-
command.instance_eval(&
|
119
|
+
command.instance_eval(&) if block
|
119
120
|
command
|
120
121
|
end
|
121
122
|
end
|
@@ -154,7 +155,7 @@ module SlackBot
|
|
154
155
|
endpoint.config.handler_class(handler_name, command_klass)
|
155
156
|
end
|
156
157
|
|
157
|
-
def argument_command(argument_token, klass = nil, &
|
158
|
+
def argument_command(argument_token, klass = nil, &)
|
158
159
|
@argument_command_configs ||= {}
|
159
160
|
@argument_command_configs[argument_token.to_sym] ||=
|
160
161
|
SlashCommandConfig.new(
|
@@ -165,7 +166,7 @@ module SlackBot
|
|
165
166
|
)
|
166
167
|
|
167
168
|
command_config = @argument_command_configs[argument_token.to_sym]
|
168
|
-
command_config.instance_eval(&
|
169
|
+
command_config.instance_eval(&) if block
|
169
170
|
|
170
171
|
command_config
|
171
172
|
end
|
@@ -19,22 +19,22 @@ module SlackBot
|
|
19
19
|
def self.log(message = nil, &block)
|
20
20
|
return unless enabled?
|
21
21
|
|
22
|
-
message = yield if
|
22
|
+
message = yield if block
|
23
23
|
logger.info(message)
|
24
24
|
end
|
25
25
|
|
26
26
|
def self.log_input(message = nil, &block)
|
27
|
-
message = yield if
|
27
|
+
message = yield if block
|
28
28
|
log(">>> #{message}")
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.log_output(message = nil, &block)
|
32
|
-
message = yield if
|
32
|
+
message = yield if block
|
33
33
|
log("<<< #{message}")
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.log_check(message = nil, &block)
|
37
|
-
message = yield if
|
37
|
+
message = yield if block
|
38
38
|
log("!!! #{message}")
|
39
39
|
end
|
40
40
|
end
|
data/lib/slack_bot/event.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "slack_bot/concerns/interaction_klass"
|
2
|
+
require "slack_bot/concerns/view_klass"
|
3
3
|
|
4
4
|
module SlackBot
|
5
5
|
class Event
|
@@ -20,13 +20,9 @@ module SlackBot
|
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
|
-
|
24
|
-
@callback = callback
|
25
|
-
end
|
23
|
+
attr_writer :callback
|
26
24
|
|
27
|
-
|
28
|
-
@metadata = metadata
|
29
|
-
end
|
25
|
+
attr_writer :metadata
|
30
26
|
|
31
27
|
def event_type
|
32
28
|
params["event"]["type"]
|
@@ -1,104 +1,107 @@
|
|
1
|
-
require
|
1
|
+
require "active_support"
|
2
|
+
require "active_support/core_ext/object"
|
2
3
|
|
3
4
|
module SlackBot
|
4
|
-
module
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
base.use ActionDispatch::RemoteIp
|
9
|
-
base.helpers do
|
10
|
-
def fetch_team_id
|
11
|
-
params.dig("team_id") || params.dig("team", "id")
|
12
|
-
end
|
5
|
+
module GrapeHelpers
|
6
|
+
def fetch_team_id
|
7
|
+
params.dig("team_id") || params.dig("team", "id")
|
8
|
+
end
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
def fetch_user_id
|
11
|
+
params.dig("user_id") || params.dig("user", "id") || params.dig("event", "user")
|
12
|
+
end
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
14
|
+
def verify_slack_signature!
|
15
|
+
slack_signing_secret = ENV.fetch("SLACK_SIGNING_SECRET")
|
16
|
+
timestamp = request.headers.fetch("x-slack-request-timestamp")
|
17
|
+
request_body = request.body.read
|
18
|
+
sig_basestring = "v0:#{timestamp}:#{request_body}"
|
19
|
+
my_signature =
|
20
|
+
"v0=" +
|
21
|
+
OpenSSL::HMAC.hexdigest(
|
22
|
+
OpenSSL::Digest.new("sha256"),
|
23
|
+
slack_signing_secret,
|
24
|
+
sig_basestring
|
25
|
+
)
|
26
|
+
slack_signature = request.headers.fetch("x-slack-signature")
|
27
|
+
if ActiveSupport::SecurityUtils.secure_compare(
|
28
|
+
my_signature,
|
29
|
+
slack_signature
|
30
|
+
)
|
31
|
+
true
|
32
|
+
else
|
33
|
+
raise SlackBot::Errors::SignatureAuthenticationError.new("Signature mismatch")
|
34
|
+
end
|
35
|
+
end
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
37
|
+
def verify_slack_team!
|
38
|
+
slack_team_id = ENV.fetch("SLACK_TEAM_ID")
|
39
|
+
if slack_team_id == fetch_team_id
|
40
|
+
true
|
41
|
+
else
|
42
|
+
raise SlackBot::Errors::TeamAuthenticationError.new("Team is not authorized")
|
43
|
+
end
|
44
|
+
end
|
49
45
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
46
|
+
def verify_direct_message_channel!
|
47
|
+
if params[:channel_name] == "directmessage"
|
48
|
+
true
|
49
|
+
else
|
50
|
+
raise SlackBot::Errors::ChannelAuthenticationError.new(
|
51
|
+
"This command is only available in direct messages"
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
59
55
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
56
|
+
def verify_current_user!
|
57
|
+
if current_user
|
58
|
+
true
|
59
|
+
else
|
60
|
+
raise SlackBot::Errors::UserAuthenticationError.new("User is not authorized")
|
61
|
+
end
|
62
|
+
end
|
67
63
|
|
68
|
-
|
69
|
-
|
64
|
+
def events_callback(params)
|
65
|
+
verify_slack_team!
|
70
66
|
|
71
|
-
|
72
|
-
|
73
|
-
|
67
|
+
SlackBot::DevConsole.log_input "SlackApi::Events#events_callback: #{params.inspect}"
|
68
|
+
handler = config.find_event_handler(params[:event][:type].to_sym)
|
69
|
+
return if handler.blank?
|
74
70
|
|
75
|
-
|
76
|
-
|
77
|
-
|
71
|
+
event = handler.new(params: params, current_user: current_user)
|
72
|
+
event.call
|
73
|
+
end
|
78
74
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
75
|
+
def url_verification(params)
|
76
|
+
SlackBot::DevConsole.log_input "SlackApi::Events#url_verification: #{params.inspect}"
|
77
|
+
{challenge: params[:challenge]}
|
78
|
+
end
|
83
79
|
|
84
|
-
|
85
|
-
|
80
|
+
def handle_block_actions_view(view:, user:, params:)
|
81
|
+
callback_id = view&.dig("callback_id")
|
86
82
|
|
87
|
-
|
88
|
-
|
83
|
+
callback = SlackBot::Callback.find(callback_id, user: user, config: config)
|
84
|
+
raise SlackBot::Errors::CallbackNotFound.new if callback.blank?
|
89
85
|
|
90
|
-
|
86
|
+
SlackBot::DevConsole.log_check "SlackApi::Interactions##{__method__}: #{callback.id} #{callback.payload} #{callback.user_id} #{user&.id}"
|
91
87
|
|
92
|
-
|
93
|
-
|
94
|
-
|
88
|
+
if callback.user_id != user.id
|
89
|
+
raise "Callback user is not equal to action user"
|
90
|
+
end
|
95
91
|
|
96
|
-
|
97
|
-
|
92
|
+
interaction_klass = callback.handler_class&.interaction_klass
|
93
|
+
return if interaction_klass.blank?
|
98
94
|
|
99
|
-
|
100
|
-
|
101
|
-
|
95
|
+
interaction_klass.new(current_user: user, params: params, callback: callback, config: config).call
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
module GrapeExtension
|
100
|
+
def self.included(base)
|
101
|
+
base.format :json
|
102
|
+
base.content_type :json, "application/json"
|
103
|
+
base.use ActionDispatch::RemoteIp
|
104
|
+
base.helpers SlackBot::GrapeHelpers
|
102
105
|
|
103
106
|
base.before do
|
104
107
|
verify_slack_signature!
|
@@ -1,6 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require "active_support"
|
2
|
+
require "active_support/core_ext/object"
|
2
3
|
|
3
|
-
require
|
4
|
+
require "slack_bot/concerns/view_klass"
|
4
5
|
|
5
6
|
module SlackBot
|
6
7
|
class Interaction
|
@@ -9,7 +10,7 @@ module SlackBot
|
|
9
10
|
include SlackBot::Concerns::ViewKlass
|
10
11
|
|
11
12
|
def self.open_modal(callback:, trigger_id:, view:)
|
12
|
-
view = view.merge({
|
13
|
+
view = view.merge({type: "modal", callback_id: callback&.id})
|
13
14
|
response =
|
14
15
|
SlackBot::ApiClient.new.views_open(trigger_id: trigger_id, view: view)
|
15
16
|
|
@@ -26,7 +27,7 @@ module SlackBot
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def self.update_modal(callback:, view_id:, view:)
|
29
|
-
view = view.merge({
|
30
|
+
view = view.merge({type: "modal", callback_id: callback&.id})
|
30
31
|
response =
|
31
32
|
SlackBot::ApiClient.new.views_update(view_id: view_id, view: view)
|
32
33
|
|
@@ -42,7 +43,7 @@ module SlackBot
|
|
42
43
|
SlackViewsReply.new(callback&.id, view_id)
|
43
44
|
end
|
44
45
|
|
45
|
-
def self.publish_view(callback: nil, metadata: nil
|
46
|
+
def self.publish_view(user_id:, view:, callback: nil, metadata: nil)
|
46
47
|
view = view.merge(callback_id: callback.id) if callback.present?
|
47
48
|
view = view.merge(private_metadata: metadata) if metadata.present?
|
48
49
|
response =
|
@@ -138,7 +139,7 @@ module SlackBot
|
|
138
139
|
return if callback.blank?
|
139
140
|
return if actions.blank?
|
140
141
|
|
141
|
-
if
|
142
|
+
if block
|
142
143
|
actions.each { |action| instance_exec(action, &block) }
|
143
144
|
else
|
144
145
|
callback.args.raw_args = actions.first["value"]
|