slack_message 3.0.2 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/slack_message/api.rb +12 -9
- data/lib/slack_message/dsl.rb +4 -0
- data/lib/slack_message/error_handling.rb +29 -11
- data/lib/slack_message/rspec.rb +25 -23
- data/slack_message.gemspec +1 -1
- data/spec/slack_message_spec.rb +79 -29
- data/spec/spec_helper.rb +5 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b35e974e04457e2d9e3b55af0c5c7562d0381c76477e9a85143c66e8d605071
|
4
|
+
data.tar.gz: 21892df8e52b365ade154424d2c98a55434efb541e144d046d208fe8b1243f24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 720e5bcf8d91f355939474b09f9d2a9830178037dca5c067ecfc4c6585631673e2ea13d888338ff1fb7a3d25ae1009b5f1a97f7a8244f1f06696b437227f6260
|
7
|
+
data.tar.gz: b7fa2c16e3d5a31ac18605bda1e1eacdd367c6e94f34779c50964a92c679b8edcdc1168d3fa808392401669f55bbeae30aec607ec44a2cfd55b916d0ad0fe70d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.3.0] - 2022-07-21
|
4
|
+
- Differentiate errors for bad JSON versus invalid block data.
|
5
|
+
- Expand tests to cover many more cases.
|
6
|
+
- Add validation for block size limit in Slack API.
|
7
|
+
- Add CI check to prevent checkin of `fit`, `fcontext` etc.
|
8
|
+
|
9
|
+
## [3.2.0] - 2022-06-23
|
10
|
+
- Fix bugs introduced by accidental checkin of incomplete refactor.
|
11
|
+
|
12
|
+
## [3.1.0] - 2022-04-18
|
13
|
+
- Methods from the calling context can now be called within a section block.
|
14
|
+
|
3
15
|
## [3.0.2] - 2022-04-16
|
4
16
|
- Fix tests on ruby 3.0.
|
5
17
|
- More adjustments and additions to docs.
|
data/lib/slack_message/api.rb
CHANGED
@@ -22,13 +22,10 @@ module SlackMessage::Api
|
|
22
22
|
raise SlackMessage::ApiError, "Received empty 200 response from Slack when looking up user info. Check your API key."
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
raise SlackMessage::ApiError, "Unable to parse JSON response from Slack API\n#{response.body}"
|
29
|
-
end
|
25
|
+
SlackMessage::ErrorHandling.raise_user_lookup_response_errors(response, email, profile)
|
26
|
+
|
27
|
+
payload = JSON.parse(response.body)
|
30
28
|
|
31
|
-
SlackMessage::ErrorHandling.raise_user_lookup_errors(response, target, profile)
|
32
29
|
payload["user"]["id"]
|
33
30
|
end
|
34
31
|
|
@@ -44,6 +41,10 @@ module SlackMessage::Api
|
|
44
41
|
raise ArgumentError, "Tried to send an entirely empty message."
|
45
42
|
end
|
46
43
|
|
44
|
+
if params[:blocks].length > 50
|
45
|
+
raise ArgumentError, "Message cannot contain more than 50 blocks."
|
46
|
+
end
|
47
|
+
|
47
48
|
icon = payload.custom_bot_icon || profile[:icon]
|
48
49
|
if icon =~ /^:\w+:$/
|
49
50
|
params[:icon_emoji] = icon
|
@@ -83,15 +84,17 @@ module SlackMessage::Api
|
|
83
84
|
raise ArgumentError, "Tried to send an entirely empty message."
|
84
85
|
end
|
85
86
|
|
87
|
+
if params[:blocks].length > 50
|
88
|
+
raise ArgumentError, "Message cannot contain more than 50 blocks."
|
89
|
+
end
|
90
|
+
|
86
91
|
if SlackMessage::Configuration.debugging?
|
87
92
|
warn params.inspect
|
88
93
|
end
|
89
94
|
|
90
95
|
response = update_message(profile, params)
|
91
|
-
body = JSON.parse(response.body)
|
92
|
-
error = body.fetch("error", "")
|
93
96
|
|
94
|
-
SlackMessage::ErrorHandling.
|
97
|
+
SlackMessage::ErrorHandling.raise_update_response_errors(response, params, profile)
|
95
98
|
SlackMessage::Response.new(response, profile[:handle])
|
96
99
|
end
|
97
100
|
|
data/lib/slack_message/dsl.rb
CHANGED
@@ -7,8 +7,10 @@ class SlackMessage::ErrorHandling
|
|
7
7
|
body = JSON.parse(response.body)
|
8
8
|
error = body.fetch("error", "")
|
9
9
|
|
10
|
-
if
|
11
|
-
raise SlackMessage::ApiError, "Couldn't send Slack message because the
|
10
|
+
if error == "invalid_blocks"
|
11
|
+
raise SlackMessage::ApiError, "Couldn't send Slack message because the request contained invalid blocks:\n#{blocks_message(params[:blocks])}"
|
12
|
+
elsif error == "invalid_blocks_format"
|
13
|
+
raise SlackMessage::ApiError, "Couldn't send Slack message because blocks is not a valid JSON object or doesn't match the Block Kit syntax:\n#{blocks_message(params[:blocks])}"
|
12
14
|
elsif error == "channel_not_found"
|
13
15
|
raise SlackMessage::ApiError, "Tried to send Slack message to non-existent channel or user '#{params[:channel]}'"
|
14
16
|
|
@@ -34,21 +36,23 @@ class SlackMessage::ErrorHandling
|
|
34
36
|
elsif response.code != "200"
|
35
37
|
raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
|
36
38
|
elsif !(error.nil? || error == "")
|
37
|
-
raise SlackMessage::ApiError, "Received error response from Slack during message posting:\n#{response.body}"
|
39
|
+
raise SlackMessage::ApiError, "Received error response '#{error}' from Slack during message posting:\n#{response.body}"
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
|
-
def self.raise_update_response_errors(response,
|
43
|
+
def self.raise_update_response_errors(response, params, profile)
|
42
44
|
body = JSON.parse(response.body)
|
43
45
|
error = body.fetch("error", "")
|
44
46
|
|
45
|
-
if
|
46
|
-
raise SlackMessage::ApiError, "Couldn't update Slack message because the
|
47
|
+
if error == "invalid_blocks"
|
48
|
+
raise SlackMessage::ApiError, "Couldn't update Slack message because the request contained invalid blocks:\n#{blocks_message(params[:blocks])}"
|
49
|
+
elsif error == "invalid_blocks_format"
|
50
|
+
raise SlackMessage::ApiError, "Couldn't update Slack message because blocks is not a valid JSON object or doesn't match the Block Kit syntax:\n#{blocks_message(params[:blocks])}"
|
47
51
|
elsif error == "channel_not_found"
|
48
|
-
raise SlackMessage::ApiError, "Tried to update Slack message to non-existent channel or user '#{
|
52
|
+
raise SlackMessage::ApiError, "Tried to update Slack message to non-existent channel or user '#{params[:channel]}'"
|
49
53
|
|
50
54
|
elsif error == "message_not_found"
|
51
|
-
raise SlackMessage::ApiError, "Tried to update Slack message, but the message wasn't found (timestamp '#{
|
55
|
+
raise SlackMessage::ApiError, "Tried to update Slack message, but the message wasn't found (timestamp '#{params[:ts]}' for channel '#{params[:channel]}'"
|
52
56
|
elsif error == "cant_update_message"
|
53
57
|
raise SlackMessage::ApiError, "Couldn't update message because the message type isn't able to be updated, or #{profile[:handle]} isn't allowed to update it"
|
54
58
|
elsif error == "edit_window_closed"
|
@@ -68,7 +72,7 @@ class SlackMessage::ErrorHandling
|
|
68
72
|
elsif response.code != "200"
|
69
73
|
raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
|
70
74
|
elsif !(error.nil? || error == "")
|
71
|
-
raise SlackMessage::ApiError, "Received error response from Slack during message update:\n#{response.body}"
|
75
|
+
raise SlackMessage::ApiError, "Received error response '#{error}' from Slack during message update:\n#{response.body}"
|
72
76
|
end
|
73
77
|
end
|
74
78
|
|
@@ -98,11 +102,17 @@ class SlackMessage::ErrorHandling
|
|
98
102
|
elsif response.code != "200"
|
99
103
|
raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
|
100
104
|
elsif !(error.nil? || error == "")
|
101
|
-
raise SlackMessage::ApiError, "Received error response from Slack during message delete:\n#{response.body}"
|
105
|
+
raise SlackMessage::ApiError, "Received error response '#{error}' from Slack during message delete:\n#{response.body}"
|
102
106
|
end
|
103
107
|
end
|
104
108
|
|
105
|
-
def self.raise_user_lookup_response_errors(
|
109
|
+
def self.raise_user_lookup_response_errors(response, email, profile)
|
110
|
+
begin
|
111
|
+
payload = JSON.parse(response.body)
|
112
|
+
rescue
|
113
|
+
raise SlackMessage::ApiError, "Unable to parse JSON response from Slack API\n#{response.body}"
|
114
|
+
end
|
115
|
+
|
106
116
|
error = payload["error"]
|
107
117
|
|
108
118
|
if error == "users_not_found"
|
@@ -121,4 +131,12 @@ class SlackMessage::ErrorHandling
|
|
121
131
|
raise SlackMessage::ApiError, "Received error response from Slack during user lookup:\n#{response.body}"
|
122
132
|
end
|
123
133
|
end
|
134
|
+
|
135
|
+
def self.blocks_message(blocks)
|
136
|
+
if SlackMessage::Configuration.debugging?
|
137
|
+
JSON.pretty_generate(blocks)
|
138
|
+
else
|
139
|
+
"[Enable debugging in configuration to view block data.]"
|
140
|
+
end
|
141
|
+
end
|
124
142
|
end
|
data/lib/slack_message/rspec.rb
CHANGED
@@ -40,30 +40,32 @@ module SlackMessage::RSpec
|
|
40
40
|
FauxResponse = Struct.new(:code, :body)
|
41
41
|
|
42
42
|
def self.included(_)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
[:post_message, :update_message, :delete_message].each do |method|
|
44
|
+
SlackMessage::Api.undef_method(method)
|
45
|
+
SlackMessage::Api.define_singleton_method(method) do |profile, params|
|
46
|
+
@@listeners.each do |listener|
|
47
|
+
listener.record_call(params.merge(profile: profile))
|
48
|
+
end
|
49
|
+
|
50
|
+
response = {
|
51
|
+
"ok" => true,
|
52
|
+
"channel" => "C12345678",
|
53
|
+
"ts" => "1635863996.002300",
|
54
|
+
"message" => { "type"=>"message", "subtype"=>"bot_message",
|
55
|
+
"text"=>"foo",
|
56
|
+
"ts"=>"1635863996.002300",
|
57
|
+
"username"=>"SlackMessage",
|
58
|
+
"icons"=>{"emoji"=>":successkid:"},
|
59
|
+
"bot_id"=>"B1234567890",
|
60
|
+
"blocks"=> [{"type"=>"section",
|
61
|
+
"block_id"=>"hAh7",
|
62
|
+
"text"=>{"type"=>"mrkdwn", "text"=>"foo", "verbatim"=>false}}
|
63
|
+
]
|
64
|
+
}
|
65
|
+
}.merge(@@custom_response).to_json
|
66
|
+
|
67
|
+
return FauxResponse.new(@@response_code, response)
|
47
68
|
end
|
48
|
-
|
49
|
-
response = {
|
50
|
-
"ok" => true,
|
51
|
-
"channel" => "C12345678",
|
52
|
-
"ts" => "1635863996.002300",
|
53
|
-
"message" => { "type"=>"message", "subtype"=>"bot_message",
|
54
|
-
"text"=>"foo",
|
55
|
-
"ts"=>"1635863996.002300",
|
56
|
-
"username"=>"SlackMessage",
|
57
|
-
"icons"=>{"emoji"=>":successkid:"},
|
58
|
-
"bot_id"=>"B1234567890",
|
59
|
-
"blocks"=> [{"type"=>"section",
|
60
|
-
"block_id"=>"hAh7",
|
61
|
-
"text"=>{"type"=>"mrkdwn", "text"=>"foo", "verbatim"=>false}}
|
62
|
-
]
|
63
|
-
}
|
64
|
-
}.merge(@@custom_response).to_json
|
65
|
-
|
66
|
-
return FauxResponse.new(@@response_code, response)
|
67
69
|
end
|
68
70
|
|
69
71
|
SlackMessage::Api.undef_method(:look_up_user_by_email)
|
data/slack_message.gemspec
CHANGED
data/spec/slack_message_spec.rb
CHANGED
@@ -4,6 +4,10 @@ RSpec.describe SlackMessage do
|
|
4
4
|
|
5
5
|
describe "DSL" do
|
6
6
|
describe "#build" do
|
7
|
+
def outer_method
|
8
|
+
"foo"
|
9
|
+
end
|
10
|
+
|
7
11
|
it "renders some JSON" do
|
8
12
|
SlackMessage.configure do |config|
|
9
13
|
config.clear_profiles!
|
@@ -13,11 +17,17 @@ RSpec.describe SlackMessage do
|
|
13
17
|
expected_output = [
|
14
18
|
{ type: "section",
|
15
19
|
text: { text: "foo", type: "mrkdwn" }
|
16
|
-
}
|
20
|
+
},
|
21
|
+
{ type: "section",
|
22
|
+
text: { text: "foo", type: "mrkdwn" }
|
23
|
+
},
|
17
24
|
]
|
18
25
|
|
19
26
|
output = SlackMessage.build do
|
20
|
-
text
|
27
|
+
text outer_method()
|
28
|
+
section do
|
29
|
+
text outer_method()
|
30
|
+
end
|
21
31
|
end
|
22
32
|
|
23
33
|
expect(output).to eq(expected_output)
|
@@ -50,13 +60,6 @@ RSpec.describe SlackMessage do
|
|
50
60
|
end
|
51
61
|
end
|
52
62
|
|
53
|
-
fit do
|
54
|
-
SlackMessage.build do
|
55
|
-
notification_text 'one'
|
56
|
-
notification_text 'two'
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
63
|
it "can assert expectations against posts" do
|
61
64
|
expect {
|
62
65
|
SlackMessage.post_to('#lieutenant') { text "foo" }
|
@@ -173,18 +176,6 @@ RSpec.describe SlackMessage do
|
|
173
176
|
SlackMessage::RSpec.reset_mock_response
|
174
177
|
end
|
175
178
|
|
176
|
-
it "raises nice error messages when API methods return errors" do
|
177
|
-
SlackMessage::RSpec.respond_with({'error' => 'nuffin'})
|
178
|
-
|
179
|
-
expect {
|
180
|
-
SlackMessage.post_to('#general') { text 'nuh uh' }
|
181
|
-
}.to raise_error(SlackMessage::ApiError)
|
182
|
-
|
183
|
-
expect {
|
184
|
-
SlackMessage.post_as(:schmoebot) { text 'nuh uh' }
|
185
|
-
}.to raise_error(SlackMessage::ApiError)
|
186
|
-
end
|
187
|
-
|
188
179
|
it "raises for redirects" do
|
189
180
|
SlackMessage::RSpec.respond_with(code: '302')
|
190
181
|
|
@@ -193,24 +184,83 @@ RSpec.describe SlackMessage do
|
|
193
184
|
}.to raise_error(SlackMessage::ApiError)
|
194
185
|
end
|
195
186
|
|
196
|
-
it "raises errors
|
187
|
+
it "even raises errors during deletes" do
|
197
188
|
message = SlackMessage.post_to('#general') { text 'nuh uh' }
|
198
189
|
|
199
190
|
SlackMessage::RSpec.respond_with({'error' => 'bad choice'})
|
200
191
|
|
201
192
|
expect {
|
202
|
-
SlackMessage.
|
193
|
+
SlackMessage.delete(message)
|
203
194
|
}.to raise_error(SlackMessage::ApiError)
|
204
195
|
end
|
205
196
|
|
206
|
-
|
207
|
-
|
197
|
+
shared_examples 'post api error message' do |error, error_message|
|
198
|
+
it "responds to posts with error code '#{error}' with the expected message" do
|
199
|
+
SlackMessage::RSpec.respond_with({'error' => error})
|
208
200
|
|
209
|
-
|
201
|
+
expect {
|
202
|
+
SlackMessage.post_to('#general') { text 'nuh uh' }
|
203
|
+
}.to raise_error(SlackMessage::ApiError).with_message(error_message)
|
210
204
|
|
211
|
-
|
212
|
-
|
213
|
-
|
205
|
+
expect {
|
206
|
+
SlackMessage.post_as(:schmoebot) { text 'nuh uh' }
|
207
|
+
}.to raise_error(SlackMessage::ApiError).with_message(error_message)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
shared_examples 'update api error message' do |error, error_message|
|
212
|
+
it "responds to updates with error code '#{error}' with the expected message" do
|
213
|
+
message = SlackMessage.post_to('#general') { text 'nuh uh' }
|
214
|
+
|
215
|
+
SlackMessage::RSpec.respond_with({'error' => error})
|
216
|
+
|
217
|
+
expect {
|
218
|
+
SlackMessage.update(message) { text 'nuh uh' }
|
219
|
+
}.to raise_error(SlackMessage::ApiError).with_message(error_message)
|
220
|
+
end
|
214
221
|
end
|
222
|
+
|
223
|
+
shared_examples 'delete api error message' do |error, error_message|
|
224
|
+
it "responds to updates with error code '#{error}' with the expected message" do
|
225
|
+
message = SlackMessage.post_to('#general') { text 'nuh uh' }
|
226
|
+
|
227
|
+
SlackMessage::RSpec.respond_with({'error' => error})
|
228
|
+
|
229
|
+
expect {
|
230
|
+
SlackMessage.delete(message)
|
231
|
+
}.to raise_error(SlackMessage::ApiError).with_message(error_message)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
shared_examples 'block api error message' do |error, error_message|
|
236
|
+
include_examples 'post api error message', error, error_message
|
237
|
+
include_examples 'update api error message', error, error_message
|
238
|
+
end
|
239
|
+
|
240
|
+
include_examples 'block api error message', 'nuffin', /Received error response 'nuffin' from Slack/
|
241
|
+
include_examples 'block api error message', 'invalid_blocks', /because the request contained invalid blocks:\n\[Enable debugging in configuration to view block data\.\]/
|
242
|
+
include_examples 'block api error message', 'invalid_blocks_format', /because blocks is not a valid JSON object or doesn't match the Block Kit syntax:\n\[Enable debugging in configuration to view block data\.\]/
|
243
|
+
include_examples 'block api error message', 'channel_not_found', /Slack message to non-existent channel or user/
|
244
|
+
include_examples 'block api error message', 'invalid_auth', /because the API key for profile '.*' is wrong, or the app has insufficient permissions \(invalid_auth\)/
|
245
|
+
include_examples 'block api error message', 'message_too_long', /but the message was too long/
|
246
|
+
include_examples 'block api error message', 'invalid_arguments', /with invalid payload/
|
247
|
+
include_examples 'block api error message', 'rate_limited', /because you've reached your rate limit/
|
248
|
+
|
249
|
+
# Scheduling messages
|
250
|
+
include_examples 'post api error message', 'invalid_time', /because you requested an invalid time/
|
251
|
+
include_examples 'post api error message', 'time_in_past', /because you requested a time in the past \(or too close to now\)/
|
252
|
+
include_examples 'post api error message', 'time_too_far', /because you requested a time more than 120 days in the future/
|
253
|
+
|
254
|
+
# Updating messages
|
255
|
+
include_examples 'update api error message', 'message_not_found', /but the message wasn't found/
|
256
|
+
|
257
|
+
# Deleting messages
|
258
|
+
include_examples 'delete api error message', 'nuffin', /Received error response 'nuffin' from Slack/
|
259
|
+
include_examples 'delete api error message', 'invalid_scheduled_message_id', /Can't delete message because the ID was invalid, or the message has already posted/
|
260
|
+
include_examples 'delete api error message', 'message_not_found', /but the message wasn't found/
|
261
|
+
include_examples 'delete api error message', 'cant_delete_message', /Can't delete message because 'default' doesn't have permission to/
|
262
|
+
include_examples 'delete api error message', 'compliance_exports_prevent_deletion', /Can't delete message because team compliance settings prevent it/
|
263
|
+
include_examples 'delete api error message', 'invalid_auth', /because the API key for profile '.*' is wrong, or the app has insufficient permissions \(invalid_auth\)/
|
264
|
+
include_examples 'delete api error message', 'rate_limited', /because you've reached your rate limit/
|
215
265
|
end
|
216
266
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -26,7 +26,11 @@ RSpec.configure do |config|
|
|
26
26
|
# is tagged with `:focus`, all examples get run. RSpec also provides
|
27
27
|
# aliases for `it`, `describe`, and `context` that include `:focus`
|
28
28
|
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
29
|
-
|
29
|
+
if ENV['CI'] == "true"
|
30
|
+
config.filter_run_when_matching :focus => lambda { raise ArgumentError, "Don't filter tests on checked in code." }
|
31
|
+
else
|
32
|
+
config.filter_run_when_matching :focus
|
33
|
+
end
|
30
34
|
|
31
35
|
# Limits the available syntax to the non-monkey patched syntax that is
|
32
36
|
# recommended. For more details, see:
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slack_message
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Mastey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|