discordrb 3.7.2 → 3.8.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.
@@ -3,23 +3,21 @@
3
3
  module Discordrb
4
4
  # Integration Account
5
5
  class IntegrationAccount
6
+ include IDObject
7
+
6
8
  # @return [String] this account's name.
7
9
  attr_reader :name
8
10
 
9
- # @return [Integer] this account's ID.
10
- attr_reader :id
11
-
12
11
  # @!visibility private
13
12
  def initialize(data)
14
- @name = data['name']
15
13
  @id = data['id'].to_i
14
+ @name = data['name']
16
15
  end
17
16
  end
18
17
 
19
18
  # Bot/OAuth2 application for discord integrations
20
19
  class IntegrationApplication
21
- # @return [Integer] the ID of the application.
22
- attr_reader :id
20
+ include IDObject
23
21
 
24
22
  # @return [String] the name of the application.
25
23
  attr_reader :name
@@ -30,9 +28,6 @@ module Discordrb
30
28
  # @return [String] the description of the application.
31
29
  attr_reader :description
32
30
 
33
- # @return [String] the summary of the application.
34
- attr_reader :summary
35
-
36
31
  # @return [User, nil] the bot associated with this application.
37
32
  attr_reader :bot
38
33
 
@@ -42,8 +37,7 @@ module Discordrb
42
37
  @name = data['name']
43
38
  @icon = data['icon']
44
39
  @description = data['description']
45
- @summary = data['summary']
46
- @bot = Discordrb::User.new(data['user'], bot) if data['user']
40
+ @bot = bot.ensure_user(data['bot']) if data['bot']
47
41
  end
48
42
  end
49
43
 
@@ -51,38 +45,50 @@ module Discordrb
51
45
  class Integration
52
46
  include IDObject
53
47
 
48
+ # Map of expire behaviors.
49
+ EXPIRE_BEHAVIORS = {
50
+ remove: 0,
51
+ kick: 1
52
+ }.freeze
53
+
54
54
  # @return [String] the integration name
55
55
  attr_reader :name
56
56
 
57
57
  # @return [Server] the server the integration is linked to
58
58
  attr_reader :server
59
59
 
60
- # @return [User] the user the integration is linked to
60
+ # @return [User, nil] the user who added the integration to the server. This will be `nil`
61
+ # for very old integrations, or if the integration was sent via a Gateway event.
61
62
  attr_reader :user
62
63
 
63
- # @return [Integer, nil] the role that this integration uses for "subscribers"
64
+ # @return [Integer, nil] the ID of the role that this integration uses for "subscribers"
64
65
  attr_reader :role_id
65
66
 
66
- # @return [true, false] whether emoticons are enabled
67
+ # @return [true, false] whether or not emoticons are enabled
67
68
  attr_reader :emoticon
68
69
  alias_method :emoticon?, :emoticon
70
+ alias_method :emoticons?, :emoticon
69
71
 
70
- # @return [String] the integration type (YouTube, Twitch, etc.)
72
+ # @return [String] the integration type (YouTube, Twitch, Discord, etc.)
71
73
  attr_reader :type
72
74
 
73
75
  # @return [true, false] whether the integration is enabled
74
76
  attr_reader :enabled
77
+ alias_method :enabled?, :enabled
75
78
 
76
- # @return [true, false] whether the integration is syncing
79
+ # @return [true, false] whether or not the integration is syncing
77
80
  attr_reader :syncing
81
+ alias_method :syncing?, :syncing
78
82
 
79
83
  # @return [IntegrationAccount] the integration account information
80
84
  attr_reader :account
81
85
 
82
- # @return [Time] the time the integration was synced at
86
+ # @return [Time, nil] the time the integration was last synced at
83
87
  attr_reader :synced_at
84
88
 
85
- # @return [Symbol] the behaviour of expiring subscribers (:remove = Remove User from role; :kick = Kick User from server)
89
+ # @return [Symbol, nil] the behaviour of expiring subscribers. When this is `:remove`, the
90
+ # associated role will be removed from the user. When this is `:kick`, the user will be
91
+ # kicked out of the server
86
92
  attr_reader :expire_behaviour
87
93
  alias_method :expire_behavior, :expire_behaviour
88
94
 
@@ -92,34 +98,47 @@ module Discordrb
92
98
  # @return [Integer, nil] how many subscribers this integration has.
93
99
  attr_reader :subscriber_count
94
100
 
95
- # @return [true, false] has this integration been revoked.
101
+ # @return [true, false] whether or not this integration been revoked.
96
102
  attr_reader :revoked
103
+ alias_method :revoked?, :revoked
104
+
105
+ # @return [IntegrationApplication, nil] the application for the integration.
106
+ attr_reader :application
107
+
108
+ # @return [Array<String>] the oauth2 scopes the application has been authorized for
109
+ attr_reader :scopes
97
110
 
98
111
  # @!visibility private
99
112
  def initialize(data, bot, server)
100
113
  @bot = bot
101
-
102
- @name = data['name']
103
114
  @server = server
104
115
  @id = data['id'].to_i
116
+ @name = data['name']
105
117
  @enabled = data['enabled']
106
- @syncing = data['syncing']
118
+ @syncing = data['syncing'] || false
107
119
  @type = data['type']
108
120
  @account = IntegrationAccount.new(data['account'])
109
- @synced_at = Time.parse(data['synced_at'])
110
- @expire_behaviour = %i[remove kick][data['expire_behavior']]
111
- @expire_grace_period = data['expire_grace_period']
112
- @user = @bot.ensure_user(data['user'])
121
+ @synced_at = Time.parse(data['synced_at']) if data['synced_at']
122
+ @expire_behaviour = EXPIRE_BEHAVIORS.key(data['expire_behavior']) if data['expire_behavior']
123
+ @expire_grace_period = data['expire_grace_period'] || 0
124
+ @user = @bot.ensure_user(data['user']) if data['user']
113
125
  @role_id = data['role_id']&.to_i
114
- @emoticon = data['enable_emoticons']
126
+ @emoticon = data['enable_emoticons'] || false
115
127
  @subscriber_count = data['subscriber_count']&.to_i
116
- @revoked = data['revoked']
128
+ @revoked = data['revoked'] || false
117
129
  @application = IntegrationApplication.new(data['application'], bot) if data['application']
130
+ @scopes = data['scopes'] || []
131
+ end
132
+
133
+ # Get the role that this integration uses for subscribers.
134
+ # @return [Role, nil] The role that this integration uses for subscribers.
135
+ def subscriber_role
136
+ @server.role(@role_id) if @role_id
118
137
  end
119
138
 
120
- # The inspect method is overwritten to give more useful output
139
+ # The inspect method is overwritten to give more useful output.
121
140
  def inspect
122
- "<Integration name=#{@name} id=#{@id} type=#{@type} enabled=#{@enabled}>"
141
+ "<Integration name=\"#{@name}\" id=#{@id} type=\"#{@type}\" enabled=#{@enabled}>"
123
142
  end
124
143
  end
125
144
  end
@@ -76,7 +76,7 @@ module Discordrb
76
76
  # @return [Integer] The maximum number of bytes an attachment can have when responding to this interaction.
77
77
  attr_reader :max_attachment_size
78
78
 
79
- # @return [Array<Symbol>] the features of the server where the interaction was initiated from.
79
+ # @return [Array<Symbol>] The features of the server where this interaction was initiated from.
80
80
  attr_reader :server_features
81
81
 
82
82
  # @!visibility private
@@ -86,7 +86,7 @@ module Discordrb
86
86
  @id = data['id'].to_i
87
87
  @application_id = data['application_id'].to_i
88
88
  @type = data['type']
89
- @message = data['message']
89
+ @message = Interactions::Message.new(data['message'], @bot, self) if data['message']
90
90
  @data = data['data']
91
91
  @server_id = data['guild_id']&.to_i
92
92
  @channel_id = data['channel_id']&.to_i
@@ -120,11 +120,13 @@ module Discordrb
120
120
  # @param ephemeral [true, false] Whether this message should only be visible to the interaction initiator.
121
121
  # @param wait [true, false] Whether this method should return a Message object of the interaction response.
122
122
  # @param components [Array<#to_h>] An array of components.
123
- # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`.
123
+ # @param attachments [Array<File>] Files that can be referenced in embeds and components via `attachment://file.png`.
124
+ # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables content and embeds.
124
125
  # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
125
126
  # @yieldparam view [Webhooks::View] A builder for creating interaction components.
126
- def respond(content: nil, tts: nil, embeds: nil, allowed_mentions: nil, flags: 0, ephemeral: nil, wait: false, components: nil, attachments: nil)
127
+ def respond(content: nil, tts: nil, embeds: nil, allowed_mentions: nil, flags: 0, ephemeral: nil, wait: false, components: nil, attachments: nil, has_components: false)
127
128
  flags |= 1 << 6 if ephemeral
129
+ flags |= (1 << 15) if has_components
128
130
 
129
131
  builder = Discordrb::Webhooks::Builder.new
130
132
  view = Discordrb::Webhooks::View.new
@@ -189,11 +191,13 @@ module Discordrb
189
191
  # @param ephemeral [true, false] Whether this message should only be visible to the interaction initiator.
190
192
  # @param wait [true, false] Whether this method should return a Message object of the interaction response.
191
193
  # @param components [Array<#to_h>] An array of components.
192
- # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`.
194
+ # @param attachments [Array<File>] Files that can be referenced in embeds and components via `attachment://file.png`.
195
+ # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables content and embeds.
193
196
  # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
194
197
  # @yieldparam view [Webhooks::View] A builder for creating interaction components.
195
- def update_message(content: nil, tts: nil, embeds: nil, allowed_mentions: nil, flags: 0, ephemeral: nil, wait: false, components: nil, attachments: nil)
198
+ def update_message(content: nil, tts: nil, embeds: nil, allowed_mentions: nil, flags: 0, ephemeral: nil, wait: false, components: nil, attachments: nil, has_components: false)
196
199
  flags |= 1 << 6 if ephemeral
200
+ flags |= (1 << 15) if has_components
197
201
 
198
202
  builder = Discordrb::Webhooks::Builder.new
199
203
  view = Discordrb::Webhooks::View.new
@@ -216,11 +220,15 @@ module Discordrb
216
220
  # @param content [String] The content of the message.
217
221
  # @param embeds [Array<Hash, Webhooks::Embed>] The embeds for the message.
218
222
  # @param allowed_mentions [Hash, AllowedMentions] Mentions that can ping on this message.
223
+ # @param flags [Integer] Message flags.
219
224
  # @param components [Array<#to_h>] An array of components.
220
- # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`.
225
+ # @param attachments [Array<File>] Files that can be referenced in embeds and components via `attachment://file.png`.
226
+ # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables content and embeds.
221
227
  # @return [InteractionMessage] The updated response message.
222
228
  # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
223
- def edit_response(content: nil, embeds: nil, allowed_mentions: nil, components: nil, attachments: nil)
229
+ def edit_response(content: nil, embeds: nil, allowed_mentions: nil, flags: 0, components: nil, attachments: nil, has_components: false)
230
+ flags |= (1 << 15) if has_components
231
+
224
232
  builder = Discordrb::Webhooks::Builder.new
225
233
  view = Discordrb::Webhooks::View.new
226
234
 
@@ -229,7 +237,7 @@ module Discordrb
229
237
 
230
238
  components ||= view
231
239
  data = builder.to_json_hash
232
- resp = Discordrb::API::Interaction.edit_original_interaction_response(@token, @application_id, data[:content], data[:embeds], data[:allowed_mentions], components.to_a, attachments)
240
+ resp = Discordrb::API::Interaction.edit_original_interaction_response(@token, @application_id, data[:content], data[:embeds], data[:allowed_mentions], components.to_a, attachments, flags)
233
241
 
234
242
  Interactions::Message.new(JSON.parse(resp), @bot, @interaction)
235
243
  end
@@ -245,10 +253,12 @@ module Discordrb
245
253
  # @param allowed_mentions [Hash, AllowedMentions] Mentions that can ping on this message.
246
254
  # @param flags [Integer] Message flags.
247
255
  # @param ephemeral [true, false] Whether this message should only be visible to the interaction initiator.
248
- # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`.
256
+ # @param attachments [Array<File>] Files that can be referenced in embeds and components via `attachment://file.png`.
257
+ # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables content and embeds.
249
258
  # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
250
- def send_message(content: nil, embeds: nil, tts: false, allowed_mentions: nil, flags: 0, ephemeral: false, components: nil, attachments: nil)
259
+ def send_message(content: nil, embeds: nil, tts: false, allowed_mentions: nil, flags: 0, ephemeral: false, components: nil, attachments: nil, has_components: false)
251
260
  flags |= 64 if ephemeral
261
+ flags |= (1 << 15) if has_components
252
262
 
253
263
  builder = Discordrb::Webhooks::Builder.new
254
264
  view = Discordrb::Webhooks::View.new
@@ -270,11 +280,15 @@ module Discordrb
270
280
  # @param embeds [Array<Hash, Webhooks::Embed>] The embeds for the message.
271
281
  # @param allowed_mentions [Hash, AllowedMentions] Mentions that can ping on this message.
272
282
  # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`.
283
+ # @param flags [Integer] Message flags.
284
+ # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables content and embeds.
273
285
  # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
274
- def edit_message(message, content: nil, embeds: nil, allowed_mentions: nil, components: nil, attachments: nil)
286
+ def edit_message(message, content: nil, embeds: nil, allowed_mentions: nil, components: nil, attachments: nil, flags: 0, has_components: false)
275
287
  builder = Discordrb::Webhooks::Builder.new
276
288
  view = Discordrb::Webhooks::View.new
277
289
 
290
+ flags |= (1 << 15) if has_components
291
+
278
292
  prepare_builder(builder, content, embeds, allowed_mentions)
279
293
  yield builder, view if block_given?
280
294
 
@@ -282,7 +296,7 @@ module Discordrb
282
296
  data = builder.to_json_hash
283
297
 
284
298
  resp = Discordrb::API::Webhook.token_edit_message(
285
- @token, @application_id, message.resolve_id, data[:content], data[:embeds], data[:allowed_mentions], components.to_a, attachments
299
+ @token, @application_id, message.resolve_id, data[:content], data[:embeds], data[:allowed_mentions], components.to_a, attachments, flags
286
300
  )
287
301
  Interactions::Message.new(JSON.parse(resp), @bot, @interaction)
288
302
  end
@@ -301,39 +315,38 @@ module Discordrb
301
315
  nil
302
316
  end
303
317
 
318
+ # Get the server associated with the interaction.
304
319
  # @return [Server, nil] This will be nil for interactions that occur in DM channels or servers where the bot
305
320
  # does not have the `bot` scope.
306
321
  def server
307
322
  @bot.server(@server_id)
308
323
  end
309
324
 
310
- # @return [Hash, nil] Returns the button that triggered this interaction if applicable, otherwise nil
325
+ # Get the button component that triggered the interaction.
326
+ # @return [Components::Button, nil] The button that triggered this interaction if applicable, otherwise `nil`.
311
327
  def button
312
- return unless @type == TYPES[:component]
313
-
314
- @message['components'].each do |row|
315
- Components::ActionRow.new(row, @bot).buttons.each do |button|
316
- return button if button.custom_id == @data['custom_id']
317
- end
318
- end
328
+ @type == TYPES[:component] ? get_component(@data['custom_id']) : nil
319
329
  end
320
330
 
321
- # @return [Array<TextInput>]
331
+ # Get the text input components associated with the interaction.
332
+ # @return [Array<TextInput>] The text input components associated with this interaction.
322
333
  def text_inputs
323
- @components&.select { |component| component.is_a? TextInput } | []
334
+ @components.filter_map do |entity|
335
+ entity.component if entity.is_a?(Components::Label) && entity.component.is_a?(Components::TextInput)
336
+ end
324
337
  end
325
338
 
326
- # @return [TextInput, Button, SelectMenu]
339
+ # Get a component by its custom ID.
340
+ # @param custom_id [String] the custom ID of the component to find.
341
+ # @return [TextInput, Button, SelectMenu, Checkbox, ModalActionGroup, nil] The component associated with the custom ID, or `nil`.
327
342
  def get_component(custom_id)
328
- top_level = @components.flat_map(&:components) || []
329
- message_level = (@message.instance_of?(Hash) ? Message.new(@message, @bot) : @message)&.components&.flat_map(&:components) || []
330
- components = top_level.concat(message_level)
331
- components.find { |component| component.custom_id == custom_id }
343
+ components = flatten_components((@message&.components || []) + @components)
344
+ components.find { |component| component.respond_to?(:custom_id) && component.custom_id == custom_id }
332
345
  end
333
346
 
334
347
  # @return [true, false] whether the application was installed by the user who initiated this interaction.
335
348
  def user_integration?
336
- @integration_owners[1] == @user_id
349
+ @integration_owners[1] == @user.id
337
350
  end
338
351
 
339
352
  # @return [true, false] whether the application was installed by the server where this interaction originates from.
@@ -353,6 +366,26 @@ module Discordrb
353
366
  builder.allowed_mentions = allowed_mentions
354
367
  embeds&.each { |embed| builder << embed }
355
368
  end
369
+
370
+ # @!visibility private
371
+ def flatten_components(components)
372
+ components = components.flat_map do |entity|
373
+ case entity
374
+ when Components::ActionRow
375
+ entity.components
376
+ when Components::Label
377
+ entity.component
378
+ when Components::Section
379
+ entity.accessory if entity.accessory.respond_to?(:custom_id)
380
+ when Components::Container
381
+ flatten_components(entity.components)
382
+ else
383
+ entity if entity.respond_to?(:custom_id)
384
+ end
385
+ end
386
+
387
+ components.compact
388
+ end
356
389
  end
357
390
 
358
391
  # An ApplicationCommand for slash commands.
@@ -82,9 +82,6 @@ module Discordrb
82
82
  # @return [Channel] the channel in which this message was sent.
83
83
  attr_reader :channel
84
84
 
85
- # @return [Time] the timestamp at which this message was sent.
86
- attr_reader :timestamp
87
-
88
85
  # @return [Time] the timestamp at which this message was edited. `nil` if the message was never edited.
89
86
  attr_reader :edited_timestamp
90
87
  alias_method :edit_timestamp, :edited_timestamp
@@ -161,11 +158,16 @@ module Discordrb
161
158
  @type = data['type']
162
159
  @tts = data['tts']
163
160
  @nonce = data['nonce']
161
+ @flags = data['flags'] || 0
162
+ @position = data['position'] || 0
164
163
  @mention_everyone = data['mention_everyone']
165
164
  @webhook_id = data['webhook_id']&.to_i
166
165
 
167
- @referenced_message = Message.new(data['referenced_message'], bot) if data['referenced_message']
166
+ @edited_timestamp = Time.parse(data['edited_timestamp']) if data['edited_timestamp']
167
+ @edited = !@edited_timestamp.nil?
168
+
168
169
  @message_reference = data['message_reference']
170
+ @referenced_message = Message.new(data['referenced_message'], @bot) if data['referenced_message']
169
171
 
170
172
  if data['author']
171
173
  if @webhook_id
@@ -177,56 +179,31 @@ module Discordrb
177
179
 
178
180
  # Turn the message user into a recipient - we can't use the channel recipient
179
181
  # directly because the bot may also send messages to the channel
180
- @author = Recipient.new(bot.user(data['author']['id'].to_i), @channel, bot)
182
+ @author = Recipient.new(@bot.user(data['author']['id'].to_i), @channel, @bot)
181
183
  else
182
184
  @author_id = data['author']['id'].to_i
183
185
  end
184
186
  end
185
187
 
186
- @timestamp = Time.parse(data['timestamp']) if data['timestamp']
187
- @edited_timestamp = data['edited_timestamp'].nil? ? nil : Time.parse(data['edited_timestamp'])
188
- @edited = !@edited_timestamp.nil?
189
-
190
- @emoji = []
191
-
192
- @reactions = []
193
-
194
- data['reactions']&.each do |element|
195
- @reactions << Reaction.new(element)
196
- end
197
-
198
- @mentions = []
199
-
200
- data['mentions']&.each do |element|
201
- @mentions << bot.ensure_user(element)
202
- end
203
-
188
+ @reactions = data['reactions']&.map { |reaction| Reaction.new(reaction) } || []
189
+ @mentions = data['mentions']&.map { |mention| @bot.ensure_user(mention) } || []
204
190
  @mention_roles = data['mention_roles']&.map(&:to_i) || []
205
191
 
206
- @attachments = []
207
- @attachments = data['attachments'].map { |e| Attachment.new(e, self, @bot) } if data['attachments']
208
-
209
- @embeds = []
210
- @embeds = data['embeds'].map { |e| Embed.new(e, self) } if data['embeds']
211
-
212
- @components = []
213
- @components = data['components'].map { |component_data| Components.from_data(component_data, @bot) } if data['components']
214
-
215
- @flags = data['flags'] || 0
216
-
217
- @thread = data['thread'] ? @bot.ensure_channel(data['thread']) : nil
218
-
219
- @pinned_at = data['pinned_at'] ? Time.parse(data['pinned_at']) : nil
192
+ @attachments = data['attachments']&.map { |attachment| Attachment.new(attachment, self, @bot) } || []
193
+ @embeds = data['embeds']&.map { |embed| Embed.new(embed, self) } || []
194
+ @components = data['components']&.map { |component| Components.from_data(component, @bot) } || []
220
195
 
221
- @call = data['call'] ? Call.new(data['call'], @bot) : nil
196
+ @thread = @bot.ensure_channel(data['thread']) if data['thread']
197
+ @pinned_at = Time.parse(data['pinned_at']) if data['pinned_at']
198
+ @call = Call.new(data['call'], @bot) if data['call']
222
199
 
223
200
  @snapshots = data['message_snapshots']&.map { |snapshot| Snapshot.new(snapshot['message'], @bot) } || []
224
-
225
201
  @role_subscription = RoleSubscriptionData.new(data['role_subscription_data'], self, @bot) if data['role_subscription_data']
226
-
227
- @position = data['position'] || 0
228
202
  end
229
203
 
204
+ # @deprecated Please migrate to using {#creation_time} instead.
205
+ alias_method :timestamp, :creation_time
206
+
230
207
  # @return [Member, User] the user that sent this message. (Will be a {Member} most of the time, it should only be a
231
208
  # {User} for old messages when the author has left the server since then)
232
209
  def author
@@ -377,18 +354,21 @@ module Discordrb
377
354
 
378
355
  # @return [Array<Emoji>] the emotes that were used/mentioned in this message.
379
356
  def emoji
380
- return if @content.nil?
381
- return @emoji unless @emoji.empty?
357
+ return [] if @content.empty? || @content.nil?
382
358
 
383
- @emoji = @bot.parse_mentions(@content).select { |el| el.is_a? Discordrb::Emoji }
359
+ @emoji ||= @bot.parse_mentions(@content).select { |mention| mention.is_a?(Discordrb::Emoji) }
384
360
  end
385
361
 
362
+ alias_method :emojis, :emoji
363
+
386
364
  # Check if any emoji were used in this message.
387
365
  # @return [true, false] whether or not any emoji were used
388
366
  def emoji?
389
- emoji&.empty?
367
+ emoji.any?
390
368
  end
391
369
 
370
+ alias_method :emojis?, :emoji?
371
+
392
372
  # Check if any reactions were used in this message.
393
373
  # @return [true, false] whether or not this message has reactions
394
374
  def reactions?
@@ -529,16 +509,18 @@ module Discordrb
529
509
 
530
510
  # @return [Array<Components::Button>]
531
511
  def buttons
532
- results = @components.collect do |component|
512
+ buttons = @components.flat_map do |component|
533
513
  case component
534
514
  when Components::Button
535
515
  component
536
- when Components::ActionRow
516
+ when Components::Section
517
+ component.accessory if component.accessory.is_a?(Components::Button)
518
+ when Components::ActionRow, Components::Container
537
519
  component.buttons
538
520
  end
539
521
  end
540
522
 
541
- results.flatten.compact
523
+ buttons.compact
542
524
  end
543
525
 
544
526
  # to_message -> self or message
@@ -54,5 +54,11 @@ module Discordrb
54
54
  def to_s
55
55
  id.nil? ? name : "#{name}:#{id}"
56
56
  end
57
+
58
+ # Converts this Reaction into a hash that can be sent back to Discord in other endpoints.
59
+ # @return [Hash] A hash representation of this reaction's emoji.
60
+ def to_h
61
+ id.nil? ? { name: name } : { id: id }
62
+ end
57
63
  end
58
64
  end
@@ -158,7 +158,8 @@ module Discordrb
158
158
  member(@bot.profile)
159
159
  end
160
160
 
161
- # @return [Array<Integration>] an array of all the integrations connected to this server.
161
+ # @return [Array<Integration>] an array of the integrations in this server.
162
+ # @note If the server has more than 50 integrations, they cannot be accessed.
162
163
  def integrations
163
164
  integration = JSON.parse(API::Server.integrations(@bot.token, @id))
164
165
  integration.map { |element| Integration.new(element, @bot, self) }
@@ -921,6 +922,19 @@ module Discordrb
921
922
  process_emoji(new_data['emojis'])
922
923
  end
923
924
 
925
+ # Updates the threads for this server's cache
926
+ # @note For internal use only
927
+ # @!visibility private
928
+ def clear_threads(ids = nil)
929
+ if ids.nil?
930
+ @channels.reject!(&:thread?)
931
+ @channels_by_id.delete_if { |_, channel| channel.thread? }
932
+ else
933
+ @channels.reject! { |channel| channel.thread? && ids.any?(channel.parent&.id) }
934
+ @channels_by_id.delete_if { |_, channel| channel.thread? && ids.any?(channel.parent&.id) }
935
+ end
936
+ end
937
+
924
938
  # The inspect method is overwritten to give more useful output
925
939
  def inspect
926
940
  "<Server name=#{@name} id=#{@id} large=#{@large} region=#{@region} owner=#{@owner} afk_channel_id=#{@afk_channel_id} system_channel_id=#{@system_channel_id} afk_timeout=#{@afk_timeout}>"
@@ -38,11 +38,11 @@ module Discordrb
38
38
  @content = data['content']
39
39
  @mention_roles = data['mention_roles']&.map(&:resolve_id) || []
40
40
  @embeds = data['embeds']&.map { |embed| Embed.new(embed, self) } || []
41
- @attachments = data['attachments']&.map { |file| Attachment.new(file, self, bot) } || []
41
+ @attachments = data['attachments']&.map { |file| Attachment.new(file, self, @bot) } || []
42
42
  @created_at = data['timestamp'] ? Time.parse(data['timestamp']) : nil
43
43
  @edited_at = data['edited_timestamp'] ? Time.parse(data['edited_timestamp']) : nil
44
- @mentions = data['mentions']&.map { |mention| bot.ensure_user(mention) } || []
45
- @components = data['components']&.map { |component| Components.from_data(component, bot) } || []
44
+ @mentions = data['mentions']&.map { |mention| @bot.ensure_user(mention) } || []
45
+ @components = data['components']&.map { |component| Components.from_data(component, @bot) } || []
46
46
  end
47
47
 
48
48
  # Check whether the message snapshot has been edited.
@@ -85,7 +85,9 @@ module Discordrb
85
85
  case component
86
86
  when Components::Button
87
87
  component
88
- when Components::ActionRow
88
+ when Components::Section
89
+ component.accessory if component.accessory.is_a?(Components::Button)
90
+ when Components::ActionRow, Components::Container
89
91
  component.buttons
90
92
  end
91
93
  end
@@ -136,7 +136,7 @@ module Discordrb
136
136
  # @return [Message, nil] If `wait` is `true`, a {Message} will be returned. Otherwise this method will return `nil`.
137
137
  # @note This is only available to webhooks with publically exposed tokens. This excludes channel follow webhooks and webhooks retrieved
138
138
  # via the audit log.
139
- def execute(content: nil, username: nil, avatar_url: nil, tts: nil, file: nil, embeds: nil, allowed_mentions: nil, wait: true, builder: nil, components: nil)
139
+ def execute(content: nil, username: nil, avatar_url: nil, tts: nil, file: nil, embeds: nil, allowed_mentions: nil, wait: true, builder: nil, components: nil, flags: 0, has_components: false)
140
140
  raise Discordrb::Errors::UnauthorizedWebhook unless @token
141
141
 
142
142
  params = { content: content, username: username, avatar_url: avatar_url, tts: tts, file: file, embeds: embeds, allowed_mentions: allowed_mentions }
@@ -144,12 +144,14 @@ module Discordrb
144
144
  builder ||= Webhooks::Builder.new
145
145
  view = Webhooks::View.new
146
146
 
147
+ flags |= (1 << 15) if has_components
148
+
147
149
  yield(builder, view) if block_given?
148
150
 
149
151
  data = builder.to_json_hash.merge(params.compact)
150
152
  components ||= view
151
153
 
152
- resp = API::Webhook.token_execute_webhook(@token, @id, wait, data[:content], data[:username], data[:avatar_url], data[:tts], data[:file], data[:embeds], data[:allowed_mentions], nil, components.to_a)
154
+ resp = API::Webhook.token_execute_webhook(@token, @id, wait, data[:content], data[:username], data[:avatar_url], data[:tts], data[:file], data[:embeds], data[:allowed_mentions], flags, components.to_a)
153
155
 
154
156
  Message.new(JSON.parse(resp), @bot) if wait
155
157
  end
@@ -173,7 +175,7 @@ module Discordrb
173
175
  # @return [Message] The updated message.
174
176
  # @param components [View, Array<Hash>] Interaction components to associate with this message.
175
177
  # @note When editing `allowed_mentions`, it will update visually in the client but not alert the user with a notification.
176
- def edit_message(message, content: nil, embeds: nil, allowed_mentions: nil, builder: nil, components: nil)
178
+ def edit_message(message, content: nil, embeds: nil, allowed_mentions: nil, builder: nil, components: nil, flags: 0, has_components: false)
177
179
  raise Discordrb::Errors::UnauthorizedWebhook unless @token
178
180
 
179
181
  params = { content: content, embeds: embeds, allowed_mentions: allowed_mentions }.compact
@@ -181,12 +183,14 @@ module Discordrb
181
183
  builder ||= Webhooks::Builder.new
182
184
  view ||= Webhooks::View.new
183
185
 
186
+ flags |= (1 << 15) if has_components
187
+
184
188
  yield(builder, view) if block_given?
185
189
 
186
190
  data = builder.to_json_hash.merge(params.compact)
187
191
  components ||= view
188
192
 
189
- resp = API::Webhook.token_edit_message(@token, @id, message.resolve_id, data[:content], data[:embeds], data[:allowed_mentions], components.to_a)
193
+ resp = API::Webhook.token_edit_message(@token, @id, message.resolve_id, data[:content], data[:embeds], data[:allowed_mentions], components.to_a, nil, flags)
190
194
  Message.new(JSON.parse(resp), @bot)
191
195
  end
192
196