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,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # Recipients are members on private channels - they exist for completeness purposes, but all
5
+ # the attributes will be empty.
6
+ class Recipient < DelegateClass(User)
7
+ include MemberAttributes
8
+
9
+ # @return [Channel] the private channel this recipient is the recipient of.
10
+ attr_reader :channel
11
+
12
+ # @!visibility private
13
+ def initialize(user, channel, bot)
14
+ @bot = bot
15
+ @channel = channel
16
+ raise ArgumentError, 'Tried to create a recipient for a public channel!' unless @channel.private?
17
+
18
+ @user = user
19
+ super(@user)
20
+
21
+ # Member attributes
22
+ @mute = @deaf = @self_mute = @self_deaf = false
23
+ @voice_channel = nil
24
+ @server = nil
25
+ @roles = []
26
+ @joined_at = @channel.creation_time
27
+ end
28
+
29
+ # Overwriting inspect for debug purposes
30
+ def inspect
31
+ "<Recipient user=#{@user.inspect} channel=#{@channel.inspect}>"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,449 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # A Discord role that contains permissions and applies to certain users
5
+ class Role
6
+ include IDObject
7
+
8
+ # @return [Permissions] this role's permissions.
9
+ attr_reader :permissions
10
+
11
+ # @return [String] this role's name ("new role" if it hasn't been changed)
12
+ attr_reader :name
13
+
14
+ # @return [Server] the server this role belongs to
15
+ attr_reader :server
16
+
17
+ # @return [true, false] whether or not this role should be displayed separately from other users
18
+ attr_reader :hoist
19
+ alias_method :hoist?, :hoist
20
+
21
+ # @return [true, false] whether or not this role is managed by an integration or a bot
22
+ attr_reader :managed
23
+ alias_method :managed?, :managed
24
+
25
+ # @return [true, false] whether this role can be mentioned using a role mention
26
+ attr_reader :mentionable
27
+ alias_method :mentionable?, :mentionable
28
+
29
+ # @return [ColourRGB] the primary colour of this role.
30
+ attr_reader :colour
31
+ alias_method :color, :colour
32
+
33
+ # @return [Integer] the position of this role in the hierarchy
34
+ attr_reader :position
35
+
36
+ # @return [String, nil] The icon hash for this role.
37
+ attr_reader :icon
38
+
39
+ # @return [Tags, nil] The role tags.
40
+ attr_reader :tags
41
+
42
+ # @return [Integer] The flags for this role.
43
+ attr_reader :flags
44
+
45
+ # @return [String, nil] The unicode emoji of this role, or nil.
46
+ attr_reader :unicode_emoji
47
+
48
+ # @return [ColourRGB, nil] the secondary colour of this role.
49
+ attr_reader :secondary_colour
50
+ alias_method :secondary_color, :secondary_colour
51
+
52
+ # @return [ColourRGB, nil] the tertiary colour of this role.
53
+ attr_reader :tertiary_colour
54
+ alias_method :tertiary_color, :tertiary_colour
55
+
56
+ # Wrapper for the role tags
57
+ class Tags
58
+ # @return [Integer, nil] The ID of the bot this role belongs to
59
+ attr_reader :bot_id
60
+
61
+ # @return [Integer, nil] The ID of the integration this role belongs to
62
+ attr_reader :integration_id
63
+
64
+ # @return [true, false] Whether this is the guild's Booster role
65
+ attr_reader :premium_subscriber
66
+ alias_method :premium_subscriber?, :premium_subscriber
67
+
68
+ # @return [Integer, nil] The id of this role's subscription sku and listing
69
+ attr_reader :subscription_listing_id
70
+
71
+ # @return [true, false] Whether this role is available for purchase
72
+ attr_reader :available_for_purchase
73
+ alias_method :available_for_purchase?, :available_for_purchase
74
+
75
+ # @return [true, false] Whether this role is a guild's linked role
76
+ attr_reader :guild_connections
77
+ alias_method :guild_connections?, :guild_connections
78
+ alias_method :server_connections?, :guild_connections
79
+
80
+ # @!visibility private
81
+ def initialize(data)
82
+ @bot_id = data['bot_id']&.resolve_id
83
+ @integration_id = data['integration_id']&.resolve_id
84
+ @premium_subscriber = data.key?('premium_subscriber')
85
+ @subscription_listing_id = data['subscription_listing_id']&.resolve_id
86
+ @available_for_purchase = data.key?('available_for_purchase')
87
+ @guild_connections = data.key?('guild_connections')
88
+ end
89
+ end
90
+
91
+ # This class is used internally as a wrapper to a Role object that allows easy writing of permission data.
92
+ class RoleWriter
93
+ # @!visibility private
94
+ def initialize(role, token)
95
+ @role = role
96
+ @token = token
97
+ end
98
+
99
+ # Write the specified permission data to the role, without updating the permission cache
100
+ # @param bits [Integer] The packed permissions to write.
101
+ def write(bits)
102
+ @role.send(:packed=, bits, false)
103
+ end
104
+
105
+ # The inspect method is overridden, in this case to prevent the token being leaked
106
+ def inspect
107
+ "<RoleWriter role=#{@role} token=...>"
108
+ end
109
+ end
110
+
111
+ # @!visibility private
112
+ def initialize(data, bot, server = nil)
113
+ @bot = bot
114
+ @server = server
115
+ @permissions = Permissions.new(data['permissions'].to_i, RoleWriter.new(self, @bot.token))
116
+ @name = data['name']
117
+ @id = data['id'].to_i
118
+
119
+ @position = data['position']
120
+
121
+ @hoist = data['hoist']
122
+ @mentionable = data['mentionable']
123
+ @managed = data['managed']
124
+
125
+ colours = data['colors']
126
+ @colour = ColourRGB.new(colours['primary_color'])
127
+
128
+ @icon = data['icon']
129
+
130
+ @tags = Tags.new(data['tags']) if data['tags']
131
+
132
+ @flags = data['flags']
133
+
134
+ @unicode_emoji = data['unicode_emoji']
135
+
136
+ @tertiary_colour = ColourRGB.new(colours['tertiary_color']) if colours['tertiary_color']
137
+ @secondary_colour = ColourRGB.new(colours['secondary_color']) if colours['secondary_color']
138
+ end
139
+
140
+ # @return [String] a string that will mention this role, if it is mentionable.
141
+ def mention
142
+ "<@&#{@id}>"
143
+ end
144
+
145
+ # @return [Array<Member>] an array of members who have this role.
146
+ # @note This requests a member chunk if it hasn't for the server before, which may be slow initially
147
+ def members
148
+ @server.members.select { |m| m.role? self }
149
+ end
150
+
151
+ alias_method :users, :members
152
+
153
+ # Updates the data cache from a hash containing data
154
+ # @note For internal use only
155
+ # @!visibility private
156
+ def update_data(new_data)
157
+ @name = new_data['name']
158
+ @hoist = new_data['hoist']
159
+ @icon = new_data['icon']
160
+ @unicode_emoji = new_data['unicode_emoji']
161
+ @position = new_data['position']
162
+ @mentionable = new_data['mentionable']
163
+ @flags = new_data['flags']
164
+ colours = new_data['colors']
165
+ @managed = new_data['managed']
166
+ @permissions.bits = new_data['permissions'].to_i
167
+ @colour = ColourRGB.new(colours['primary_color'])
168
+ @tags = Tags.new(new_data['tags']) if new_data['tags']
169
+ @tertiary_colour = colours['tertiary_color'] ? ColourRGB.new(colours['tertiary_color']) : nil
170
+ @secondary_colour = colours['secondary_color'] ? ColourRGB.new(colours['secondary_color']) : nil
171
+ end
172
+
173
+ # Sets the role name to something new
174
+ # @param name [String, nil] The name that should be set.
175
+ def name=(name)
176
+ modify(name: name)
177
+ end
178
+
179
+ # Changes whether or not this role is displayed at the top of the user list
180
+ # @param hoist [true, false] The value it should be changed to
181
+ def hoist=(hoist)
182
+ modify(hoist: hoist)
183
+ end
184
+
185
+ # Changes whether or not this role can be mentioned
186
+ # @param mentionable [true, false] The value it should be changed to
187
+ def mentionable=(mentionable)
188
+ modify(mentionable: mentionable)
189
+ end
190
+
191
+ # Sets the primary role colour to something new.
192
+ # @param colour [ColourRGB, Integer, nil] The new colour.
193
+ def colour=(colour)
194
+ modify(colour: colour)
195
+ end
196
+
197
+ # Sets the secondary role colour to something new.
198
+ # @param colour [ColourRGB, Integer, nil] The new secondary colour.
199
+ def secondary_colour=(colour)
200
+ modify(secondary_colour: colour)
201
+ end
202
+
203
+ # Sets the tertiary role colour to something new.
204
+ # @param colour [ColourRGB, Integer, nil] The new tertiary colour.
205
+ def tertiary_colour=(colour)
206
+ modify(tertiary_colour: colour)
207
+ end
208
+
209
+ # Sets whether the role colour should be a holographic style.
210
+ # @param holographic [true, false] whether the role colour should be a holographic style.
211
+ def holographic=(holographic)
212
+ update_colours(holographic: holographic)
213
+ end
214
+
215
+ # Upload a role icon for servers with the ROLE_ICONS feature.
216
+ # @param file [File, nil] File like object that responds to #read, or nil.
217
+ def icon=(file)
218
+ modify(icon: file)
219
+ end
220
+
221
+ # Set a role icon to a unicode emoji for servers with the ROLE_ICONS feature.
222
+ # @param emoji [String, nil] The new unicode emoji for this role, or nil.
223
+ def unicode_emoji=(emoji)
224
+ modify(unicode_emoji: emoji)
225
+ end
226
+
227
+ # @param format ['webp', 'png', 'jpeg']
228
+ # @return [String] URL to the icon on Discord's CDN.
229
+ def icon_url(format = 'webp')
230
+ API.role_icon_url(@id, @icon, format) if @icon
231
+ end
232
+
233
+ # Get the icon that a role has displayed.
234
+ # @return [String, nil] Icon URL, the unicode emoji, or nil if this role doesn't have any icon.
235
+ # @note A role can have a unicode emoji, and an icon, but only the icon will be shown in the UI.
236
+ def display_icon
237
+ icon_url || unicode_emoji
238
+ end
239
+
240
+ # Set the icon this role is displaying.
241
+ # @param icon [File, String, nil] File like object that responds to #read, unicode emoji, or nil.
242
+ # @note Setting the icon to nil will remove the unicode emoji **and** the custom icon.
243
+ def display_icon=(icon)
244
+ modify(display_icon: icon)
245
+ end
246
+
247
+ # Whether or not the role is of the holographic style.
248
+ # @return [true, false]
249
+ def holographic?
250
+ !@tertiary_colour.nil?
251
+ end
252
+
253
+ # Whether or not the role has a two-point gradient.
254
+ # @return [true, false]
255
+ def gradient?
256
+ !@secondary_colour.nil? && @tertiary_colour.nil?
257
+ end
258
+
259
+ alias_method :color=, :colour=
260
+ alias_method :secondary_color=, :secondary_colour=
261
+ alias_method :tertiary_color=, :tertiary_colour=
262
+
263
+ # Changes this role's permissions to a fixed bitfield. This allows setting multiple permissions at once with just
264
+ # one API call.
265
+ #
266
+ # Information on how this bitfield is structured can be found at
267
+ # https://discord.com/developers/docs/topics/permissions.
268
+ # @example Remove all permissions from a role
269
+ # role.packed = 0
270
+ # @param permissions [Integer, nil] A bitfield with the desired permissions value.
271
+ # @param _update_perms [true, false] Whether the internal data should also be updated. This should always be true
272
+ # when calling externally. This is deprecated and no longer functional. Permissions data is always updated.
273
+ def packed=(permissions, _update_perms = true)
274
+ modify(permissions: permissions)
275
+ end
276
+
277
+ # Moves this role above another role in the list.
278
+ # @param other [Role, String, Integer, nil] The role, or its ID, above which this role should be moved. If it is `nil`,
279
+ # the role will be moved above the @everyone role.
280
+ # @return [Integer] the new position of this role
281
+ # @deprecated Please migrate to using {#move} with the `above` or `below` KWARGS.
282
+ def sort_above(other = nil)
283
+ other ? move(above: other) : move(bottom: true)
284
+ end
285
+
286
+ alias_method :move_above, :sort_above
287
+
288
+ # Deletes this role. This cannot be undone without recreating the role!
289
+ # @param reason [String] the reason for this role's deletion
290
+ def delete(reason = nil)
291
+ API::Server.delete_role(@bot.token, @server.id, @id, reason)
292
+ @server.delete_role(@id)
293
+ end
294
+
295
+ # Move the position of this role in the roles list.
296
+ # @example This will move the role 2 places above the `@everyone` role.
297
+ # role.move(bottom: true, offset: 2)
298
+ # @example This will move the role above the `@muted` role.
299
+ # role.move(above: 257017090932867072)
300
+ # @example This will move the role 3 spots below the `@moderator` role.
301
+ # role.move(below: 254077236989132800, offset: -3)
302
+ # @param bottom [true, false, nil] Whether to move the roles to the bottom of the role list.
303
+ # @param above [Integer, String, Role, nil] The role that this role should be moved above.
304
+ # @param below [Integer, String, Role, nil] The role that this role should be moved below.
305
+ # @param offset [Integer, nil] The number of roles to offset the new position by. A positive number will
306
+ # move the role above, and a negative number will move the role below. This parameter is relative and
307
+ # calculated after the `bottom`, `above`, and `below` parameters.
308
+ # @param reason [String, nil] The audit log reason to show for moving the role.
309
+ # @return [Integer] The new position of the role.
310
+ def move(bottom: nil, above: nil, below: nil, offset: 0, reason: nil)
311
+ if [bottom, above, below].count(&:itself) > 1
312
+ raise ArgumentError, "'bottom', 'above', and 'below' are mutually exclusive"
313
+ end
314
+
315
+ if (above || below) && !(target = @server.role(above || below))
316
+ raise ArgumentError, "The given 'above' or 'below' options are not valid"
317
+ end
318
+
319
+ if (below && target&.id == @server.id) || (@id == target&.id)
320
+ raise ArgumentError, 'The target role that was provded is not valid'
321
+ end
322
+
323
+ roles = @server.roles.sort_by { |role| [role.position, role.id] }
324
+
325
+ # Make sure we remove the current role.
326
+ myself = roles.rindex(@id).tap { |index| roles.delete_at(index) }
327
+
328
+ index = if bottom
329
+ 1
330
+ elsif below
331
+ roles.rindex(target)
332
+ elsif above
333
+ roles.rindex(target) + 1
334
+ else
335
+ myself
336
+ end
337
+
338
+ roles.insert([index + (offset || 0), 1].max, self)
339
+
340
+ roles = roles.map.with_index do |role, new_position|
341
+ { id: role.resolve_id, position: new_position }
342
+ end
343
+
344
+ @server.update_role_positions(roles, reason: reason)
345
+ @position
346
+ end
347
+
348
+ # A rich interface designed to make working with role colours simple.
349
+ # @param primary [ColourRGB, Integer, nil] The new primary/base colour of this role, or nil to clear the primary colour.
350
+ # @param secondary [ColourRGB, Integer, nil] The new secondary colour of this role, or nil to clear the secondary colour.
351
+ # @param tertiary [ColourRGB, Integer,nil] The new tertiary colour of this role, or nil to clear the tertiary colour.
352
+ # @param holographic [true, false] Whether to apply or remove the holographic style to the role colour, overriding any other
353
+ # arguments that were passed. Using this argument is recommended over passing individual colours.
354
+ # @param reason [String, nil] The audit log reason to show for updating the role's colours.
355
+ def update_colours(primary: :undef, secondary: :undef, tertiary: :undef, holographic: :undef, reason: nil)
356
+ colours = {
357
+ color: (primary == :undef ? @colour : primary)&.to_i,
358
+ tertiary_color: (tertiary == :undef ? @tertiary_colour : tertiary)&.to_i,
359
+ secondary_color: (secondary == :undef ? @secondary_colour : secondary)&.to_i
360
+ }
361
+
362
+ holographic_colours = {
363
+ color: 11_127_295,
364
+ tertiary_color: 16_761_760,
365
+ secondary_color: 16_759_788
366
+ }
367
+
368
+ # Only set the tertiary_color to `nil` if holographic is explicitly set to false.
369
+ (colours[:tertiary_color] = nil) if holographic.is_a?(FalseClass)
370
+
371
+ modify(reason: reason, **(holographic ? holographic_colours : colours))
372
+ end
373
+
374
+ alias_method :update_colors, :update_colours
375
+
376
+ # Modify the properties of the role.
377
+ # @param name [String, nil] The new 1-100 character name of the role.
378
+ # @param mentionable [true, false, nil] Whether or not anyone should be able to ping the role.
379
+ # @param hoist [true, false, nil] Whether or not members who have the role should be shown seperately in the sidebar.
380
+ # @param unicode_emoji [String, nil] The new unicode emoji to set as the role's icon.
381
+ # @param icon [#read, File, nil] The new custom icon of the role. Must be a file-like object that responds to `#read`.
382
+ # @param display_icon [String, #read, File, nil] The new display icon of the role. Mutually exclusive with `icon:` and `unicode_emoji:`.
383
+ # @param colour [ColourRGB, Integer, nil] The new primary colour of the role. Can also be passed as `color:`.
384
+ # @param secondary_colour [ColourRGB, Integer, nil] The new secondary colour of the role. Can also be passed as `secondary_color:`.
385
+ # @param tertiary_colour [ColourRGB, Integer, nil] The new tertiary colour of the role. Can also be passed as `tertiary_color:`.
386
+ # @param permissions [String, Integer, nil] The new permissions to set for the role.
387
+ # @param reason [String, nil] The reason to show in the server's audit log for modifying the role.
388
+ # @yieldparam builder [Permissions] An optional permissions builder. Arguments passed to the method overwrite builder data.
389
+ # @return [nil]
390
+ def modify(
391
+ name: :undef, mentionable: :undef, hoist: :undef, unicode_emoji: :undef, icon: :undef,
392
+ display_icon: :undef, color: :undef, colour: :undef, secondary_color: :undef,
393
+ secondary_colour: :undef, tertiary_color: :undef, tertiary_colour: :undef,
394
+ permissions: :undef, reason: nil
395
+ )
396
+ if display_icon != :undef
397
+ if icon != :undef || unicode_emoji != :undef
398
+ raise ArgumentError, "'display_icon' is mutually exclusive with 'icon' and 'unicode_emoji'"
399
+ end
400
+
401
+ if display_icon.nil?
402
+ icon = nil
403
+ unicode_emoji = nil
404
+ elsif display_icon.is_a?(String)
405
+ icon = nil
406
+ unicode_emoji = display_icon
407
+ elsif display_icon.respond_to?(:read)
408
+ icon = display_icon
409
+ unicode_emoji = nil
410
+ end
411
+ end
412
+
413
+ if block_given? && permissions == :undef
414
+ yield((builder = Permissions.new(@permissions.bits)))
415
+ permissions = builder.bits
416
+ end
417
+
418
+ data = {
419
+ name: name,
420
+ mentionable: mentionable,
421
+ hoist: hoist,
422
+ unicode_emoji: unicode_emoji,
423
+ icon: icon.respond_to?(:read) ? OnyxCord.encode64(icon) : icon,
424
+ permissions: permissions == :undef ? permissions : permissions&.to_s,
425
+ reason: reason
426
+ }
427
+
428
+ color = (colour == :undef ? color : colour)
429
+ tertiary = (tertiary_colour == :undef ? tertiary_color : tertiary_colour)
430
+ secondary = (secondary_colour == :undef ? secondary_color : secondary_colour)
431
+
432
+ if color != :undef || secondary != :undef || tertiary != :undef
433
+ data[:colors] = {
434
+ primary_color: (color == :undef ? @colour : color)&.to_i,
435
+ tertiary_color: (tertiary == :undef ? @tertiary_colour : tertiary)&.to_i,
436
+ secondary_color: (secondary == :undef ? @secondary_colour : secondary)&.to_i
437
+ }
438
+ end
439
+
440
+ update_data(JSON.parse(API::Server.update_role!(@bot.token, @server.id, @id, **data)))
441
+ nil
442
+ end
443
+
444
+ # The inspect method is overwritten to give more useful output
445
+ def inspect
446
+ "<Role name=#{@name} permissions=#{@permissions.inspect} hoist=#{@hoist} colour=#{@colour.inspect} server=#{@server.inspect} position=#{@position} mentionable=#{@mentionable} unicode_emoji=#{@unicode_emoji} flags=#{@flags}>"
447
+ end
448
+ end
449
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # Metadata about a role's linked connection.
5
+ class RoleConnectionMetadata
6
+ # Map of connection types.
7
+ TYPES = {
8
+ integer_less_than_or_equal: 1,
9
+ integer_greater_than_or_equal: 2,
10
+ integer_equal: 3,
11
+ integer_not_equal: 4,
12
+ datetime_less_than_or_equal: 5,
13
+ datetime_greater_than_or_equal: 6,
14
+ boolean_equal: 7,
15
+ boolean_not_equal: 8
16
+ }.freeze
17
+
18
+ # @return [String] the key of the metadata field.
19
+ attr_reader :key
20
+
21
+ # @return [String] the name of the metadata field.
22
+ attr_reader :name
23
+
24
+ # @return [Integer] the value of the metadata field.
25
+ attr_reader :type
26
+
27
+ # @return [String] the description of the metadata field.
28
+ attr_reader :description
29
+
30
+ # @return [Hash<String => String>] the name localizations of the metadata field.
31
+ attr_reader :name_localizations
32
+
33
+ # @return [Hash<String => String>] the description localizations of the metadata field.
34
+ attr_reader :description_localizations
35
+
36
+ # @!visibility private
37
+ def initialize(data, bot)
38
+ @bot = bot
39
+ @key = data['key']
40
+ @name = data['name']
41
+ @type = data['type']
42
+ @description = data['description']
43
+ @name_localizations = data['name_localizations'] || {}
44
+ @description_localizations = data['description_localizations'] || {}
45
+ end
46
+
47
+ # @!method integer_less_than_or_equal?
48
+ # @return [true, false] whether the numeric metadata value is less than or equivalent to the server's configured numeric value.
49
+ # @!method integer_greater_than_or_equal?
50
+ # @return [true, false] whether the numeric metadata value is greater than or equivalent to the server's configured numeric value.
51
+ # @!method integer_equal?
52
+ # @return [true, false] whether the numeric metadata value is equivalent to the server's configured numeric value.
53
+ # @!method integer_not_equal?
54
+ # @return [true, false] whether the numeric metadata value is not equivalent to the server's configured numeric value.
55
+ # @!method datetime_less_than_or_equal?
56
+ # @return [true, false] whether the ISO8601 date is less than or equivalent to the server's configured number of days before a date.
57
+ # @!method datetime_greater_than_or_equal?
58
+ # @return [true, false] whether the ISO8601 date is greater than or equivalent to the server's configured number of days before a date.
59
+ # @!method boolean_equal?
60
+ # @return [true, false] whether the boolean metadata value is equivalent to the server's configured boolean value.
61
+ # @!method boolean_not_equal?
62
+ # @return [true, false] whether the boolean metadata value is not equivalent to the server's configured boolean value.
63
+ TYPES.each do |name, value|
64
+ define_method("#{name}?") do
65
+ @type == value
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ # Metadata about a purchase or renewal for a role subscription.
5
+ class RoleSubscriptionData
6
+ # @return [String] the name of the tier the user is subscribed to.
7
+ attr_reader :tier_name
8
+
9
+ # @return [Integer] the ID of the SKU and listing the user is subscribed to.
10
+ attr_reader :listing_id
11
+
12
+ # @return [true, false] whether the subscription notification is for a renewal.
13
+ attr_reader :renewal
14
+ alias_method :renewal?, :renewal
15
+
16
+ # @return [Integer] the total number of months the user has been subscribed for.
17
+ attr_reader :total_months_subscribed
18
+
19
+ # @!visibility private
20
+ def initialize(data, message, bot)
21
+ @bot = bot
22
+ @message = message
23
+ @renewal = data['is_renewal']
24
+ @tier_name = data['tier_name']
25
+ @listing_id = data['role_subscription_listing_id']&.to_i
26
+ @total_months_subscribed = data['total_months_subscribed']
27
+ end
28
+
29
+ # Check if this role subscription is a new purchase.
30
+ # @return [true, false] if this role subscription is a new purchase.
31
+ def new?
32
+ @renewal == false
33
+ end
34
+
35
+ # Get the role associated with the notification for this subscription.
36
+ # @return [Role, nil] the role that's associated with this subscription.
37
+ def role
38
+ @message.server.roles.find { |role| role.tags&.subscription_listing_id == @listing_id }
39
+ end
40
+ end
41
+ end