slack_message 3.0.2 → 3.3.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/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
|