slack_message 3.2.0 → 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 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