discordrb-webhooks 3.4.3 → 3.5.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: 79b0d69e96092e442b9602a6dd69088579af024ec84480209754831dcd0e39f8
4
- data.tar.gz: 17ddc58683c197db7bb8afc5153e3587bef92652eecb9a2430d7101356f730a4
3
+ metadata.gz: ac23678014708b3612c2b64182fc560e28fffaff546fe32068b6c80f92241a49
4
+ data.tar.gz: 1af3c1de510f8262df3074bbcb28af659ad233c0447feab33709ccafbb99bf9b
5
5
  SHA512:
6
- metadata.gz: 79f43ebe587deac54faf3745839fd0a39e13c62d9f8f00bcffb6f6aa23234d0fcec7b3b7be2d116cf4cb351d208837c8955b1d79e0382a1d42f94e3489c8c35f
7
- data.tar.gz: c697972d1a676d5f704f7d1b3f4160daeb1e0d72ee8841122e974b30f85ce63176195ef4fbf4258c6eb1f0be5b39bfe6c84effa9ba8bab3ad82f4d4fc5680805
6
+ metadata.gz: eb90480b721262fe38147e7f117ebd102ab05f9dc5435ef4fdf2263c0c4bb9b0886077f10ebb8f4b73db57e8cd751bad1e97f90917c5c3f4ad9b6714fd92212b
7
+ data.tar.gz: '0678b594744221149421bb72ed219ee9b916aca0e2ad58f4f7002fc94627d3d9aed6bcbaaca73cf8116eed7a0b7a5a5dd3f0c8a71cf5183a256d6af6471fe61d'
@@ -5,13 +5,14 @@ require 'discordrb/webhooks/embeds'
5
5
  module Discordrb::Webhooks
6
6
  # A class that acts as a builder for a webhook message object.
7
7
  class Builder
8
- def initialize(content: '', username: nil, avatar_url: nil, tts: false, file: nil, embeds: [])
8
+ def initialize(content: '', username: nil, avatar_url: nil, tts: false, file: nil, embeds: [], allowed_mentions: nil)
9
9
  @content = content
10
10
  @username = username
11
11
  @avatar_url = avatar_url
12
12
  @tts = tts
13
13
  @file = file
14
14
  @embeds = embeds
15
+ @allowed_mentions = allowed_mentions
15
16
  end
16
17
 
17
18
  # The content of the message. May be 2000 characters long at most.
@@ -70,6 +71,10 @@ module Discordrb::Webhooks
70
71
  # @return [Array<Embed>] the embeds attached to this message.
71
72
  attr_reader :embeds
72
73
 
74
+ # @return [Discordrb::AllowedMentions, Hash] Mentions that are allowed to ping in this message.
75
+ # @see https://discord.com/developers/docs/resources/channel#allowed-mentions-object
76
+ attr_accessor :allowed_mentions
77
+
73
78
  # @return [Hash] a hash representation of the created message, for JSON format.
74
79
  def to_json_hash
75
80
  {
@@ -77,7 +82,8 @@ module Discordrb::Webhooks
77
82
  username: @username,
78
83
  avatar_url: @avatar_url,
79
84
  tts: @tts,
80
- embeds: @embeds.map(&:to_hash)
85
+ embeds: @embeds.map(&:to_hash),
86
+ allowed_mentions: @allowed_mentions&.to_hash
81
87
  }
82
88
  end
83
89
 
@@ -88,7 +94,8 @@ module Discordrb::Webhooks
88
94
  username: @username,
89
95
  avatar_url: @avatar_url,
90
96
  tts: @tts,
91
- file: @file
97
+ file: @file,
98
+ allowed_mentions: @allowed_mentions&.to_hash
92
99
  }
93
100
  end
94
101
  end
@@ -38,33 +38,97 @@ module Discordrb::Webhooks
38
38
  # end
39
39
  # end
40
40
  # @return [RestClient::Response] the response returned by Discord.
41
- def execute(builder = nil, wait = false)
41
+ def execute(builder = nil, wait = false, components = nil)
42
42
  raise TypeError, 'builder needs to be nil or like a Discordrb::Webhooks::Builder!' unless
43
- builder.respond_to?(:file) && builder.respond_to?(:to_multipart_hash) || builder.respond_to?(:to_json_hash) || builder.nil?
43
+ (builder.respond_to?(:file) && builder.respond_to?(:to_multipart_hash)) || builder.respond_to?(:to_json_hash) || builder.nil?
44
44
 
45
45
  builder ||= Builder.new
46
+ view = View.new
46
47
 
47
- yield builder if block_given?
48
+ yield(builder, view) if block_given?
49
+
50
+ components ||= view
48
51
 
49
52
  if builder.file
50
- post_multipart(builder, wait)
53
+ post_multipart(builder, components, wait)
51
54
  else
52
- post_json(builder, wait)
55
+ post_json(builder, components, wait)
53
56
  end
54
57
  end
55
58
 
59
+ # Modify this webhook's properties.
60
+ # @param name [String, nil] The default name.
61
+ # @param avatar [String, #read, nil] The new avatar, in base64-encoded JPG format.
62
+ # @param channel_id [String, Integer, nil] The channel to move the webhook to.
63
+ # @return [RestClient::Response] the response returned by Discord.
64
+ def modify(name: nil, avatar: nil, channel_id: nil)
65
+ RestClient.patch(@url, { name: name, avatar: avatarise(avatar), channel_id: channel_id }.compact.to_json, content_type: :json)
66
+ end
67
+
68
+ # Delete this webhook.
69
+ # @param reason [String, nil] The reason this webhook was deleted.
70
+ # @return [RestClient::Response] the response returned by Discord.
71
+ # @note This is permanent and cannot be undone.
72
+ def delete(reason: nil)
73
+ RestClient.delete(@url, 'X-Audit-Log-Reason': reason)
74
+ end
75
+
76
+ # Edit a message from this webhook.
77
+ # @param message_id [String, Integer] The ID of the message to edit.
78
+ # @param builder [Builder, nil] The builder to start out with, or nil if one should be created anew.
79
+ # @param content [String] The message content.
80
+ # @param embeds [Array<Embed, Hash>]
81
+ # @param allowed_mentions [Hash]
82
+ # @return [RestClient::Response] the response returned by Discord.
83
+ # @example Edit message content
84
+ # client.edit_message(message_id, content: 'goodbye world!')
85
+ # @example Edit a message via builder
86
+ # client.edit_message(message_id) do |builder|
87
+ # builder.add_embed do |e|
88
+ # e.description = 'Hello World!'
89
+ # end
90
+ # end
91
+ # @note Not all builder options are available when editing.
92
+ def edit_message(message_id, builder: nil, content: nil, embeds: nil, allowed_mentions: nil)
93
+ builder ||= Builder.new
94
+
95
+ yield builder if block_given?
96
+
97
+ data = builder.to_json_hash.merge({ content: content, embeds: embeds, allowed_mentions: allowed_mentions }.compact)
98
+ RestClient.patch("#{@url}/messages/#{message_id}", data.compact.to_json, content_type: :json)
99
+ end
100
+
101
+ # Delete a message created by this webhook.
102
+ # @param message_id [String, Integer] The ID of the message to delete.
103
+ # @return [RestClient::Response] the response returned by Discord.
104
+ def delete_message(message_id)
105
+ RestClient.delete("#{@url}/messages/#{message_id}")
106
+ end
107
+
56
108
  private
57
109
 
58
- def post_json(builder, wait)
59
- RestClient.post(@url + (wait ? '?wait=true' : ''), builder.to_json_hash.to_json, content_type: :json)
110
+ # Convert an avatar to API ready data.
111
+ # @param avatar [String, #read] Avatar data.
112
+ def avatarise(avatar)
113
+ if avatar.respond_to? :read
114
+ "data:image/jpg;base64,#{Base64.strict_encode64(avatar.read)}"
115
+ else
116
+ avatar
117
+ end
118
+ end
119
+
120
+ def post_json(builder, components, wait)
121
+ data = builder.to_json_hash.merge({ components: components.to_a })
122
+ RestClient.post(@url + (wait ? '?wait=true' : ''), data.to_json, content_type: :json)
60
123
  end
61
124
 
62
- def post_multipart(builder, wait)
63
- RestClient.post(@url + (wait ? '?wait=true' : ''), builder.to_multipart_hash)
125
+ def post_multipart(builder, components, wait)
126
+ data = builder.to_multipart_hash.merge({ components: components.to_a })
127
+ RestClient.post(@url + (wait ? '?wait=true' : ''), data)
64
128
  end
65
129
 
66
130
  def generate_url(id, token)
67
- "https://discord.com/api/v6/webhooks/#{id}/#{token}"
131
+ "https://discord.com/api/v8/webhooks/#{id}/#{token}"
68
132
  end
69
133
  end
70
134
  end
@@ -51,7 +51,7 @@ module Discordrb::Webhooks
51
51
  elsif value.is_a? Array
52
52
  raise ArgumentError, 'Colour tuple must have three values!' if value.length != 3
53
53
 
54
- self.colour = value[0] << 16 | value[1] << 8 | value[2]
54
+ self.colour = (value[0] << 16) | (value[1] << 8) | value[2]
55
55
  else
56
56
  self.colour = value.to_i
57
57
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Modal component builder.
4
+ class Discordrb::Webhooks::Modal
5
+ # A mapping of names to types of components usable in a modal.
6
+ COMPONENT_TYPES = {
7
+ action_row: 1,
8
+ text_input: 4
9
+ }.freeze
10
+
11
+ # This builder is used when constructing an ActionRow. All current components must be within an action row, but this can
12
+ # change in the future. A message can have 5 action rows, each action row can hold a weight of 5. Buttons have a weight of 1,
13
+ # and dropdowns have a weight of 5.
14
+ class RowBuilder
15
+ # A mapping of short names to types of input styles. `short` is a single line where `paragraph` is a block.
16
+ TEXT_INPUT_STYLES = {
17
+ short: 1,
18
+ paragraph: 2
19
+ }.freeze
20
+
21
+ # @!visibility private
22
+ def initialize
23
+ @components = []
24
+ end
25
+
26
+ # Add a text input to this action row.
27
+ # @param style [Symbol, Integer] The text input's style type. See {TEXT_INPUT_STYLES}
28
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
29
+ # There is a limit of 100 characters to each custom_id.
30
+ # @param label [String, nil] The text label for the field.
31
+ # @param min_length [Integer, nil] The minimum input length for a text input, min 0, max 4000.
32
+ # @param max_length [Integer, nil] The maximum input length for a text input, min 1, max 4000.
33
+ # @param required [true, false, nil] Whether this component is required to be filled, default true.
34
+ # @param value [String, nil] A pre-filled value for this component, max 4000 characters.
35
+ # @param placeholder [String, nil] Custom placeholder text if the input is empty, max 100 characters
36
+ def text_input(style:, custom_id:, label: nil, min_length: nil, max_length: nil, required: nil, value: nil, placeholder: nil)
37
+ style = TEXT_INPUT_STYLES[style] || style
38
+
39
+ @components << {
40
+ style: style,
41
+ custom_id: custom_id,
42
+ type: COMPONENT_TYPES[:text_input],
43
+ label: label,
44
+ min_length: min_length,
45
+ max_length: max_length,
46
+ required: required,
47
+ value: value,
48
+ placeholder: placeholder
49
+ }
50
+ end
51
+
52
+ # @!visibility private
53
+ def to_h
54
+ { type: COMPONENT_TYPES[:action_row], components: @components }
55
+ end
56
+ end
57
+
58
+ attr_reader :rows
59
+
60
+ def initialize
61
+ @rows = []
62
+
63
+ yield self if block_given?
64
+ end
65
+
66
+ # Add a new ActionRow to the view
67
+ # @yieldparam [RowBuilder]
68
+ def row
69
+ new_row = RowBuilder.new
70
+
71
+ yield new_row
72
+
73
+ @rows << new_row
74
+ end
75
+
76
+ # @!visibility private
77
+ def to_a
78
+ @rows.map(&:to_h)
79
+ end
80
+ end
@@ -4,6 +4,6 @@
4
4
  module Discordrb
5
5
  module Webhooks
6
6
  # The current version of discordrb-webhooks.
7
- VERSION = '3.4.3'
7
+ VERSION = '3.5.0'
8
8
  end
9
9
  end
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A reusable view representing a component collection, with builder methods.
4
+ class Discordrb::Webhooks::View
5
+ # Possible button style names and values.
6
+ BUTTON_STYLES = {
7
+ primary: 1,
8
+ secondary: 2,
9
+ success: 3,
10
+ danger: 4,
11
+ link: 5
12
+ }.freeze
13
+
14
+ # Component types.
15
+ # @see https://discord.com/developers/docs/interactions/message-components#component-types
16
+ COMPONENT_TYPES = {
17
+ action_row: 1,
18
+ button: 2,
19
+ string_select: 3,
20
+ # text_input: 4, # (defined in modal.rb)
21
+ user_select: 5,
22
+ role_select: 6,
23
+ mentionable_select: 7,
24
+ channel_select: 8
25
+ }.freeze
26
+
27
+ # This builder is used when constructing an ActionRow. All current components must be within an action row, but this can
28
+ # change in the future. A message can have 5 action rows, each action row can hold a weight of 5. Buttons have a weight of 1,
29
+ # and dropdowns have a weight of 5.
30
+ class RowBuilder
31
+ # @!visibility private
32
+ def initialize
33
+ @components = []
34
+ end
35
+
36
+ # Add a button to this action row.
37
+ # @param style [Symbol, Integer] The button's style type. See {BUTTON_STYLES}
38
+ # @param label [String, nil] The text label for the button. Either a label or emoji must be provided.
39
+ # @param emoji [#to_h, String, Integer] An emoji ID, or unicode emoji to attach to the button. Can also be a object
40
+ # that responds to `#to_h` which returns a hash in the format of `{ id: Integer, name: string }`.
41
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
42
+ # There is a limit of 100 characters to each custom_id.
43
+ # @param disabled [true, false] Whether this button is disabled and shown as greyed out.
44
+ # @param url [String, nil] The URL, when using a link style button.
45
+ def button(style:, label: nil, emoji: nil, custom_id: nil, disabled: nil, url: nil)
46
+ style = BUTTON_STYLES[style] || style
47
+
48
+ emoji = case emoji
49
+ when Integer, String
50
+ emoji.to_i.positive? ? { id: emoji } : { name: emoji }
51
+ else
52
+ emoji.to_h
53
+ end
54
+
55
+ @components << { type: COMPONENT_TYPES[:button], label: label, emoji: emoji, style: style, custom_id: custom_id, disabled: disabled, url: url }
56
+ end
57
+
58
+ # Add a select string to this action row.
59
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
60
+ # There is a limit of 100 characters to each custom_id.
61
+ # @param options [Array<Hash>] Options that can be selected in this menu. Can also be provided via the yielded builder.
62
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
63
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
64
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
65
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
66
+ # @yieldparam builder [SelectMenuBuilder]
67
+ def string_select(custom_id:, options: [], placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
68
+ builder = SelectMenuBuilder.new(custom_id, options, placeholder, min_values, max_values, disabled, select_type: :string_select)
69
+
70
+ yield builder if block_given?
71
+
72
+ @components << builder.to_h
73
+ end
74
+
75
+ alias_method :select_menu, :string_select
76
+
77
+ # Add a select user to this action row.
78
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
79
+ # There is a limit of 100 characters to each custom_id.
80
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
81
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
82
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
83
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
84
+ def user_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
85
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :user_select).to_h
86
+ end
87
+
88
+ # Add a select role to this action row.
89
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
90
+ # There is a limit of 100 characters to each custom_id.
91
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
92
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
93
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
94
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
95
+ def role_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
96
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :role_select).to_h
97
+ end
98
+
99
+ # Add a select mentionable to this action row.
100
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
101
+ # There is a limit of 100 characters to each custom_id.
102
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
103
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
104
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
105
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
106
+ def mentionable_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
107
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :mentionable_select).to_h
108
+ end
109
+
110
+ # Add a select channel to this action row.
111
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
112
+ # There is a limit of 100 characters to each custom_id.
113
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
114
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
115
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
116
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
117
+ def channel_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
118
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :channel_select).to_h
119
+ end
120
+
121
+ # @!visibility private
122
+ def to_h
123
+ { type: COMPONENT_TYPES[:action_row], components: @components }
124
+ end
125
+ end
126
+
127
+ # A builder to assist in adding options to select menus.
128
+ class SelectMenuBuilder
129
+ # @!visibility hidden
130
+ def initialize(custom_id, options = [], placeholder = nil, min_values = nil, max_values = nil, disabled = nil, select_type: :string_select)
131
+ @custom_id = custom_id
132
+ @options = options
133
+ @placeholder = placeholder
134
+ @min_values = min_values
135
+ @max_values = max_values
136
+ @disabled = disabled
137
+ @select_type = select_type
138
+ end
139
+
140
+ # Add an option to this select menu.
141
+ # @param label [String] The title of this option.
142
+ # @param value [String] The value that this option represents.
143
+ # @param description [String, nil] An optional description of the option.
144
+ # @param emoji [#to_h, String, Integer] An emoji ID, or unicode emoji to attach to the button. Can also be a object
145
+ # that responds to `#to_h` which returns a hash in the format of `{ id: Integer, name: string }`.
146
+ # @param default [true, false, nil] Whether this is the default selected option.
147
+ def option(label:, value:, description: nil, emoji: nil, default: nil)
148
+ emoji = case emoji
149
+ when Integer, String
150
+ emoji.to_i.positive? ? { id: emoji } : { name: emoji }
151
+ else
152
+ emoji.to_h
153
+ end
154
+
155
+ @options << { label: label, value: value, description: description, emoji: emoji, default: default }
156
+ end
157
+
158
+ # @!visibility private
159
+ def to_h
160
+ {
161
+ type: COMPONENT_TYPES[@select_type],
162
+ options: @options,
163
+ placeholder: @placeholder,
164
+ min_values: @min_values,
165
+ max_values: @max_values,
166
+ custom_id: @custom_id,
167
+ disabled: @disabled
168
+ }
169
+ end
170
+ end
171
+
172
+ attr_reader :rows
173
+
174
+ def initialize
175
+ @rows = []
176
+
177
+ yield self if block_given?
178
+ end
179
+
180
+ # Add a new ActionRow to the view
181
+ # @yieldparam [RowBuilder]
182
+ def row
183
+ new_row = RowBuilder.new
184
+
185
+ yield new_row
186
+
187
+ @rows << new_row
188
+ end
189
+
190
+ # @!visibility private
191
+ def to_a
192
+ @rows.map(&:to_h)
193
+ end
194
+ end
@@ -4,6 +4,8 @@ require 'discordrb/webhooks/version'
4
4
  require 'discordrb/webhooks/embeds'
5
5
  require 'discordrb/webhooks/client'
6
6
  require 'discordrb/webhooks/builder'
7
+ require 'discordrb/webhooks/view'
8
+ require 'discordrb/webhooks/modal'
7
9
 
8
10
  module Discordrb
9
11
  # Webhook client
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discordrb-webhooks
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.3
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - meew0
@@ -36,11 +36,14 @@ files:
36
36
  - lib/discordrb/webhooks/builder.rb
37
37
  - lib/discordrb/webhooks/client.rb
38
38
  - lib/discordrb/webhooks/embeds.rb
39
+ - lib/discordrb/webhooks/modal.rb
39
40
  - lib/discordrb/webhooks/version.rb
41
+ - lib/discordrb/webhooks/view.rb
40
42
  homepage: https://github.com/shardlab/discordrb
41
43
  licenses:
42
44
  - MIT
43
- metadata: {}
45
+ metadata:
46
+ rubygems_mfa_required: 'true'
44
47
  post_install_message:
45
48
  rdoc_options: []
46
49
  require_paths:
@@ -49,7 +52,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
49
52
  requirements:
50
53
  - - ">="
51
54
  - !ruby/object:Gem::Version
52
- version: '2.5'
55
+ version: '2.7'
53
56
  required_rubygems_version: !ruby/object:Gem::Requirement
54
57
  requirements:
55
58
  - - ">="