slack_message 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdc04bd65ae2c98be234fbea88cec4d5373553bdb758a28959ef7c2515e8420c
4
- data.tar.gz: 68beb2e7a60e6cb6b4f2904e1f5335e934b447070b29c9362caca0ce2148fad5
3
+ metadata.gz: 0b35e974e04457e2d9e3b55af0c5c7562d0381c76477e9a85143c66e8d605071
4
+ data.tar.gz: 21892df8e52b365ade154424d2c98a55434efb541e144d046d208fe8b1243f24
5
5
  SHA512:
6
- metadata.gz: f6f5ca7c5ced4e495439429eb9aba32fbb4567f64eff04ff3eff9ba5e05caab3faac995d18e830e58a9bb432c40a4cc4ecc4e383cff71bf7fa7e4cf4f8b47e75
7
- data.tar.gz: 5ad0999dd393d908a3ddd1e8e83d82f01ff8296f5178f7817cabd73553987c37a82107034d50a20c52a671fd12af5d6771e20962dbc0dcccc7eb135865a9a465
6
+ metadata.gz: 720e5bcf8d91f355939474b09f9d2a9830178037dca5c067ecfc4c6585631673e2ea13d888338ff1fb7a3d25ae1009b5f1a97f7a8244f1f06696b437227f6260
7
+ data.tar.gz: b7fa2c16e3d5a31ac18605bda1e1eacdd367c6e94f34779c50964a92c679b8edcdc1168d3fa808392401669f55bbeae30aec607ec44a2cfd55b916d0ad0fe70d
data/CHANGELOG.md CHANGED
@@ -1,7 +1,13 @@
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
+
3
9
  ## [3.2.0] - 2022-06-23
4
- - Fix bugs introduced by accidental checkin of incomplete refactor
10
+ - Fix bugs introduced by accidental checkin of incomplete refactor.
5
11
 
6
12
  ## [3.1.0] - 2022-04-18
7
13
  - Methods from the calling context can now be called within a section block.
@@ -41,6 +41,10 @@ module SlackMessage::Api
41
41
  raise ArgumentError, "Tried to send an entirely empty message."
42
42
  end
43
43
 
44
+ if params[:blocks].length > 50
45
+ raise ArgumentError, "Message cannot contain more than 50 blocks."
46
+ end
47
+
44
48
  icon = payload.custom_bot_icon || profile[:icon]
45
49
  if icon =~ /^:\w+:$/
46
50
  params[:icon_emoji] = icon
@@ -80,15 +84,17 @@ module SlackMessage::Api
80
84
  raise ArgumentError, "Tried to send an entirely empty message."
81
85
  end
82
86
 
87
+ if params[:blocks].length > 50
88
+ raise ArgumentError, "Message cannot contain more than 50 blocks."
89
+ end
90
+
83
91
  if SlackMessage::Configuration.debugging?
84
92
  warn params.inspect
85
93
  end
86
94
 
87
95
  response = update_message(profile, params)
88
- body = JSON.parse(response.body)
89
- error = body.fetch("error", "")
90
96
 
91
- SlackMessage::ErrorHandling.raise_post_response_errors(response, message, profile)
97
+ SlackMessage::ErrorHandling.raise_update_response_errors(response, params, profile)
92
98
  SlackMessage::Response.new(response, profile[:handle])
93
99
  end
94
100
 
@@ -7,8 +7,10 @@ class SlackMessage::ErrorHandling
7
7
  body = JSON.parse(response.body)
8
8
  error = body.fetch("error", "")
9
9
 
10
- if ["invalid_blocks", "invalid_blocks_format"].include?(error)
11
- raise SlackMessage::ApiError, "Couldn't send Slack message because the serialized message had an invalid format"
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, message, profile)
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 ["invalid_blocks", "invalid_blocks_format"].include?(error)
46
- raise SlackMessage::ApiError, "Couldn't update Slack message because the serialized message had an invalid format"
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 '#{message.channel}'"
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 '#{message.timestamp}' for channel '#{message.channel}'"
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,7 +102,7 @@ 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
 
@@ -127,4 +131,12 @@ class SlackMessage::ErrorHandling
127
131
  raise SlackMessage::ApiError, "Received error response from Slack during user lookup:\n#{response.body}"
128
132
  end
129
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
130
142
  end
@@ -40,30 +40,32 @@ module SlackMessage::RSpec
40
40
  FauxResponse = Struct.new(:code, :body)
41
41
 
42
42
  def self.included(_)
43
- SlackMessage::Api.undef_method(:post_message)
44
- SlackMessage::Api.define_singleton_method(:post_message) do |profile, params|
45
- @@listeners.each do |listener|
46
- listener.record_call(params.merge(profile: profile))
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)
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'slack_message'
3
- gem.version = "3.2.0"
3
+ gem.version = "3.3.0"
4
4
  gem.summary = "A nice DSL for composing rich messages in Slack"
5
5
  gem.authors = ["Joe Mastey"]
6
6
  gem.email = 'hello@joemastey.com'
@@ -176,18 +176,6 @@ RSpec.describe SlackMessage do
176
176
  SlackMessage::RSpec.reset_mock_response
177
177
  end
178
178
 
179
- it "raises nice error messages when API methods return errors" do
180
- SlackMessage::RSpec.respond_with({'error' => 'nuffin'})
181
-
182
- expect {
183
- SlackMessage.post_to('#general') { text 'nuh uh' }
184
- }.to raise_error(SlackMessage::ApiError)
185
-
186
- expect {
187
- SlackMessage.post_as(:schmoebot) { text 'nuh uh' }
188
- }.to raise_error(SlackMessage::ApiError)
189
- end
190
-
191
179
  it "raises for redirects" do
192
180
  SlackMessage::RSpec.respond_with(code: '302')
193
181
 
@@ -196,24 +184,83 @@ RSpec.describe SlackMessage do
196
184
  }.to raise_error(SlackMessage::ApiError)
197
185
  end
198
186
 
199
- it "raises errors w/ updates too" do
187
+ it "even raises errors during deletes" do
200
188
  message = SlackMessage.post_to('#general') { text 'nuh uh' }
201
189
 
202
190
  SlackMessage::RSpec.respond_with({'error' => 'bad choice'})
203
191
 
204
192
  expect {
205
- SlackMessage.update(message) { text 'nuh uh' }
193
+ SlackMessage.delete(message)
206
194
  }.to raise_error(SlackMessage::ApiError)
207
195
  end
208
196
 
209
- it "even raises errors during deletes" do
210
- message = SlackMessage.post_to('#general') { text 'nuh uh' }
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})
211
200
 
212
- SlackMessage::RSpec.respond_with({'error' => 'bad choice'})
201
+ expect {
202
+ SlackMessage.post_to('#general') { text 'nuh uh' }
203
+ }.to raise_error(SlackMessage::ApiError).with_message(error_message)
213
204
 
214
- expect {
215
- SlackMessage.delete(message) { text 'nuh uh' }
216
- }.to raise_error(SlackMessage::ApiError)
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
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
217
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/
218
265
  end
219
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
- config.filter_run_when_matching :focus
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.2.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-06-23 00:00:00.000000000 Z
11
+ date: 2022-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec