slack_message 3.2.0 → 3.4.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: 494d2f51af95a53df19c42dcaa9f88168cf44509b1675dbe001a42fdf39250dc
4
+ data.tar.gz: 306050272f54d60a1b6820f315ac51c0b563af71862847efdb2940464ca201b8
5
5
  SHA512:
6
- metadata.gz: f6f5ca7c5ced4e495439429eb9aba32fbb4567f64eff04ff3eff9ba5e05caab3faac995d18e830e58a9bb432c40a4cc4ecc4e383cff71bf7fa7e4cf4f8b47e75
7
- data.tar.gz: 5ad0999dd393d908a3ddd1e8e83d82f01ff8296f5178f7817cabd73553987c37a82107034d50a20c52a671fd12af5d6771e20962dbc0dcccc7eb135865a9a465
6
+ metadata.gz: d8e43baeab730d3c6e7acbb1232b98d4a265b55260ab3c12bcc87325cb81d03f00b7ff05ff72667105e10e123c604630eac7331db238823374b8584d8242e611
7
+ data.tar.gz: 2c2709365ec780ca44c6960414861c9479eb3b2918d547ca3f3299745aa382e6affd6dfd46a364c27097f5e562939913e098c52bc72cb29911f7c9c669756d30
data/CHANGELOG.md CHANGED
@@ -1,7 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.4.0] - 2023-02-21
4
+ - Add full support for ruby 3.0.x kwargs
5
+
6
+ ## [3.3.0] - 2022-07-21
7
+ - Differentiate errors for bad JSON versus invalid block data.
8
+ - Expand tests to cover many more cases.
9
+ - Add validation for block size limit in Slack API.
10
+ - Add CI check to prevent checkin of `fit`, `fcontext` etc.
11
+
3
12
  ## [3.2.0] - 2022-06-23
4
- - Fix bugs introduced by accidental checkin of incomplete refactor
13
+ - Fix bugs introduced by accidental checkin of incomplete refactor.
5
14
 
6
15
  ## [3.1.0] - 2022-04-18
7
16
  - 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
 
@@ -80,8 +80,8 @@ class SlackMessage::Dsl
80
80
  # delegation to allow terse syntax without e.g. `section`
81
81
 
82
82
  def text(*args); default_section.text(*args); end
83
- def link_button(*args); default_section.link_button(*args); end
84
- def accessory_image(*args); default_section.accessory_image(*args); end
83
+ def link_button(*args, **kwargs); default_section.link_button(*args, **kwargs); end
84
+ def accessory_image(*args, **kwargs); default_section.accessory_image(*args, **kwargs); end
85
85
  def blank_line(*args); default_section.blank_line(*args); end
86
86
  def link(*args); default_section.link(*args); end
87
87
  def list_item(*args); default_section.list_item(*args); end
@@ -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.4.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'
@@ -127,6 +127,14 @@ RSpec.describe SlackMessage do
127
127
  SlackMessage.post_to('#general') { text "foo" }
128
128
  }.to post_to_slack.with_content_matching(/foo/)
129
129
  end
130
+
131
+ it "lets you send links with custom styles" do
132
+ expect {
133
+ SlackMessage.post_to('#general') do
134
+ link_button 'Does this person exist?', 'https://thispersondoesnotexist.com/image', style: :danger
135
+ end
136
+ }.to post_to_slack.with_content_matching(/danger/)
137
+ end
130
138
  end
131
139
 
132
140
  describe "API convenience" do
@@ -176,18 +184,6 @@ RSpec.describe SlackMessage do
176
184
  SlackMessage::RSpec.reset_mock_response
177
185
  end
178
186
 
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
187
  it "raises for redirects" do
192
188
  SlackMessage::RSpec.respond_with(code: '302')
193
189
 
@@ -196,24 +192,83 @@ RSpec.describe SlackMessage do
196
192
  }.to raise_error(SlackMessage::ApiError)
197
193
  end
198
194
 
199
- it "raises errors w/ updates too" do
195
+ it "even raises errors during deletes" do
200
196
  message = SlackMessage.post_to('#general') { text 'nuh uh' }
201
197
 
202
198
  SlackMessage::RSpec.respond_with({'error' => 'bad choice'})
203
199
 
204
200
  expect {
205
- SlackMessage.update(message) { text 'nuh uh' }
201
+ SlackMessage.delete(message)
206
202
  }.to raise_error(SlackMessage::ApiError)
207
203
  end
208
204
 
209
- it "even raises errors during deletes" do
210
- message = SlackMessage.post_to('#general') { text 'nuh uh' }
205
+ shared_examples 'post api error message' do |error, error_message|
206
+ it "responds to posts with error code '#{error}' with the expected message" do
207
+ SlackMessage::RSpec.respond_with({'error' => error})
211
208
 
212
- SlackMessage::RSpec.respond_with({'error' => 'bad choice'})
209
+ expect {
210
+ SlackMessage.post_to('#general') { text 'nuh uh' }
211
+ }.to raise_error(SlackMessage::ApiError).with_message(error_message)
213
212
 
214
- expect {
215
- SlackMessage.delete(message) { text 'nuh uh' }
216
- }.to raise_error(SlackMessage::ApiError)
213
+ expect {
214
+ SlackMessage.post_as(:schmoebot) { text 'nuh uh' }
215
+ }.to raise_error(SlackMessage::ApiError).with_message(error_message)
216
+ end
217
+ end
218
+
219
+ shared_examples 'update api error message' do |error, error_message|
220
+ it "responds to updates with error code '#{error}' with the expected message" do
221
+ message = SlackMessage.post_to('#general') { text 'nuh uh' }
222
+
223
+ SlackMessage::RSpec.respond_with({'error' => error})
224
+
225
+ expect {
226
+ SlackMessage.update(message) { text 'nuh uh' }
227
+ }.to raise_error(SlackMessage::ApiError).with_message(error_message)
228
+ end
217
229
  end
230
+
231
+ shared_examples 'delete api error message' do |error, error_message|
232
+ it "responds to updates with error code '#{error}' with the expected message" do
233
+ message = SlackMessage.post_to('#general') { text 'nuh uh' }
234
+
235
+ SlackMessage::RSpec.respond_with({'error' => error})
236
+
237
+ expect {
238
+ SlackMessage.delete(message)
239
+ }.to raise_error(SlackMessage::ApiError).with_message(error_message)
240
+ end
241
+ end
242
+
243
+ shared_examples 'block api error message' do |error, error_message|
244
+ include_examples 'post api error message', error, error_message
245
+ include_examples 'update api error message', error, error_message
246
+ end
247
+
248
+ include_examples 'block api error message', 'nuffin', /Received error response 'nuffin' from Slack/
249
+ include_examples 'block api error message', 'invalid_blocks', /because the request contained invalid blocks:\n\[Enable debugging in configuration to view block data\.\]/
250
+ 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\.\]/
251
+ include_examples 'block api error message', 'channel_not_found', /Slack message to non-existent channel or user/
252
+ include_examples 'block api error message', 'invalid_auth', /because the API key for profile '.*' is wrong, or the app has insufficient permissions \(invalid_auth\)/
253
+ include_examples 'block api error message', 'message_too_long', /but the message was too long/
254
+ include_examples 'block api error message', 'invalid_arguments', /with invalid payload/
255
+ include_examples 'block api error message', 'rate_limited', /because you've reached your rate limit/
256
+
257
+ # Scheduling messages
258
+ include_examples 'post api error message', 'invalid_time', /because you requested an invalid time/
259
+ include_examples 'post api error message', 'time_in_past', /because you requested a time in the past \(or too close to now\)/
260
+ include_examples 'post api error message', 'time_too_far', /because you requested a time more than 120 days in the future/
261
+
262
+ # Updating messages
263
+ include_examples 'update api error message', 'message_not_found', /but the message wasn't found/
264
+
265
+ # Deleting messages
266
+ include_examples 'delete api error message', 'nuffin', /Received error response 'nuffin' from Slack/
267
+ 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/
268
+ include_examples 'delete api error message', 'message_not_found', /but the message wasn't found/
269
+ include_examples 'delete api error message', 'cant_delete_message', /Can't delete message because 'default' doesn't have permission to/
270
+ include_examples 'delete api error message', 'compliance_exports_prevent_deletion', /Can't delete message because team compliance settings prevent it/
271
+ include_examples 'delete api error message', 'invalid_auth', /because the API key for profile '.*' is wrong, or the app has insufficient permissions \(invalid_auth\)/
272
+ include_examples 'delete api error message', 'rate_limited', /because you've reached your rate limit/
218
273
  end
219
274
  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.4.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: 2023-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec