Skip to content

Commit

Permalink
Add JSON encoding to all applicable Web API arguments (#448)
Browse files Browse the repository at this point in the history
* Method and template for json encoding options

* regenerate files without patches

* reintroduce missing patched lines and recreated patches [ci skip]

* use api-ref to find JSON arguments

* redo patches

* update to latest slack-api-ref

* use arg format to find json args

* require the new file

* add tests for encode_options_as_json

* auto-generate tests for json params

* safer strings in json tests

* rubocop

* add changelog entry

* fix options hash in tests
  • Loading branch information
jmanian authored Mar 21, 2023
1 parent bb36a69 commit 16ffbf5
Show file tree
Hide file tree
Showing 29 changed files with 290 additions and 171 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### 2.1.1 (Next)

* Your contribution here.
* [#448](https://github.com/slack-ruby/slack-ruby-client/pull/448): Automatically convert more Web API arguments to JSON-encoded strings - [@jmanian](https://github.com/jmanian).

### 2.1.0 (2023/03/17)

Expand Down
1 change: 1 addition & 0 deletions lib/slack-ruby-client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
require_relative 'slack/web/api/error'
require_relative 'slack/web/api/errors'
require_relative 'slack/web/api/errors/server_error'
require_relative 'slack/web/api/options'
require_relative 'slack/web/faraday/response/raise_error'
require_relative 'slack/web/faraday/response/wrap_error'
require_relative 'slack/web/faraday/connection'
Expand Down
1 change: 1 addition & 0 deletions lib/slack/web/api/endpoints/admin_conversations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ def admin_conversations_search(options = {})
def admin_conversations_setConversationPrefs(options = {})
raise ArgumentError, 'Required arguments :channel_id missing' if options[:channel_id].nil?
raise ArgumentError, 'Required arguments :prefs missing' if options[:prefs].nil?
options = encode_options_as_json(options, %i[prefs])
post('admin.conversations.setConversationPrefs', options)
end

Expand Down
2 changes: 2 additions & 0 deletions lib/slack/web/api/endpoints/apps_manifest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module AppsManifest
# @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/apps.manifest/apps.manifest.create.json
def apps_manifest_create(options = {})
raise ArgumentError, 'Required arguments :manifest missing' if options[:manifest].nil?
options = encode_options_as_json(options, %i[manifest])
post('apps.manifest.create', options)
end

Expand Down Expand Up @@ -54,6 +55,7 @@ def apps_manifest_export(options = {})
def apps_manifest_update(options = {})
raise ArgumentError, 'Required arguments :app_id missing' if options[:app_id].nil?
raise ArgumentError, 'Required arguments :manifest missing' if options[:manifest].nil?
options = encode_options_as_json(options, %i[manifest])
post('apps.manifest.update', options)
end

Expand Down
43 changes: 6 additions & 37 deletions lib/slack/web/api/endpoints/chat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,7 @@ def chat_postEphemeral(options = {})
raise ArgumentError, 'Required arguments :text, :attachments or :blocks missing' if options[:text].nil? && options[:attachments].nil? && options[:blocks].nil?
raise ArgumentError, 'Required arguments :user missing' if options[:user].nil?
options = options.merge(user: users_id(options)['user']['id']) if options[:user]
# attachments must be passed as an encoded JSON string
if options.key?(:attachments)
attachments = options[:attachments]
attachments = JSON.dump(attachments) unless attachments.is_a?(String)
options = options.merge(attachments: attachments)
end
# blocks must be passed as an encoded JSON string
if options.key?(:blocks)
blocks = options[:blocks]
blocks = JSON.dump(blocks) unless blocks.is_a?(String)
options = options.merge(blocks: blocks)
end
options = encode_options_as_json(options, %i[attachments blocks])
post('chat.postEphemeral', options)
end

Expand Down Expand Up @@ -180,18 +169,7 @@ def chat_postEphemeral(options = {})
def chat_postMessage(options = {})
raise ArgumentError, 'Required arguments :channel missing' if options[:channel].nil?
raise ArgumentError, 'Required arguments :text, :attachments or :blocks missing' if options[:text].nil? && options[:attachments].nil? && options[:blocks].nil?
# attachments must be passed as an encoded JSON string
if options.key?(:attachments)
attachments = options[:attachments]
attachments = JSON.dump(attachments) unless attachments.is_a?(String)
options = options.merge(attachments: attachments)
end
# blocks must be passed as an encoded JSON string
if options.key?(:blocks)
blocks = options[:blocks]
blocks = JSON.dump(blocks) unless blocks.is_a?(String)
options = options.merge(blocks: blocks)
end
options = encode_options_as_json(options, %i[attachments blocks metadata])
post('chat.postMessage', options)
end

Expand Down Expand Up @@ -230,6 +208,7 @@ def chat_scheduleMessage(options = {})
raise ArgumentError, 'Required arguments :channel missing' if options[:channel].nil?
raise ArgumentError, 'Required arguments :post_at missing' if options[:post_at].nil?
raise ArgumentError, 'Required arguments :text missing' if options[:text].nil?
options = encode_options_as_json(options, %i[attachments blocks metadata])
post('chat.scheduleMessage', options)
end

Expand Down Expand Up @@ -261,6 +240,7 @@ def chat_unfurl(options = {})
raise ArgumentError, 'Required arguments :ts missing' if options[:ts].nil?
raise ArgumentError, 'Required arguments :unfurls missing' if options[:unfurls].nil?
options = options.merge(channel: conversations_id(options)['channel']['id']) if options[:channel]
options = encode_options_as_json(options, %i[unfurls user_auth_blocks])
post('chat.unfurl', options)
end

Expand Down Expand Up @@ -293,21 +273,10 @@ def chat_unfurl(options = {})
# @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/chat/chat.update.json
def chat_update(options = {})
raise ArgumentError, 'Required arguments :channel missing' if options[:channel].nil?
raise ArgumentError, 'Required arguments :text, :attachments, :blocks or :reply_broadcast missing' if options[:text].nil? && options[:attachments].nil? && options[:blocks].nil? && options[:reply_broadcast].nil?
raise ArgumentError, 'Required arguments :ts missing' if options[:ts].nil?
raise ArgumentError, 'Required arguments :text, :attachments, :blocks or :reply_broadcast missing' if options[:text].nil? && options[:attachments].nil? && options[:blocks].nil? && options[:reply_broadcast].nil?
options = options.merge(channel: conversations_id(options)['channel']['id']) if options[:channel]
# attachments must be passed as an encoded JSON string
if options.key?(:attachments)
attachments = options[:attachments]
attachments = JSON.dump(attachments) unless attachments.is_a?(String)
options = options.merge(attachments: attachments)
end
# blocks must be passed as an encoded JSON string
if options.key?(:blocks)
blocks = options[:blocks]
blocks = JSON.dump(blocks) unless blocks.is_a?(String)
options = options.merge(blocks: blocks)
end
options = encode_options_as_json(options, %i[attachments blocks metadata])
post('chat.update', options)
end
end
Expand Down
7 changes: 1 addition & 6 deletions lib/slack/web/api/endpoints/dialog.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@ module Dialog
def dialog_open(options = {})
raise ArgumentError, 'Required arguments :dialog missing' if options[:dialog].nil?
raise ArgumentError, 'Required arguments :trigger_id missing' if options[:trigger_id].nil?
# dialog must be passed as an encoded JSON string
if options.key?(:dialog)
dialog = options[:dialog]
dialog = JSON.dump(dialog) unless dialog.is_a?(String)
options = options.merge(dialog: dialog)
end
options = encode_options_as_json(options, %i[dialog])
post('dialog.open', options)
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/slack/web/api/endpoints/users_profile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def users_profile_get(options = {})
# @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/users.profile/users.profile.set.json
def users_profile_set(options = {})
options = options.merge(user: users_id(options)['user']['id']) if options[:user]
options = encode_options_as_json(options, %i[profile])
post('users.profile.set', options)
end
end
Expand Down
24 changes: 4 additions & 20 deletions lib/slack/web/api/endpoints/views.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ module Views
def views_open(options = {})
raise ArgumentError, 'Required arguments :view missing' if options[:view].nil?
raise ArgumentError, 'One of :trigger_id, :interactivity_pointer is required' unless options[:trigger_id].nil? ^ options[:interactivity_pointer].nil?
if options.key?(:view)
view = options[:view]
view = JSON.dump(view) unless view.is_a?(String)
options = options.merge(view: view)
end
options = encode_options_as_json(options, %i[view])
post('views.open', options)
end

Expand All @@ -42,11 +38,7 @@ def views_open(options = {})
def views_publish(options = {})
raise ArgumentError, 'Required arguments :user_id missing' if options[:user_id].nil?
raise ArgumentError, 'Required arguments :view missing' if options[:view].nil?
if options.key?(:view)
view = options[:view]
view = JSON.dump(view) unless view.is_a?(String)
options = options.merge(view: view)
end
options = encode_options_as_json(options, %i[view])
post('views.publish', options)
end

Expand All @@ -64,11 +56,7 @@ def views_publish(options = {})
def views_push(options = {})
raise ArgumentError, 'Required arguments :view missing' if options[:view].nil?
raise ArgumentError, 'One of :trigger_id, :interactivity_pointer is required' unless options[:trigger_id].nil? ^ options[:interactivity_pointer].nil?
if options.key?(:view)
view = options[:view]
view = JSON.dump(view) unless view.is_a?(String)
options = options.merge(view: view)
end
options = encode_options_as_json(options, %i[view])
post('views.push', options)
end

Expand All @@ -88,11 +76,7 @@ def views_push(options = {})
def views_update(options = {})
raise ArgumentError, 'Required arguments :view missing' if options[:view].nil?
raise ArgumentError, 'One of :external_id, :view_id is required' unless options[:external_id].nil? ^ options[:view_id].nil?
if options.key?(:view)
view = options[:view]
view = JSON.dump(view) unless view.is_a?(String)
options = options.merge(view: view)
end
options = encode_options_as_json(options, %i[view])
post('views.update', options)
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/slack/web/api/endpoints/workflows.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def workflows_stepCompleted(options = {})
def workflows_stepFailed(options = {})
raise ArgumentError, 'Required arguments :error missing' if options[:error].nil?
raise ArgumentError, 'Required arguments :workflow_step_execute_id missing' if options[:workflow_step_execute_id].nil?
options = encode_options_as_json(options, %i[error])
post('workflows.stepFailed', options)
end

Expand All @@ -52,6 +53,7 @@ def workflows_stepFailed(options = {})
# @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/workflows/workflows.updateStep.json
def workflows_updateStep(options = {})
raise ArgumentError, 'Required arguments :workflow_step_edit_id missing' if options[:workflow_step_edit_id].nil?
options = encode_options_as_json(options, %i[inputs outputs])
post('workflows.updateStep', options)
end
end
Expand Down
26 changes: 26 additions & 0 deletions lib/slack/web/api/options.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module Slack
module Web
module Api
module Options
def encode_options_as_json(options, keys)
encoded_options = options.slice(*keys).transform_values do |value|
encode_json(value)
end
options.merge(encoded_options)
end

private

def encode_json(value)
if value.is_a?(String)
value
else
JSON.dump(value)
end
end
end
end
end
end
56 changes: 8 additions & 48 deletions lib/slack/web/api/patches/chat.attachments-blocks.patch
Original file line number Diff line number Diff line change
@@ -1,69 +1,29 @@
diff --git a/lib/slack/web/api/endpoints/chat.rb b/lib/slack/web/api/endpoints/chat.rb
index 701cd1e..07acc40 100644
index c3100ec..5909f4e 100644
--- a/lib/slack/web/api/endpoints/chat.rb
+++ b/lib/slack/web/api/endpoints/chat.rb
@@ -122,9 +122,21 @@ module Slack
@@ -122,7 +122,7 @@ module Slack
# @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/chat/chat.postEphemeral.json
def chat_postEphemeral(options = {})
raise ArgumentError, 'Required arguments :channel missing' if options[:channel].nil?
- raise ArgumentError, 'Required arguments :text missing' if options[:text].nil?
+ raise ArgumentError, 'Required arguments :text, :attachments or :blocks missing' if options[:text].nil? && options[:attachments].nil? && options[:blocks].nil?
raise ArgumentError, 'Required arguments :user missing' if options[:user].nil?
options = options.merge(user: users_id(options)['user']['id']) if options[:user]
+ # attachments must be passed as an encoded JSON string
+ if options.key?(:attachments)
+ attachments = options[:attachments]
+ attachments = JSON.dump(attachments) unless attachments.is_a?(String)
+ options = options.merge(attachments: attachments)
+ end
+ # blocks must be passed as an encoded JSON string
+ if options.key?(:blocks)
+ blocks = options[:blocks]
+ blocks = JSON.dump(blocks) unless blocks.is_a?(String)
+ options = options.merge(blocks: blocks)
+ end
post('chat.postEphemeral', options)
end

@@ -167,6 +179,19 @@ module Slack
options = encode_options_as_json(options, %i[attachments blocks])
@@ -168,6 +168,7 @@ module Slack
# @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/chat/chat.postMessage.json
def chat_postMessage(options = {})
raise ArgumentError, 'Required arguments :channel missing' if options[:channel].nil?
+ raise ArgumentError, 'Required arguments :text, :attachments or :blocks missing' if options[:text].nil? && options[:attachments].nil? && options[:blocks].nil?
+ # attachments must be passed as an encoded JSON string
+ if options.key?(:attachments)
+ attachments = options[:attachments]
+ attachments = JSON.dump(attachments) unless attachments.is_a?(String)
+ options = options.merge(attachments: attachments)
+ end
+ # blocks must be passed as an encoded JSON string
+ if options.key?(:blocks)
+ blocks = options[:blocks]
+ blocks = JSON.dump(blocks) unless blocks.is_a?(String)
+ options = options.merge(blocks: blocks)
+ end
options = encode_options_as_json(options, %i[attachments blocks metadata])
post('chat.postMessage', options)
end

@@ -268,8 +293,21 @@ module Slack
# @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/chat/chat.update.json
@@ -273,6 +274,7 @@ module Slack
def chat_update(options = {})
raise ArgumentError, 'Required arguments :channel missing' if options[:channel].nil?
+ raise ArgumentError, 'Required arguments :text, :attachments, :blocks or :reply_broadcast missing' if options[:text].nil? && options[:attachments].nil? && options[:blocks].nil? && options[:reply_broadcast].nil?
raise ArgumentError, 'Required arguments :ts missing' if options[:ts].nil?
+ raise ArgumentError, 'Required arguments :text, :attachments, :blocks or :reply_broadcast missing' if options[:text].nil? && options[:attachments].nil? && options[:blocks].nil? && options[:reply_broadcast].nil?
options = options.merge(channel: conversations_id(options)['channel']['id']) if options[:channel]
+ # attachments must be passed as an encoded JSON string
+ if options.key?(:attachments)
+ attachments = options[:attachments]
+ attachments = JSON.dump(attachments) unless attachments.is_a?(String)
+ options = options.merge(attachments: attachments)
+ end
+ # blocks must be passed as an encoded JSON string
+ if options.key?(:blocks)
+ blocks = options[:blocks]
+ blocks = JSON.dump(blocks) unless blocks.is_a?(String)
+ options = options.merge(blocks: blocks)
+ end
options = encode_options_as_json(options, %i[attachments blocks metadata])
post('chat.update', options)
end
end
17 changes: 0 additions & 17 deletions lib/slack/web/api/patches/dialog.encoded-json.patch

This file was deleted.

Loading

0 comments on commit 16ffbf5

Please sign in to comment.