onyxcord 1.1.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.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/.devcontainer/Dockerfile +13 -0
  3. data/.devcontainer/devcontainer.json +29 -0
  4. data/.devcontainer/postcreate.sh +4 -0
  5. data/.github/CONTRIBUTING.md +13 -0
  6. data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  7. data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  8. data/.github/pull_request_template.md +37 -0
  9. data/.github/workflows/ci.yml +78 -0
  10. data/.github/workflows/codeql.yml +65 -0
  11. data/.github/workflows/deploy.yml +54 -0
  12. data/.github/workflows/release.yml +51 -0
  13. data/.gitignore +16 -0
  14. data/.markdownlint.json +4 -0
  15. data/.overcommit.yml +7 -0
  16. data/.rspec +2 -0
  17. data/.rubocop.yml +129 -0
  18. data/.yardopts +1 -0
  19. data/CHANGELOG.md +0 -0
  20. data/Gemfile +7 -0
  21. data/LICENSE.txt +21 -0
  22. data/README.md +305 -0
  23. data/Rakefile +17 -0
  24. data/bin/console +15 -0
  25. data/bin/setup +7 -0
  26. data/lib/onyxcord/allowed_mentions.rb +43 -0
  27. data/lib/onyxcord/api/application.rb +316 -0
  28. data/lib/onyxcord/api/channel.rb +700 -0
  29. data/lib/onyxcord/api/interaction.rb +67 -0
  30. data/lib/onyxcord/api/invite.rb +44 -0
  31. data/lib/onyxcord/api/server.rb +775 -0
  32. data/lib/onyxcord/api/user.rb +158 -0
  33. data/lib/onyxcord/api/webhook.rb +163 -0
  34. data/lib/onyxcord/api.rb +335 -0
  35. data/lib/onyxcord/await.rb +51 -0
  36. data/lib/onyxcord/bot.rb +1971 -0
  37. data/lib/onyxcord/cache.rb +326 -0
  38. data/lib/onyxcord/colour_rgb.rb +43 -0
  39. data/lib/onyxcord/commands/command_bot.rb +511 -0
  40. data/lib/onyxcord/commands/container.rb +112 -0
  41. data/lib/onyxcord/commands/events.rb +11 -0
  42. data/lib/onyxcord/commands/parser.rb +327 -0
  43. data/lib/onyxcord/commands/rate_limiter.rb +144 -0
  44. data/lib/onyxcord/configuration.rb +125 -0
  45. data/lib/onyxcord/container.rb +988 -0
  46. data/lib/onyxcord/data/activity.rb +271 -0
  47. data/lib/onyxcord/data/application.rb +341 -0
  48. data/lib/onyxcord/data/attachment.rb +91 -0
  49. data/lib/onyxcord/data/audit_logs.rb +438 -0
  50. data/lib/onyxcord/data/avatar_decoration.rb +26 -0
  51. data/lib/onyxcord/data/call.rb +22 -0
  52. data/lib/onyxcord/data/channel.rb +1355 -0
  53. data/lib/onyxcord/data/channel_tag.rb +69 -0
  54. data/lib/onyxcord/data/collectibles.rb +47 -0
  55. data/lib/onyxcord/data/component.rb +583 -0
  56. data/lib/onyxcord/data/embed.rb +258 -0
  57. data/lib/onyxcord/data/emoji.rb +123 -0
  58. data/lib/onyxcord/data/install_params.rb +24 -0
  59. data/lib/onyxcord/data/integration.rb +144 -0
  60. data/lib/onyxcord/data/interaction.rb +1141 -0
  61. data/lib/onyxcord/data/invite.rb +137 -0
  62. data/lib/onyxcord/data/member.rb +528 -0
  63. data/lib/onyxcord/data/message.rb +612 -0
  64. data/lib/onyxcord/data/message_activity.rb +41 -0
  65. data/lib/onyxcord/data/overwrite.rb +109 -0
  66. data/lib/onyxcord/data/poll.rb +365 -0
  67. data/lib/onyxcord/data/primary_server.rb +60 -0
  68. data/lib/onyxcord/data/profile.rb +79 -0
  69. data/lib/onyxcord/data/reaction.rb +64 -0
  70. data/lib/onyxcord/data/recipient.rb +34 -0
  71. data/lib/onyxcord/data/role.rb +449 -0
  72. data/lib/onyxcord/data/role_connection_data.rb +69 -0
  73. data/lib/onyxcord/data/role_subscription.rb +41 -0
  74. data/lib/onyxcord/data/scheduled_event.rb +513 -0
  75. data/lib/onyxcord/data/server.rb +1614 -0
  76. data/lib/onyxcord/data/server_preview.rb +68 -0
  77. data/lib/onyxcord/data/snapshot.rb +112 -0
  78. data/lib/onyxcord/data/team.rb +98 -0
  79. data/lib/onyxcord/data/timestamp.rb +69 -0
  80. data/lib/onyxcord/data/user.rb +324 -0
  81. data/lib/onyxcord/data/voice_region.rb +46 -0
  82. data/lib/onyxcord/data/voice_state.rb +41 -0
  83. data/lib/onyxcord/data/webhook.rb +238 -0
  84. data/lib/onyxcord/data.rb +57 -0
  85. data/lib/onyxcord/errors.rb +246 -0
  86. data/lib/onyxcord/event_executor.rb +80 -0
  87. data/lib/onyxcord/events/await.rb +48 -0
  88. data/lib/onyxcord/events/bans.rb +60 -0
  89. data/lib/onyxcord/events/channels.rb +225 -0
  90. data/lib/onyxcord/events/generic.rb +129 -0
  91. data/lib/onyxcord/events/guilds.rb +269 -0
  92. data/lib/onyxcord/events/integrations.rb +100 -0
  93. data/lib/onyxcord/events/interactions.rb +624 -0
  94. data/lib/onyxcord/events/invites.rb +127 -0
  95. data/lib/onyxcord/events/lifetime.rb +31 -0
  96. data/lib/onyxcord/events/members.rb +110 -0
  97. data/lib/onyxcord/events/message.rb +399 -0
  98. data/lib/onyxcord/events/polls.rb +118 -0
  99. data/lib/onyxcord/events/presence.rb +131 -0
  100. data/lib/onyxcord/events/raw.rb +74 -0
  101. data/lib/onyxcord/events/reactions.rb +218 -0
  102. data/lib/onyxcord/events/roles.rb +87 -0
  103. data/lib/onyxcord/events/scheduled_events.rb +171 -0
  104. data/lib/onyxcord/events/threads.rb +100 -0
  105. data/lib/onyxcord/events/typing.rb +73 -0
  106. data/lib/onyxcord/events/voice_server_update.rb +48 -0
  107. data/lib/onyxcord/events/voice_state_update.rb +106 -0
  108. data/lib/onyxcord/events/webhooks.rb +65 -0
  109. data/lib/onyxcord/gateway.rb +890 -0
  110. data/lib/onyxcord/id_object.rb +39 -0
  111. data/lib/onyxcord/light/data.rb +62 -0
  112. data/lib/onyxcord/light/integrations.rb +73 -0
  113. data/lib/onyxcord/light/light_bot.rb +58 -0
  114. data/lib/onyxcord/light.rb +8 -0
  115. data/lib/onyxcord/logger.rb +120 -0
  116. data/lib/onyxcord/message_components.rb +70 -0
  117. data/lib/onyxcord/paginator.rb +60 -0
  118. data/lib/onyxcord/permissions.rb +255 -0
  119. data/lib/onyxcord/rate_limiter/gateway.rb +42 -0
  120. data/lib/onyxcord/rate_limiter/rest.rb +89 -0
  121. data/lib/onyxcord/version.rb +7 -0
  122. data/lib/onyxcord/voice/encoder.rb +115 -0
  123. data/lib/onyxcord/voice/network.rb +380 -0
  124. data/lib/onyxcord/voice/opcodes.rb +29 -0
  125. data/lib/onyxcord/voice/sodium.rb +157 -0
  126. data/lib/onyxcord/voice/timer.rb +19 -0
  127. data/lib/onyxcord/voice/voice_bot.rb +386 -0
  128. data/lib/onyxcord/webhooks.rb +14 -0
  129. data/lib/onyxcord/websocket.rb +62 -0
  130. data/lib/onyxcord.rb +180 -0
  131. data/onyxcord-webhooks.gemspec +30 -0
  132. data/onyxcord.gemspec +50 -0
  133. metadata +421 -0
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # A forum or media tag that can be applied to threads.
5
+ class ChannelTag
6
+ include IDObject
7
+
8
+ # @return [String] the 1-20 character name of the channel tag.
9
+ attr_reader :name
10
+
11
+ # @return [Channel] the channel associated with the channel tag.
12
+ attr_reader :channel
13
+
14
+ # @return [true, false] whether or not the channel tag is moderated.
15
+ attr_reader :moderated
16
+ alias_method :moderated?, :moderated
17
+
18
+ # @!visibility private
19
+ def initialize(data, channel, bot)
20
+ @bot = bot
21
+ @channel = channel
22
+ @id = data['id'].to_i
23
+ @name = data['name']
24
+ @moderated = data['moderated']
25
+ @emoji_id = data['emoji_id']&.to_i
26
+ @emoji_name = Emoji.new({ 'name' => data['emoji_name'] }, @bot) if data['emoji_name']
27
+ end
28
+
29
+ # Get the emoji of the channel tag.
30
+ # @return [Emoji, nil] the emoji of the channel tag, or `nil` if no emoji has been set.
31
+ def emoji
32
+ @emoji_id ? @channel.server.emojis[@emoji_id] : @emoji_name
33
+ end
34
+
35
+ # Modify the properties of the channel tag.
36
+ # @param name [String] The new 1-20 character name of the channel tag.
37
+ # @param emoji [Emoji, Integer, String, nil] The new emoji of the channel tag.
38
+ # @param moderated [true, false] Whether or not the channel tag should be moderated.
39
+ # @param reason [String, nil] The reason to show in the audit log for modifying the tag.
40
+ # @return [nil]
41
+ def modify(name: :undef, emoji: :undef, moderated: :undef, reason: nil)
42
+ data = {
43
+ name: name,
44
+ moderated: moderated,
45
+ **(Emoji.build_emoji_hash(emoji) if emoji != :undef)
46
+ }.reject { |_, value| value == :undef }
47
+
48
+ @channel.update_tags(to_h.merge(data), reason)
49
+ end
50
+
51
+ # Permenantly delete the channel tag.
52
+ # @param reason [String, nil] The reason to show in the audit log for deleting the tag.
53
+ # @return [nil]
54
+ def delete(reason: nil)
55
+ @channel.update_tags({ id: @id, d: true }, reason)
56
+ end
57
+
58
+ # @!visibility private
59
+ def to_h
60
+ {
61
+ id: @id,
62
+ name: @name,
63
+ emoji_id: @emoji_id,
64
+ moderated: @moderated,
65
+ emoji_name: @emoji_name&.name
66
+ }
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # Collectibles are resources such as nameplates that can be collected by users.
5
+ class Collectibles
6
+ # @return [Nameplate, nil] the nameplate the user has collected or nil.
7
+ attr_reader :nameplate
8
+
9
+ # @!visibility private
10
+ def initialize(data, bot)
11
+ @bot = bot
12
+ @nameplate = Nameplate.new(data['nameplate'], bot) if data['nameplate']
13
+ end
14
+
15
+ # Collectable background images shown on a user's name in the member's tab.
16
+ class Nameplate
17
+ # @return [Integer] ID of the nameplate's SKU.
18
+ attr_reader :sku_id
19
+
20
+ # @return [String] the path to the nameplate asset.
21
+ attr_reader :asset
22
+
23
+ # @return [String] the label of the nameplate.
24
+ attr_reader :label
25
+
26
+ # @return [Symbol] the background color of the nameplate.
27
+ attr_reader :palette
28
+
29
+ # @!visibility private
30
+ def initialize(data, bot)
31
+ @bot = bot
32
+ @sku_id = data['sku_id']&.to_i
33
+ @asset = data['asset']
34
+ @label = data['label']
35
+ @palette = data['palette'].to_sym
36
+ end
37
+
38
+ # Utility method to get the URL of this nameplate.
39
+ # @param static [true, false] Whether to return the static URL of this
40
+ # nameplate instead of the animated URL.
41
+ # @return [String] The CDN url of this nameplate.
42
+ def url(static: false)
43
+ static ? API.static_nameplate_url(@asset) : API.nameplate_url(@asset)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,583 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # Components are interactable interfaces that can be attached to messages.
5
+ module Components
6
+ # @deprecated This alias will be removed in future releases.
7
+ class View < Webhooks::View
8
+ end
9
+
10
+ # @!visibility private
11
+ def self.from_data(data, bot)
12
+ case data['type']
13
+ when Webhooks::View::COMPONENT_TYPES[:action_row]
14
+ ActionRow.new(data, bot)
15
+ when Webhooks::View::COMPONENT_TYPES[:button]
16
+ Button.new(data, bot)
17
+ when Webhooks::View::COMPONENT_TYPES[:string_select], Webhooks::View::COMPONENT_TYPES[:user_select], Webhooks::View::COMPONENT_TYPES[:role_select], Webhooks::View::COMPONENT_TYPES[:mentionable_select], Webhooks::View::COMPONENT_TYPES[:channel_select]
18
+ SelectMenu.new(data, bot)
19
+ when Webhooks::Modal::COMPONENT_TYPES[:text_input]
20
+ TextInput.new(data, bot)
21
+ when Webhooks::View::COMPONENT_TYPES[:section]
22
+ Section.new(data, bot)
23
+ when Webhooks::View::COMPONENT_TYPES[:text_display]
24
+ TextDisplay.new(data, bot)
25
+ when Webhooks::View::COMPONENT_TYPES[:thumbnail]
26
+ Thumbnail.new(data, bot)
27
+ when Webhooks::View::COMPONENT_TYPES[:media_gallery]
28
+ MediaGallery.new(data, bot)
29
+ when Webhooks::View::COMPONENT_TYPES[:file]
30
+ File.new(data, bot)
31
+ when Webhooks::View::COMPONENT_TYPES[:separator]
32
+ Separator.new(data, bot)
33
+ when Webhooks::View::COMPONENT_TYPES[:container]
34
+ Container.new(data, bot)
35
+ when Webhooks::Modal::COMPONENT_TYPES[:label]
36
+ Label.new(data, bot)
37
+ when Webhooks::Modal::COMPONENT_TYPES[:file_upload]
38
+ FileUpload.new(data, bot)
39
+ when Webhooks::Modal::COMPONENT_TYPES[:radio_group]
40
+ RadioGroup.new(data, bot)
41
+ when Webhooks::Modal::COMPONENT_TYPES[:checkbox_group]
42
+ CheckboxGroup.new(data, bot)
43
+ when Webhooks::Modal::COMPONENT_TYPES[:checkbox]
44
+ Checkbox.new(data, bot)
45
+ end
46
+ end
47
+
48
+ # Represents a row of components.
49
+ class ActionRow
50
+ include Enumerable
51
+
52
+ # @return [Integer] the numeric identifier of the action row.
53
+ attr_reader :id
54
+
55
+ # @return [Array<Button>] the components contained within this action row.
56
+ attr_reader :components
57
+
58
+ # @!visibility private
59
+ def initialize(data, bot)
60
+ @bot = bot
61
+ @id = data['id']
62
+ @components = data['components'].filter_map { |component| Components.from_data(component, @bot) }
63
+ end
64
+
65
+ # Iterate over each component in the row.
66
+ # @return [Array, Enumerator]
67
+ def each(&block)
68
+ @components.each(&block)
69
+ end
70
+
71
+ # Get all the buttons in this action row.
72
+ # @return [Array<Button>] All of the buttons in this action row.
73
+ def buttons
74
+ select { |component| component.is_a?(Button) }
75
+ end
76
+
77
+ # Get all the text inputs in this action row.
78
+ # @return [Array<TextInput>] All of the text inputs in this action row.
79
+ def text_inputs
80
+ select { |component| component.is_a?(TextInput) }
81
+ end
82
+
83
+ # @!visibility private
84
+ def to_a
85
+ @components
86
+ end
87
+ end
88
+
89
+ # An interactable button component.
90
+ class Button
91
+ # @return [Integer] the numeric identifier of the button.
92
+ attr_reader :id
93
+
94
+ # @return [String] the label of the button.
95
+ attr_reader :label
96
+
97
+ # @return [Integer] the style of the button.
98
+ attr_reader :style
99
+
100
+ # @return [String] the custom ID of the button.
101
+ attr_reader :custom_id
102
+
103
+ # @return [true, false] whether or not the button is disabled.
104
+ attr_reader :disabled
105
+
106
+ # @return [String, nil] the URL of the button if applicable.
107
+ attr_reader :url
108
+
109
+ # @return [Integer, nil] the SKU ID of the button if it is a premium button.
110
+ attr_reader :sku_id
111
+
112
+ # @return [Emoji, nil] the custom emoji of the button component.
113
+ attr_reader :emoji
114
+
115
+ # @!visibility private
116
+ def initialize(data, bot)
117
+ @bot = bot
118
+ @id = data['id']
119
+ @label = data['label']
120
+ @style = data['style']
121
+ @custom_id = data['custom_id']
122
+ @disabled = data['disabled']
123
+ @url = data['url']
124
+ @sku_id = data['sku_id']&.to_i
125
+ @emoji = Emoji.new(data['emoji'], @bot) if data['emoji']
126
+ end
127
+
128
+ # @!method primary?
129
+ # @return [true, false] whether the button is a primary option in the group.
130
+ # @!method secondary?
131
+ # @return [true, false] whether the button denotes a secondary option in the group.
132
+ # @!method success?
133
+ # @return [true, false] whether the button denotes a success action in the group.
134
+ # @!method danger?
135
+ # @return [true, false] whether the button denotes a dangerous action in the group.
136
+ # @!method link?
137
+ # @return [true, false] whether the button is a container for a URL that will open upon click.
138
+ # @!method premium?
139
+ # @return [true, false] whether the button starts a premium SKU purchase.
140
+ Webhooks::View::BUTTON_STYLES.each do |name, value|
141
+ define_method("#{name}?") do
142
+ @style == value
143
+ end
144
+ end
145
+
146
+ # Await a button click.
147
+ def await_click(key, **attributes, &block)
148
+ @bot.add_await(key, OnyxCord::Events::ButtonEvent, { custom_id: @custom_id }.merge!(attributes), &block)
149
+ end
150
+
151
+ # Await a button click, blocking.
152
+ def await_click!(**attributes, &block)
153
+ @bot.add_await!(OnyxCord::Events::ButtonEvent, { custom_id: @custom_id }.merge!(attributes), &block)
154
+ end
155
+ end
156
+
157
+ # An interactable select menu component.
158
+ class SelectMenu
159
+ # A select menu option.
160
+ class Option
161
+ # @return [String] the label of the option.
162
+ attr_reader :label
163
+
164
+ # @return [String] the value of the option.
165
+ attr_reader :value
166
+
167
+ # @return [String, nil] the description of the option.
168
+ attr_reader :description
169
+
170
+ # @return [Emoji, nil] the emoji of the option, or `nil`.
171
+ attr_reader :emoji
172
+
173
+ # @!visibility private
174
+ def initialize(data)
175
+ @label = data['label']
176
+ @value = data['value']
177
+ @description = data['description']
178
+ @emoji = Emoji.new(data['emoji'], @bot) if data['emoji']
179
+ end
180
+ end
181
+
182
+ # @return [Integer] the numeric identifier of the select menu.
183
+ attr_reader :id
184
+
185
+ # @return [Array<String>] the submitted values from the modal.
186
+ attr_reader :values
187
+
188
+ # @return [String] the custom ID used to identify the select menu.
189
+ attr_reader :custom_id
190
+
191
+ # @return [Integer, nil] the minimum amount of values that be selected.
192
+ attr_reader :max_values
193
+
194
+ # @return [Integer, nil] the maximum amount of values that can be selected.
195
+ attr_reader :min_values
196
+
197
+ # @return [String, nil] the default placeholder text shown on the select menu.
198
+ attr_reader :placeholder
199
+
200
+ # @return [Array<Option>] the options in the select menu, or the selected options.
201
+ attr_reader :options
202
+
203
+ # @!visibility private
204
+ def initialize(data, bot)
205
+ @bot = bot
206
+ @id = data['id']
207
+ @values = data['values'] || []
208
+ @custom_id = data['custom_id']
209
+ @max_values = data['max_values']
210
+ @min_values = data['min_values']
211
+ @placeholder = data['placeholder']
212
+ @options = data['options']&.map { |option| Option.new(option) } || []
213
+ end
214
+ end
215
+
216
+ # A free-form text input bar in a modal.
217
+ class TextInput
218
+ # @!visibility private
219
+ PLACEHOLDERS = %i[
220
+ label
221
+ min_length
222
+ max_length
223
+ required
224
+ required?
225
+ placeholder
226
+ ].freeze
227
+
228
+ # @!visibility private
229
+ SHORT = 1
230
+
231
+ # @!visibility private
232
+ PARAGRAPH = 2
233
+
234
+ # @return [Integer] the numeric identifier of the text input.
235
+ attr_reader :id
236
+
237
+ # @return [Symbol] This is deprecated and not accurate. This will
238
+ # be removed in the next major version (4.0.0).
239
+ attr_reader :style
240
+
241
+ # @return [String, nil] the value the user typed into the text input.
242
+ attr_reader :value
243
+
244
+ # @return [String] the developer-defined identifier for the text input.
245
+ attr_reader :custom_id
246
+
247
+ # @!visibility private
248
+ def initialize(data, bot)
249
+ @bot = bot
250
+ @id = data['id']
251
+ @style = :paragraph
252
+ @value = data['value']
253
+ @custom_id = data['custom_id']
254
+ end
255
+
256
+ # @!visibility private
257
+ PLACEHOLDERS.each { |name| define_method(name) { nil } }
258
+ end
259
+
260
+ # A grouping of components with a contextual accessory.
261
+ class Section
262
+ # @return [Integer] the numeric identifier of the section.
263
+ attr_reader :id
264
+
265
+ # @return [Component] the contextual accessory of the section.
266
+ attr_reader :accessory
267
+
268
+ # @return [Array<Component>] the child components of the section.
269
+ attr_reader :components
270
+
271
+ # @!visibility private
272
+ def initialize(data, bot)
273
+ @bot = bot
274
+ @id = data['id']
275
+ @accessory = Components.from_data(data['accessory'], @bot)
276
+ @components = data['components'].filter_map { |component| Components.from_data(component, @bot) }
277
+ end
278
+ end
279
+
280
+ # A content component representing message content.
281
+ class TextDisplay
282
+ # @return [Integer] the numeric identifier of the text display.
283
+ attr_reader :id
284
+
285
+ # @return [String] the content to be displayed for the text display.
286
+ attr_reader :content
287
+
288
+ # @!visibility private
289
+ def initialize(data, bot)
290
+ @bot = bot
291
+ @id = data['id']
292
+ @content = data['content']
293
+ end
294
+ end
295
+
296
+ # A content component that compactly displays media.
297
+ class Thumbnail
298
+ # @return [Integer] the numeric identifier of the thumbnail.
299
+ attr_reader :id
300
+
301
+ # @return [MediaItem] the unfurled media content of the thumbnail.
302
+ attr_reader :media
303
+
304
+ # @return [true, false] whether or not the thumbnail's media should
305
+ # be blurred out.
306
+ attr_reader :spoiler
307
+ alias spoiler? spoiler
308
+
309
+ # @return [String, nil] the alternative text for the thumbnail's media.
310
+ attr_reader :description
311
+
312
+ # @!visibility private
313
+ def initialize(data, bot)
314
+ @bot = bot
315
+ @id = data['id']
316
+ @spoiler = data['spoiler']
317
+ @description = data['description']
318
+ @media = MediaItem.new(data['media'], @bot)
319
+ end
320
+ end
321
+
322
+ # A grouping of media attachments in an organized gallery format.
323
+ class MediaGallery
324
+ # @return [Integer] the numeric identifier of the media gallery.
325
+ attr_reader :id
326
+
327
+ # @return [Array<Item>] the media items contained within the media gallery.
328
+ attr_reader :items
329
+
330
+ # @!visibility private
331
+ def initialize(data, bot)
332
+ @bot = bot
333
+ @id = data['id']
334
+ @items = data['items'].map { |item| Item.new(item, @bot) }
335
+ end
336
+
337
+ # A singular media attachment.
338
+ class Item
339
+ # @return [MediaItem] the unfurled media content of the gallery item.
340
+ attr_reader :media
341
+
342
+ # @return [true, false] whether or not the gallery item's media should
343
+ # be blurred out.
344
+ attr_reader :spoiler
345
+ alias spoiler? spoiler
346
+
347
+ # @return [String, nil] the alternative text for the gallery item's media.
348
+ attr_reader :description
349
+
350
+ # @!visibility private
351
+ def initialize(data, bot)
352
+ @bot = bot
353
+ @spoiler = data['spoiler']
354
+ @description = data['description']
355
+ @media = MediaItem.new(data['media'], @bot)
356
+ end
357
+ end
358
+ end
359
+
360
+ # A component that adds vertical padding and visual division.
361
+ class Separator
362
+ # @return [Integer] the numeric identifier of the separator.
363
+ attr_reader :id
364
+
365
+ # @return [true, false] whether or not a visual divider should be displayed.
366
+ attr_reader :divider
367
+ alias divider? divider
368
+
369
+ # @return [Integer] the size of the separator's padding. `1` for little padding,
370
+ # and `2` for big padding.
371
+ attr_reader :spacing
372
+
373
+ # @!visibility private
374
+ def initialize(data, bot)
375
+ @bot = bot
376
+ @id = data['id']
377
+ @divider = data['divider']
378
+ @spacing = data['spacing']
379
+ end
380
+ end
381
+
382
+ # A collection of components in an embed-like format.
383
+ class Container
384
+ # @return [Integer] the numeric identifier of the container.
385
+ attr_reader :id
386
+
387
+ # @return [ColourRGB, nil] the accent colour of the container.
388
+ attr_reader :color
389
+ alias colour color
390
+
391
+ # @return [true, false] whether or not the container should be
392
+ # blurred out.
393
+ attr_reader :spoiler
394
+ alias spoiler? spoiler
395
+
396
+ # @return [Array<Component>] the child components of the container.
397
+ attr_reader :components
398
+
399
+ # @!visibility private
400
+ def initialize(data, bot)
401
+ @bot = bot
402
+ @id = data['id']
403
+ @spoiler = data['spoiler']
404
+ @color = ColourRGB.new(data['accent_color']) if data['accent_color']
405
+ @components = data['components'].filter_map { |component| Components.from_data(component, @bot) }
406
+ end
407
+
408
+ # Get the buttons contained within the container.
409
+ # @return [Array<Button>] The buttons within the container.
410
+ def buttons
411
+ @components.flat_map do |component|
412
+ case component
413
+ when ActionRow
414
+ component.buttons
415
+ when Section
416
+ component.accessory if component.accessory.is_a?(Button)
417
+ end
418
+ end.compact
419
+ end
420
+ end
421
+
422
+ # A component that allows you to display an attachment.
423
+ class File
424
+ # @return [Integer] the numeric identifier of the file.
425
+ attr_reader :id
426
+
427
+ # @return [String] the name of the file that was uploaded.
428
+ attr_reader :name
429
+
430
+ # @return [Integer] the size of the file that was uploaded
431
+ # in bytes.
432
+ attr_reader :size
433
+
434
+ # @return [MediaItem] the unfurled media item of the file.
435
+ attr_reader :media
436
+
437
+ # @return [true, false] whether or not the file should be
438
+ # blurred out.
439
+ attr_reader :spoiler
440
+ alias spoiler? spoiler
441
+
442
+ # @!visibility private
443
+ def initialize(data, bot)
444
+ @bot = bot
445
+ @id = data['id']
446
+ @name = data['name']
447
+ @size = data['size']
448
+ @spoiler = data['spoiler']
449
+ @media = MediaItem.new(data['file'], @bot)
450
+ end
451
+ end
452
+
453
+ # Resolved metadata about a piece of media.
454
+ class MediaItem
455
+ # @return [String] the URL to the media item.
456
+ attr_reader :url
457
+
458
+ # @return [Integer, nil] the width of the media item.
459
+ attr_reader :width
460
+
461
+ # @return [Integer, nil] the height of the media item.
462
+ attr_reader :height
463
+
464
+ # @return [String, nil] the proxied URL to the media item.
465
+ attr_reader :proxy_url
466
+
467
+ # @return [String, nil] the content type of the media item.
468
+ attr_reader :content_type
469
+
470
+ # @return [Integer, nil] the ID of the uploaded attachment. Only present
471
+ # when the media item was uploaded via an `attachment://<filename>` reference.
472
+ attr_reader :attachment_id
473
+
474
+ # @!visibility private
475
+ def initialize(data, bot)
476
+ @bot = bot
477
+ @url = data['url']
478
+ @width = data['width']
479
+ @height = data['height']
480
+ @proxy_url = data['proxy_url']
481
+ @content_type = data['content_type']
482
+ @attachment_id = data['attachment_id']&.to_i
483
+ end
484
+ end
485
+
486
+ # A parent component for interactive modal components.
487
+ class Label
488
+ # @return [Integer] the numeric identifier of the label.
489
+ attr_reader :id
490
+
491
+ # @return [Component] the interactive component of the label.
492
+ attr_reader :component
493
+
494
+ # @!visibility private
495
+ def initialize(data, bot)
496
+ @bot = bot
497
+ @id = data['id']
498
+ @component = Components.from_data(data['component'], @bot)
499
+ end
500
+ end
501
+
502
+ # A surface that allows users to upload files in a modal.
503
+ class FileUpload
504
+ # @return [Integer] the numeric identifier of the file upload.
505
+ attr_reader :id
506
+
507
+ # @return [Array<Integer>] the IDs of the uploaded attachments.
508
+ attr_reader :values
509
+
510
+ # @return [String] the developer-defined identifier for the file upload.
511
+ attr_reader :custom_id
512
+
513
+ # @!visibility private
514
+ def initialize(data, bot)
515
+ @bot = bot
516
+ @id = data['id']
517
+ @custom_id = data['custom_id']
518
+ @values = data['values'].map(&:to_i)
519
+ end
520
+ end
521
+
522
+ # A grouping of radio buttons in a modal.
523
+ class RadioGroup
524
+ # @return [Integer] the numeric identifier of the radio group.
525
+ attr_reader :id
526
+
527
+ # @return [String, nil] whether or not a radio button was selected.
528
+ attr_reader :value
529
+
530
+ # @return [String] the developer-defined identifier of the radio group.
531
+ attr_reader :custom_id
532
+
533
+ # @!visibility private
534
+ def initialize(data, bot)
535
+ @bot = bot
536
+ @id = data['id']
537
+ @value = data['value']
538
+ @custom_id = data['custom_id']
539
+ end
540
+ end
541
+
542
+ # A grouping of checkboxes in a modal.
543
+ class CheckboxGroup
544
+ # @return [Integer] the numeric identifier of the checkbox group.
545
+ attr_reader :id
546
+
547
+ # @return [Array<String>] the values of the selected checkbox buttons.
548
+ attr_reader :values
549
+
550
+ # @return [String] the developer-defined identifier of the checkbox group.
551
+ attr_reader :custom_id
552
+
553
+ # @!visibility private
554
+ def initialize(data, bot)
555
+ @bot = bot
556
+ @id = data['id']
557
+ @values = data['values']
558
+ @custom_id = data['custom_id']
559
+ end
560
+ end
561
+
562
+ # A checkbox that can be ticked in a modal.
563
+ class Checkbox
564
+ # @return [Integer] the numeric identifier of the checkbox.
565
+ attr_reader :id
566
+
567
+ # @return [true, false] whether or not the checkbox was selected.
568
+ attr_reader :value
569
+ alias value? value
570
+
571
+ # @return [String] the developer-defined identifier of the checkbox.
572
+ attr_reader :custom_id
573
+
574
+ # @!visibility private
575
+ def initialize(data, bot)
576
+ @bot = bot
577
+ @id = data['id']
578
+ @value = data['value']
579
+ @custom_id = data['custom_id']
580
+ end
581
+ end
582
+ end
583
+ end