discordrb 3.7.1 → 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.
@@ -165,6 +165,8 @@ module Discordrb
165
165
  @unicode_emoji = other.unicode_emoji
166
166
  @secondary_colour = other.secondary_colour
167
167
  @tertiary_colour = other.tertiary_colour
168
+ @mentionable = other.mentionable?
169
+ @tags = other.tags
168
170
  end
169
171
 
170
172
  # Updates the data cache from a hash containing data
@@ -179,14 +181,16 @@ module Discordrb
179
181
  @mentionable = new_data['mentionable']
180
182
  @flags = new_data['flags']
181
183
  colours = new_data['colors']
184
+ @managed = new_data['managed']
182
185
  @permissions.bits = new_data['permissions'].to_i
183
186
  @colour = ColourRGB.new(colours['primary_color'])
187
+ @tags = Tags.new(new_data['tags']) if new_data['tags']
184
188
  @secondary_color = ColourRGB.new(colours['secondary_color']) if colours['secondary_color']
185
189
  @tertiary_colour = ColourRGB.new(colours['tertiary_color']) if colours['tertiary_color']
186
190
  end
187
191
 
188
192
  # Sets the role name to something new
189
- # @param name [String] The name that should be set
193
+ # @param name [String, nil] The name that should be set.
190
194
  def name=(name)
191
195
  update_role_data(name: name)
192
196
  end
@@ -206,7 +210,7 @@ module Discordrb
206
210
  # Sets the primary role colour to something new.
207
211
  # @param colour [ColourRGB, Integer, nil] The new colour.
208
212
  def colour=(colour)
209
- update_colors(primary: colour)
213
+ update_colours(primary: colour)
210
214
  end
211
215
 
212
216
  # Sets the secondary role colour to something new.
@@ -293,7 +297,7 @@ module Discordrb
293
297
  # https://discord.com/developers/docs/topics/permissions.
294
298
  # @example Remove all permissions from a role
295
299
  # role.packed = 0
296
- # @param packed [Integer] A bitfield with the desired permissions value.
300
+ # @param packed [Integer, nil] A bitfield with the desired permissions value.
297
301
  # @param update_perms [true, false] Whether the internal data should also be updated. This should always be true
298
302
  # when calling externally.
299
303
  def packed=(packed, update_perms = true)
@@ -305,17 +309,9 @@ module Discordrb
305
309
  # @param other [Role, String, Integer, nil] The role, or its ID, above which this role should be moved. If it is `nil`,
306
310
  # the role will be moved above the @everyone role.
307
311
  # @return [Integer] the new position of this role
312
+ # @deprecated Please migrate to using {#move} with the `above` or `below` KWARGS.
308
313
  def sort_above(other = nil)
309
- other = @server.role(other.resolve_id) if other
310
- roles = @server.roles.sort_by(&:position)
311
- roles.delete_at(@position)
312
-
313
- index = other ? roles.index { |role| role.id == other.id } + 1 : 1
314
- roles.insert(index, self)
315
-
316
- updated_roles = roles.map.with_index { |role, position| { id: role.id, position: position } }
317
- @server.update_role_positions(updated_roles)
318
- index
314
+ other ? move(above: other) : move(bottom: true)
319
315
  end
320
316
 
321
317
  alias_method :move_above, :sort_above
@@ -327,13 +323,69 @@ module Discordrb
327
323
  @server.delete_role(@id)
328
324
  end
329
325
 
326
+ # Move the position of this role in the roles list.
327
+ # @example This will move the role 2 places above the `@everyone` role.
328
+ # role.move(bottom: true, offset: 2)
329
+ # @example This will move the role above the `@muted` role.
330
+ # role.move(above: 257017090932867072)
331
+ # @example This will move the role 3 spots below the `No Images` role.
332
+ # roles.move(below: 254077236989132800, offset: -3)
333
+ # @param bottom [true, false, nil] Whether to move the roles to the bottom of the role list.
334
+ # @param above [Integer, String, Role, nil] The role that this role should be moved above.
335
+ # @param below [Integer, String, Role, nil] The role that this role should be moved below.
336
+ # @param offset [Integer, nil] The number of roles to offset the new position by. A positive number will
337
+ # move the role above, and a negative number will move the role below. This parameter is relative and
338
+ # calculated after the `bottom`, `above`, and `below` parameters.
339
+ # @param reason [String, nil] The audit log reason to show for moving the role.
340
+ # @return [Integer] the new position of the role.
341
+ def move(bottom: nil, above: nil, below: nil, offset: 0, reason: nil)
342
+ # rubocop:disable Style/IfUnlessModifier
343
+ if [bottom, above, below].count(&:itself) > 1
344
+ raise ArgumentError, "'bottom', 'above', and 'below' are mutually exclusive"
345
+ end
346
+
347
+ if (above || below) && !(target = @server.role(above || below))
348
+ raise ArgumentError, "The given 'above' or 'below' options are not valid"
349
+ end
350
+
351
+ if (below && target&.id == @server.id) || (@id == target&.id)
352
+ raise ArgumentError, 'The target role that was provded is not valid'
353
+ end
354
+
355
+ # rubocop:enable Style/IfUnlessModifier
356
+ roles = @server.roles.uniq.sort_by { |role| [role.position, role.id] }
357
+
358
+ # Make sure we remove the current role.
359
+ myself = roles.rindex(self).tap { |index| roles.delete_at(index) }
360
+
361
+ index = if bottom
362
+ 1
363
+ elsif below
364
+ roles.rindex(target)
365
+ elsif above
366
+ roles.rindex(target) + 1
367
+ else
368
+ myself
369
+ end
370
+
371
+ roles.insert([index + (offset || 0), 1].max, self)
372
+
373
+ roles = roles.map.with_index do |role, new_position|
374
+ { id: role.resolve_id, position: new_position }
375
+ end
376
+
377
+ @server.update_role_positions(roles, reason: reason)
378
+ @position
379
+ end
380
+
330
381
  # A rich interface designed to make working with role colours simple.
331
382
  # @param primary [ColourRGB, Integer, nil] The new primary/base colour of this role, or nil to clear the primary colour.
332
383
  # @param secondary [ColourRGB, Integer, nil] The new secondary colour of this role, or nil to clear the secondary colour.
333
384
  # @param tertiary [ColourRGB, Integer,nil] The new tertiary colour of this role, or nil to clear the tertiary colour.
334
385
  # @param holographic [true, false] Whether to apply or remove the holographic style to the role colour, overriding any other
335
386
  # arguments that were passed. Using this argument is recommended over passing individual colours.
336
- def update_colours(primary: :undef, secondary: :undef, tertiary: :undef, holographic: :undef)
387
+ # @param reason [String, nil] The audit log reason to show for updating the role's colours.
388
+ def update_colours(primary: :undef, secondary: :undef, tertiary: :undef, holographic: :undef, reason: nil)
337
389
  colours = {
338
390
  primary_color: (primary == :undef ? @colour : primary)&.to_i,
339
391
  tertiary_color: (tertiary == :undef ? @tertiary_colour : tertiary)&.to_i,
@@ -347,9 +399,9 @@ module Discordrb
347
399
  }
348
400
 
349
401
  # Only set the tertiary_color to `nil` if holographic is explicitly set to false.
350
- colours[:tertiary_color] = nil if holographic.is_a?(FalseClass) && holographic?
402
+ (colours[:tertiary_color] = nil) if holographic.is_a?(FalseClass)
351
403
 
352
- update_role_data(colours: holographic == true ? holographic_colours : colours)
404
+ update_role_data(colours: holographic == true ? holographic_colours : colours, reason: reason)
353
405
  end
354
406
 
355
407
  alias_method :update_colors, :update_colours
@@ -361,14 +413,15 @@ module Discordrb
361
413
 
362
414
  private
363
415
 
416
+ # @!visibility private
364
417
  def update_role_data(new_data)
365
418
  update_data(JSON.parse(API::Server.update_role(@bot.token, @server.id, @id,
366
- new_data[:name] || @name,
419
+ new_data.key?(:name) ? new_data[:name] : :undef,
367
420
  :undef,
368
421
  new_data.key?(:hoist) ? new_data[:hoist] : :undef,
369
422
  new_data.key?(:mentionable) ? new_data[:mentionable] : :undef,
370
- new_data[:permissions] || @permissions.bits,
371
- nil,
423
+ new_data.key?(:permissions) ? new_data[:permissions] : :undef,
424
+ new_data[:reason],
372
425
  new_data.key?(:icon) ? new_data[:icon] : :undef,
373
426
  new_data.key?(:unicode_emoji) ? new_data[:unicode_emoji] : :undef,
374
427
  new_data.key?(:colours) ? new_data[:colours] : :undef)))
@@ -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) }
@@ -412,11 +413,11 @@ module Discordrb
412
413
  # Updates the positions of all roles on the server
413
414
  # @note For internal use only
414
415
  # @!visibility private
415
- def update_role_positions(role_positions)
416
- response = JSON.parse(API::Server.update_role_positions(@bot.token, @id, role_positions))
416
+ def update_role_positions(role_positions, reason: nil)
417
+ response = JSON.parse(API::Server.update_role_positions(@bot.token, @id, role_positions, reason))
417
418
  response.each do |data|
418
419
  updated_role = Role.new(data, @bot, self)
419
- role(updated_role.id).update_from(updated_role)
420
+ role(updated_role.id)&.update_from(updated_role)
420
421
  end
421
422
  end
422
423
 
@@ -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
 
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'discordrb/data'
4
+ require 'discordrb/events/generic'
5
+
6
+ module Discordrb::Events
7
+ # Generic superclass for integration events.
8
+ class IntegrationEvent < Event
9
+ # @return [Server] the server associated with the event.
10
+ attr_reader :server
11
+
12
+ # @return [Integration] the integration associated with the event.
13
+ attr_reader :integration
14
+
15
+ # @!visibility private
16
+ def initialize(data, bot)
17
+ @bot = bot
18
+ @server = bot.server(data['guild_id'].to_i)
19
+ @integration = Discordrb::Integration.new(data, @bot, @server)
20
+ end
21
+ end
22
+
23
+ # Raised whenever an integration is created.
24
+ class IntegrationCreateEvent < IntegrationEvent; end
25
+
26
+ # Raised whenever an integration is updated.
27
+ class IntegrationUpdateEvent < IntegrationEvent; end
28
+
29
+ # Raised whenever an integration is deleted.
30
+ class IntegrationDeleteEvent < Event
31
+ # @return [Server] the server associated with the event.
32
+ attr_reader :server
33
+
34
+ # @return [Integer] the ID of the integration that was removed.
35
+ attr_reader :integration_id
36
+
37
+ # @return [Integer, nil] the ID of the application that was removed.
38
+ attr_reader :application_id
39
+
40
+ # @!visibility private
41
+ def initialize(data, bot)
42
+ @bot = bot
43
+ @server = bot.server(data['guild_id'].to_i)
44
+ @integration_id = data['id'].to_i
45
+ @application_id = data['application_id']&.to_i
46
+ end
47
+ end
48
+
49
+ # Generic event handler for integration events.
50
+ class IntegrationEventHandler < EventHandler
51
+ # @!visibility private
52
+ def matches?(event)
53
+ # Check for the proper event type.
54
+ return false unless event.is_a?(IntegrationEvent)
55
+
56
+ [
57
+ matches_all(@attributes[:server], event.server) do |a, e|
58
+ a&.resolve_id == e&.resolve_id
59
+ end,
60
+
61
+ matches_all(@attributes[:id], event.integration) do |a, e|
62
+ a&.resolve_id == e&.resolve_id
63
+ end,
64
+
65
+ matches_all(@attributes[:application], event.integration) do |a, e|
66
+ a&.resolve_id == e.application&.resolve_id
67
+ end
68
+ ].reduce(true, &:&)
69
+ end
70
+ end
71
+
72
+ # Event handler for INTEGRATION_CREATE events.
73
+ class IntegrationCreateEventHandler < IntegrationEventHandler; end
74
+
75
+ # Event handler for INTEGRATION_UPDATE events.
76
+ class IntegrationUpdateEventHandler < IntegrationEventHandler; end
77
+
78
+ # Event handler for INTEGRATION_DELETE events.
79
+ class IntegrationDeleteEventHandler < EventHandler
80
+ # @!visibility private
81
+ def matches?(event)
82
+ # Check for the proper event type.
83
+ return false unless event.is_a?(IntegrationDeleteEvent)
84
+
85
+ [
86
+ matches_all(@attributes[:server], event.server) do |a, e|
87
+ a&.resolve_id == e&.resolve_id
88
+ end,
89
+
90
+ matches_all(@attributes[:id], event.integration_id) do |a, e|
91
+ a&.resolve_id == e&.resolve_id
92
+ end,
93
+
94
+ matches_all(@attributes[:application], event.application_id) do |a, e|
95
+ a&.resolve_id == e&.resolve_id
96
+ end
97
+ ].reduce(true, &:&)
98
+ end
99
+ end
100
+ end
@@ -6,6 +6,9 @@ require 'discordrb/data'
6
6
  module Discordrb::Events
7
7
  # Generic subclass for interaction events
8
8
  class InteractionCreateEvent < Event
9
+ # Struct to allow accessing data via [] or methods.
10
+ Resolved = Struct.new('Resolved', :channels, :members, :messages, :roles, :users, :attachments) # rubocop:disable Lint/StructNewOverride
11
+
9
12
  # @return [Interaction] The interaction for this event.
10
13
  attr_reader :interaction
11
14
 
@@ -33,7 +36,13 @@ module Discordrb::Events
33
36
  # @!attribute [r] context
34
37
  # @return [Integer]
35
38
  # @see Interaction#context
36
- delegate :type, :server, :server_id, :channel, :channel_id, :user, :user_locale, :context, to: :interaction
39
+ # @!attribute [r] user_integration?
40
+ # @return [true, false]
41
+ # @see Interaction#user_integration?
42
+ # @!attribute [r] server_integration?
43
+ # @return [true, false]
44
+ # @see Interaction#server_integration?
45
+ delegate :type, :server, :server_id, :channel, :channel_id, :user, :user_locale, :context, :user_integration?, :server_integration?, to: :interaction
37
46
 
38
47
  # @!visibility private
39
48
  def initialize(data, bot)
@@ -95,6 +104,38 @@ module Discordrb::Events
95
104
  def get_component(...)
96
105
  @interaction.get_component(...)
97
106
  end
107
+
108
+ private
109
+
110
+ # @!visibility private
111
+ def process_resolved(resolved_data)
112
+ resolved_data['users']&.each do |id, data|
113
+ @resolved[:users][id.to_i] = @bot.ensure_user(data)
114
+ end
115
+
116
+ resolved_data['roles']&.each do |id, data|
117
+ @resolved[:roles][id.to_i] = Discordrb::Role.new(data, @bot)
118
+ end
119
+
120
+ resolved_data['channels']&.each do |id, data|
121
+ data['guild_id'] = @interaction.server_id
122
+ @resolved[:channels][id.to_i] = Discordrb::Channel.new(data, @bot)
123
+ end
124
+
125
+ resolved_data['members']&.each do |id, data|
126
+ data['user'] = resolved_data['users'][id]
127
+ data['guild_id'] = @interaction.server_id
128
+ @resolved[:members][id.to_i] = Discordrb::Member.new(data, nil, @bot)
129
+ end
130
+
131
+ resolved_data['messages']&.each do |id, data|
132
+ @resolved[:messages][id.to_i] = Discordrb::Message.new(data, @bot)
133
+ end
134
+
135
+ resolved_data['attachments']&.each do |id, data|
136
+ @resolved[:attachments][id.to_i] = Discordrb::Attachment.new(data, nil, @bot)
137
+ end
138
+ end
98
139
  end
99
140
 
100
141
  # Event handler for INTERACTION_CREATE events.
@@ -130,9 +171,6 @@ module Discordrb::Events
130
171
 
131
172
  # Event for ApplicationCommand interactions.
132
173
  class ApplicationCommandEvent < InteractionCreateEvent
133
- # Struct to allow accessing data via [] or methods.
134
- Resolved = Struct.new('Resolved', :channels, :members, :messages, :roles, :users, :attachments) # rubocop:disable Lint/StructNewOverride
135
-
136
174
  # @return [Symbol] The name of the command.
137
175
  attr_reader :command_name
138
176
 
@@ -145,7 +183,7 @@ module Discordrb::Events
145
183
  # @return [Symbol, nil] The name of the subcommand relevant to this event.
146
184
  attr_reader :subcommand
147
185
 
148
- # @return [Resolved]
186
+ # @return [Resolved] The resolved channels, roles, users, members, and attachments for this event.
149
187
  attr_reader :resolved
150
188
 
151
189
  # @return [Hash<Symbol, Object>] Arguments provided to the command, mapped as `Name => Value`.
@@ -198,35 +236,6 @@ module Discordrb::Events
198
236
 
199
237
  private
200
238
 
201
- def process_resolved(resolved_data)
202
- resolved_data['users']&.each do |id, data|
203
- @resolved[:users][id.to_i] = @bot.ensure_user(data)
204
- end
205
-
206
- resolved_data['roles']&.each do |id, data|
207
- @resolved[:roles][id.to_i] = Discordrb::Role.new(data, @bot)
208
- end
209
-
210
- resolved_data['channels']&.each do |id, data|
211
- data['guild_id'] = @interaction.server_id
212
- @resolved[:channels][id.to_i] = Discordrb::Channel.new(data, @bot)
213
- end
214
-
215
- resolved_data['members']&.each do |id, data|
216
- data['user'] = resolved_data['users'][id]
217
- data['guild_id'] = @interaction.server_id
218
- @resolved[:members][id.to_i] = Discordrb::Member.new(data, nil, @bot)
219
- end
220
-
221
- resolved_data['messages']&.each do |id, data|
222
- @resolved[:messages][id.to_i] = Discordrb::Message.new(data, @bot)
223
- end
224
-
225
- resolved_data['attachments']&.each do |id, data|
226
- @resolved[:attachments][id.to_i] = Discordrb::Attachment.new(data, nil, @bot)
227
- end
228
- end
229
-
230
239
  def transform_options_hash(hash)
231
240
  hash.to_h { |opt| [opt['name'], opt['options'] || opt['value']] }
232
241
  end
@@ -397,15 +406,40 @@ module Discordrb::Events
397
406
 
398
407
  # An event for when a user submits a modal.
399
408
  class ModalSubmitEvent < ComponentEvent
400
- # @return [Array<TextInputComponent>]
409
+ # @return [Array<Component>] an array of partial component objects that were in the modal.
401
410
  attr_reader :components
402
411
 
412
+ # @return [Resolved] The resolved channels, roles, users, members, and attachments for the modal.
413
+ attr_reader :resolved
414
+
415
+ # @!visibility private
416
+ def initialize(data, bot)
417
+ super
418
+
419
+ @resolved = Resolved.new({}, {}, {}, {}, {}, {})
420
+ process_resolved(data['data']['resolved']) if data['data']['resolved']
421
+ end
422
+
403
423
  # Get the value of an input passed to the modal.
404
424
  # @param custom_id [String] The custom ID of the component to look for.
405
- # @return [String, nil]
425
+ # @return [String, nil] The selected value for the component.
406
426
  def value(custom_id)
407
427
  get_component(custom_id)&.value
408
428
  end
429
+
430
+ # Get the selected values from a select menu or file upload component.
431
+ # @param custom_id [String] The custom ID of the component to look for.
432
+ # @return [Array<String>, nil] The values that were chosen for the component.
433
+ def values(custom_id)
434
+ get_component(custom_id)&.values
435
+ end
436
+
437
+ # Get the attachments that a user uploaded in this modal.
438
+ # @param custom_id [String] The custom ID of the file upload component to get attachments for.
439
+ # @return [Array<Attachment>] the attachments that were uploaded to the file upload component.
440
+ def attachments(custom_id)
441
+ values(custom_id)&.map { |id| @resolved[:attachments][id.to_i] } || []
442
+ end
409
443
  end
410
444
 
411
445
  # Event handler for a modal submission.
@@ -455,7 +489,7 @@ module Discordrb::Events
455
489
  def initialize(data, bot)
456
490
  super
457
491
 
458
- users = data['data']['resolved']['users'].keys.map { |e| bot.user(e) }
492
+ users = data['data']['resolved']['users'].map { |_, user| @bot.ensure_user(user) }
459
493
  roles = data['data']['resolved']['roles'] ? data['data']['resolved']['roles'].keys.map { |e| bot.server(data['guild_id']).role(e) } : []
460
494
  @values = { users: users, roles: roles }
461
495
  end
@@ -18,7 +18,7 @@ module Discordrb::Events
18
18
  # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
19
19
  # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
20
20
  # @param components [View, Array<Hash>, nil] A collection of components to attach to the message.
21
- # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2) and SUPPRESS_NOTIFICATIONS (1 << 12) can be set.
21
+ # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
22
22
  # @return [Discordrb::Message] the message that was sent
23
23
  def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0)
24
24
  channel.send_message(content, tts, embed, attachments, allowed_mentions, message_reference, components, flags)
@@ -33,7 +33,7 @@ module Discordrb::Events
33
33
  # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
34
34
  # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
35
35
  # @param components [View, Array<Hash>, nil] A collection of components to attach to the message.
36
- # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2) and SUPPRESS_NOTIFICATIONS (1 << 12) can be set.
36
+ # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
37
37
  # @yield [embed] Yields the embed to allow for easy building inside a block.
38
38
  # @yieldparam embed [Discordrb::Webhooks::Embed] The embed from the parameters, or a new one.
39
39
  # @return [Message] The resulting message.
@@ -49,7 +49,7 @@ module Discordrb::Events
49
49
  # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
50
50
  # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
51
51
  # @param components [View, Array<Hash>, nil] A collection of components to attach to the message.
52
- # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2) and SUPPRESS_NOTIFICATIONS (1 << 12) can be set.
52
+ # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
53
53
  def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, components = nil, flags = 0)
54
54
  channel.send_temporary_message(content, timeout, tts, embed, attachments, allowed_mentions, components, flags)
55
55
  end
@@ -3,5 +3,5 @@
3
3
  # Discordrb and all its functionality, in this case only the version.
4
4
  module Discordrb
5
5
  # The current version of discordrb.
6
- VERSION = '3.7.1'
6
+ VERSION = '3.8.0'
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: discordrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.1
4
+ version: 3.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - meew0
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 3.7.1
89
+ version: 3.8.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 3.7.1
96
+ version: 3.8.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: bundler
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -103,7 +103,7 @@ dependencies:
103
103
  version: '1.10'
104
104
  - - "<"
105
105
  - !ruby/object:Gem::Version
106
- version: '3'
106
+ version: '5'
107
107
  type: :development
108
108
  prerelease: false
109
109
  version_requirements: !ruby/object:Gem::Requirement
@@ -113,7 +113,7 @@ dependencies:
113
113
  version: '1.10'
114
114
  - - "<"
115
115
  - !ruby/object:Gem::Version
116
- version: '3'
116
+ version: '5'
117
117
  - !ruby/object:Gem::Dependency
118
118
  name: rake
119
119
  requirement: !ruby/object:Gem::Requirement
@@ -344,6 +344,7 @@ files:
344
344
  - lib/discordrb/events/channels.rb
345
345
  - lib/discordrb/events/generic.rb
346
346
  - lib/discordrb/events/guilds.rb
347
+ - lib/discordrb/events/integrations.rb
347
348
  - lib/discordrb/events/interactions.rb
348
349
  - lib/discordrb/events/invites.rb
349
350
  - lib/discordrb/events/lifetime.rb
@@ -399,7 +400,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
399
400
  - !ruby/object:Gem::Version
400
401
  version: '0'
401
402
  requirements: []
402
- rubygems_version: 3.6.9
403
+ rubygems_version: 4.0.10
403
404
  specification_version: 4
404
405
  summary: Discord API for Ruby
405
406
  test_files: []