discordrb 3.3.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +152 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  5. data/.github/pull_request_template.md +37 -0
  6. data/.github/workflows/codeql.yml +65 -0
  7. data/.markdownlint.json +4 -0
  8. data/.rubocop.yml +39 -36
  9. data/CHANGELOG.md +874 -552
  10. data/Gemfile +2 -0
  11. data/LICENSE.txt +1 -1
  12. data/README.md +80 -86
  13. data/Rakefile +2 -0
  14. data/bin/console +1 -0
  15. data/discordrb-webhooks.gemspec +9 -6
  16. data/discordrb.gemspec +21 -18
  17. data/lib/discordrb/allowed_mentions.rb +36 -0
  18. data/lib/discordrb/api/application.rb +202 -0
  19. data/lib/discordrb/api/channel.rb +236 -47
  20. data/lib/discordrb/api/interaction.rb +54 -0
  21. data/lib/discordrb/api/invite.rb +5 -5
  22. data/lib/discordrb/api/server.rb +94 -66
  23. data/lib/discordrb/api/user.rb +17 -11
  24. data/lib/discordrb/api/webhook.rb +63 -6
  25. data/lib/discordrb/api.rb +55 -16
  26. data/lib/discordrb/await.rb +0 -1
  27. data/lib/discordrb/bot.rb +480 -93
  28. data/lib/discordrb/cache.rb +31 -24
  29. data/lib/discordrb/colour_rgb.rb +43 -0
  30. data/lib/discordrb/commands/command_bot.rb +35 -12
  31. data/lib/discordrb/commands/container.rb +21 -24
  32. data/lib/discordrb/commands/parser.rb +20 -20
  33. data/lib/discordrb/commands/rate_limiter.rb +4 -3
  34. data/lib/discordrb/container.rb +209 -20
  35. data/lib/discordrb/data/activity.rb +271 -0
  36. data/lib/discordrb/data/application.rb +50 -0
  37. data/lib/discordrb/data/attachment.rb +71 -0
  38. data/lib/discordrb/data/audit_logs.rb +345 -0
  39. data/lib/discordrb/data/channel.rb +993 -0
  40. data/lib/discordrb/data/component.rb +229 -0
  41. data/lib/discordrb/data/embed.rb +251 -0
  42. data/lib/discordrb/data/emoji.rb +82 -0
  43. data/lib/discordrb/data/integration.rb +122 -0
  44. data/lib/discordrb/data/interaction.rb +800 -0
  45. data/lib/discordrb/data/invite.rb +137 -0
  46. data/lib/discordrb/data/member.rb +372 -0
  47. data/lib/discordrb/data/message.rb +414 -0
  48. data/lib/discordrb/data/overwrite.rb +108 -0
  49. data/lib/discordrb/data/profile.rb +91 -0
  50. data/lib/discordrb/data/reaction.rb +33 -0
  51. data/lib/discordrb/data/recipient.rb +34 -0
  52. data/lib/discordrb/data/role.rb +248 -0
  53. data/lib/discordrb/data/server.rb +1004 -0
  54. data/lib/discordrb/data/user.rb +264 -0
  55. data/lib/discordrb/data/voice_region.rb +45 -0
  56. data/lib/discordrb/data/voice_state.rb +41 -0
  57. data/lib/discordrb/data/webhook.rb +238 -0
  58. data/lib/discordrb/data.rb +28 -4180
  59. data/lib/discordrb/errors.rb +46 -4
  60. data/lib/discordrb/events/bans.rb +7 -5
  61. data/lib/discordrb/events/channels.rb +3 -1
  62. data/lib/discordrb/events/guilds.rb +16 -9
  63. data/lib/discordrb/events/interactions.rb +482 -0
  64. data/lib/discordrb/events/invites.rb +125 -0
  65. data/lib/discordrb/events/members.rb +6 -2
  66. data/lib/discordrb/events/message.rb +72 -27
  67. data/lib/discordrb/events/presence.rb +35 -18
  68. data/lib/discordrb/events/raw.rb +1 -3
  69. data/lib/discordrb/events/reactions.rb +49 -4
  70. data/lib/discordrb/events/threads.rb +96 -0
  71. data/lib/discordrb/events/typing.rb +6 -4
  72. data/lib/discordrb/events/voice_server_update.rb +47 -0
  73. data/lib/discordrb/events/voice_state_update.rb +15 -10
  74. data/lib/discordrb/events/webhooks.rb +9 -6
  75. data/lib/discordrb/gateway.rb +99 -71
  76. data/lib/discordrb/id_object.rb +39 -0
  77. data/lib/discordrb/light/integrations.rb +1 -1
  78. data/lib/discordrb/light/light_bot.rb +1 -1
  79. data/lib/discordrb/logger.rb +4 -4
  80. data/lib/discordrb/paginator.rb +57 -0
  81. data/lib/discordrb/permissions.rb +159 -39
  82. data/lib/discordrb/version.rb +1 -1
  83. data/lib/discordrb/voice/encoder.rb +16 -7
  84. data/lib/discordrb/voice/network.rb +99 -47
  85. data/lib/discordrb/voice/sodium.rb +98 -0
  86. data/lib/discordrb/voice/voice_bot.rb +33 -25
  87. data/lib/discordrb/webhooks.rb +2 -0
  88. data/lib/discordrb.rb +107 -1
  89. metadata +126 -54
  90. data/.codeclimate.yml +0 -16
  91. data/.travis.yml +0 -33
  92. data/bin/travis_build_docs.sh +0 -17
  93. /data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +0 -0
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # These classes hold relevant Discord data, such as messages or channels.
4
-
3
+ require 'discordrb/allowed_mentions'
5
4
  require 'discordrb/permissions'
5
+ require 'discordrb/id_object'
6
+ require 'discordrb/colour_rgb'
6
7
  require 'discordrb/errors'
7
8
  require 'discordrb/api'
8
9
  require 'discordrb/api/channel'
@@ -11,4184 +12,31 @@ require 'discordrb/api/invite'
11
12
  require 'discordrb/api/user'
12
13
  require 'discordrb/api/webhook'
13
14
  require 'discordrb/webhooks/embeds'
15
+ require 'discordrb/webhooks/view'
16
+ require 'discordrb/paginator'
14
17
  require 'time'
15
18
  require 'base64'
16
19
 
17
- # Discordrb module
18
- module Discordrb
19
- # The unix timestamp Discord IDs are based on
20
- DISCORD_EPOCH = 1_420_070_400_000
21
-
22
- # Compares two objects based on IDs - either the objects' IDs are equal, or one object is equal to the other's ID.
23
- def self.id_compare(one_id, other)
24
- other.respond_to?(:resolve_id) ? (one_id.resolve_id == other.resolve_id) : (one_id == other)
25
- end
26
-
27
- # The maximum length a Discord message can have
28
- CHARACTER_LIMIT = 2000
29
-
30
- # Splits a message into chunks of 2000 characters. Attempts to split by lines if possible.
31
- # @param msg [String] The message to split.
32
- # @return [Array<String>] the message split into chunks
33
- def self.split_message(msg)
34
- # If the messages is empty, return an empty array
35
- return [] if msg.empty?
36
-
37
- # Split the message into lines
38
- lines = msg.lines
39
-
40
- # Turn the message into a "triangle" of consecutively longer slices, for example the array [1,2,3,4] would become
41
- # [
42
- # [1],
43
- # [1, 2],
44
- # [1, 2, 3],
45
- # [1, 2, 3, 4]
46
- # ]
47
- tri = [*0..(lines.length - 1)].map { |i| lines.combination(i + 1).first }
48
-
49
- # Join the individual elements together to get an array of strings with consecutively more lines
50
- joined = tri.map(&:join)
51
-
52
- # Find the largest element that is still below the character limit, or if none such element exists return the first
53
- ideal = joined.max_by { |e| e.length > CHARACTER_LIMIT ? -1 : e.length }
54
-
55
- # If it's still larger than the character limit (none was smaller than it) split it into slices with the length
56
- # being the character limit, otherwise just return an array with one element
57
- ideal_ary = ideal.length > CHARACTER_LIMIT ? ideal.chars.each_slice(CHARACTER_LIMIT).map(&:join) : [ideal]
58
-
59
- # Slice off the ideal part and strip newlines
60
- rest = msg[ideal.length..-1].strip
61
-
62
- # If none remains, return an empty array -> we're done
63
- return [] unless rest
64
-
65
- # Otherwise, call the method recursively to split the rest of the string and add it onto the ideal array
66
- ideal_ary + split_message(rest)
67
- end
68
-
69
- # Mixin for objects that have IDs
70
- module IDObject
71
- # @return [Integer] the ID which uniquely identifies this object across Discord.
72
- attr_reader :id
73
- alias_method :resolve_id, :id
74
- alias_method :hash, :id
75
-
76
- # ID based comparison
77
- def ==(other)
78
- Discordrb.id_compare(@id, other)
79
- end
80
-
81
- alias_method :eql?, :==
82
-
83
- # Estimates the time this object was generated on based on the beginning of the ID. This is fairly accurate but
84
- # shouldn't be relied on as Discord might change its algorithm at any time
85
- # @return [Time] when this object was created at
86
- def creation_time
87
- # Milliseconds
88
- ms = (@id >> 22) + DISCORD_EPOCH
89
- Time.at(ms / 1000.0)
90
- end
91
-
92
- # Creates an artificial snowflake at the given point in time. Useful for comparing against.
93
- # @param time [Time] The time the snowflake should represent.
94
- # @return [Integer] a snowflake with the timestamp data as the given time
95
- def self.synthesise(time)
96
- ms = (time.to_f * 1000).to_i
97
- (ms - DISCORD_EPOCH) << 22
98
- end
99
-
100
- class << self
101
- alias_method :synthesize, :synthesise
102
- end
103
- end
104
-
105
- # Mixin for the attributes users should have
106
- module UserAttributes
107
- # @return [String] this user's username
108
- attr_reader :username
109
- alias_method :name, :username
110
-
111
- # @return [String] this user's discriminator which is used internally to identify users with identical usernames.
112
- attr_reader :discriminator
113
- alias_method :discrim, :discriminator
114
- alias_method :tag, :discriminator
115
- alias_method :discord_tag, :discriminator
116
-
117
- # @return [true, false] whether this user is a Discord bot account
118
- attr_reader :bot_account
119
- alias_method :bot_account?, :bot_account
120
-
121
- # @return [String] the ID of this user's current avatar, can be used to generate an avatar URL.
122
- # @see #avatar_url
123
- attr_accessor :avatar_id
124
-
125
- # Utility function to mention users in messages
126
- # @return [String] the mention code in the form of <@id>
127
- def mention
128
- "<@#{@id}>"
129
- end
130
-
131
- # Utility function to get Discord's distinct representation of a user, i.e. username + discriminator
132
- # @return [String] distinct representation of user
133
- def distinct
134
- "#{@username}##{@discriminator}"
135
- end
136
-
137
- # Utility function to get a user's avatar URL.
138
- # @param format [String, nil] If `nil`, the URL will default to `webp` for static avatars, and will detect if the user has a `gif` avatar. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this. Will always be PNG for default avatars.
139
- # @return [String] the URL to the avatar image.
140
- def avatar_url(format = nil)
141
- return API::User.default_avatar(@discriminator) unless @avatar_id
142
- API::User.avatar_url(@id, @avatar_id, format)
143
- end
144
- end
145
-
146
- # User on Discord, including internal data like discriminators
147
- class User
148
- include IDObject
149
- include UserAttributes
150
-
151
- # @return [Symbol] the current online status of the user (`:online`, `:offline` or `:idle`)
152
- attr_reader :status
153
-
154
- # @return [String, nil] the game the user is currently playing, or `nil` if none is being played.
155
- attr_reader :game
156
-
157
- # @return [String, nil] the URL to the stream, if the user is currently streaming something.
158
- attr_reader :stream_url
159
-
160
- # @return [String, Integer, nil] the type of the stream. Can technically be set to anything, most of the time it
161
- # will be 0 for no stream or 1 for Twitch streams.
162
- attr_reader :stream_type
163
-
164
- def initialize(data, bot)
165
- @bot = bot
166
-
167
- @username = data['username']
168
- @id = data['id'].to_i
169
- @discriminator = data['discriminator']
170
- @avatar_id = data['avatar']
171
- @roles = {}
172
-
173
- @bot_account = false
174
- @bot_account = true if data['bot']
175
-
176
- @status = :offline
177
- end
178
-
179
- # Get a user's PM channel or send them a PM
180
- # @overload pm
181
- # Creates a private message channel for this user or returns an existing one if it already exists
182
- # @return [Channel] the PM channel to this user.
183
- # @overload pm(content)
184
- # Sends a private to this user.
185
- # @param content [String] The content to send.
186
- # @return [Message] the message sent to this user.
187
- def pm(content = nil)
188
- if content
189
- # Recursively call pm to get the channel, then send a message to it
190
- channel = pm
191
- channel.send_message(content)
192
- else
193
- # If no message was specified, return the PM channel
194
- @bot.pm_channel(@id)
195
- end
196
- end
197
-
198
- alias_method :dm, :pm
199
-
200
- # Send the user a file.
201
- # @param file [File] The file to send to the user
202
- # @param caption [String] The caption of the file being sent
203
- # @return [Message] the message sent to this user.
204
- # @example Send a file from disk
205
- # user.send_file(File.open('rubytaco.png', 'r'))
206
- def send_file(file, caption = nil)
207
- pm.send_file(file, caption: caption)
208
- end
209
-
210
- # Set the user's name
211
- # @note for internal use only
212
- # @!visibility private
213
- def update_username(username)
214
- @username = username
215
- end
216
-
217
- # Set the user's presence data
218
- # @note for internal use only
219
- # @!visibility private
220
- def update_presence(data)
221
- @status = data['status'].to_sym
222
-
223
- if data['game']
224
- game = data['game']
225
-
226
- @game = game['name']
227
- @stream_url = game['url']
228
- @stream_type = game['type']
229
- else
230
- @game = @stream_url = @stream_type = nil
231
- end
232
- end
233
-
234
- # Add an await for a message from this user. Specifically, this adds a global await for a MessageEvent with this
235
- # user's ID as a :from attribute.
236
- # @see Bot#add_await
237
- def await(key, attributes = {}, &block)
238
- @bot.add_await(key, Discordrb::Events::MessageEvent, { from: @id }.merge(attributes), &block)
239
- end
240
-
241
- # Add a blocking await for a message from this user. Specifically, this adds a global await for a MessageEvent with this
242
- # user's ID as a :from attribute.
243
- # @see Bot#add_await!
244
- def await!(attributes = {})
245
- @bot.add_await!(Discordrb::Events::MessageEvent, { from: @id }.merge(attributes))
246
- end
247
-
248
- # Gets the member this user is on a server
249
- # @param server [Server] The server to get the member for
250
- # @return [Member] this user as a member on a particular server
251
- def on(server)
252
- id = server.resolve_id
253
- @bot.server(id).member(@id)
254
- end
255
-
256
- # Is the user the bot?
257
- # @return [true, false] whether this user is the bot
258
- def current_bot?
259
- @bot.profile.id == @id
260
- end
261
-
262
- # @return [true, false] whether this user is a fake user for a webhook message
263
- def webhook?
264
- @discriminator == Message::ZERO_DISCRIM
265
- end
266
-
267
- %i[offline idle online].each do |e|
268
- define_method(e.to_s + '?') do
269
- @status.to_sym == e
270
- end
271
- end
272
-
273
- # The inspect method is overwritten to give more useful output
274
- def inspect
275
- "<User username=#{@username} id=#{@id} discriminator=#{@discriminator}>"
276
- end
277
- end
278
-
279
- # OAuth Application information
280
- class Application
281
- include IDObject
282
-
283
- # @return [String] the application name
284
- attr_reader :name
285
-
286
- # @return [String] the application description
287
- attr_reader :description
288
-
289
- # @return [Array<String>] the application's origins permitted to use RPC
290
- attr_reader :rpc_origins
291
-
292
- # @return [Integer]
293
- attr_reader :flags
294
-
295
- # Gets the user object of the owner. May be limited to username, discriminator,
296
- # ID, and avatar if the bot cannot reach the owner.
297
- # @return [User] the user object of the owner
298
- attr_reader :owner
299
-
300
- def initialize(data, bot)
301
- @bot = bot
302
-
303
- @name = data['name']
304
- @id = data['id'].to_i
305
- @description = data['description']
306
- @icon_id = data['icon']
307
- @rpc_origins = data['rpc_origins']
308
- @flags = data['flags']
309
- @owner = @bot.ensure_user(data['owner'])
310
- end
311
-
312
- # Utility function to get a application's icon URL.
313
- # @return [String, nil] the URL of the icon image (nil if no image is set).
314
- def icon_url
315
- return nil if @icon_id.nil?
316
- API.app_icon_url(@id, @icon_id)
317
- end
318
-
319
- # The inspect method is overwritten to give more useful output
320
- def inspect
321
- "<Application name=#{@name} id=#{@id}>"
322
- end
323
- end
324
-
325
- # Mixin for the attributes members and private members should have
326
- module MemberAttributes
327
- # @return [Time] when this member joined the server.
328
- attr_reader :joined_at
329
-
330
- # @return [String, nil] the nickname this member has, or `nil` if it has none.
331
- attr_reader :nick
332
- alias_method :nickname, :nick
333
-
334
- # @return [Array<Role>] the roles this member has.
335
- attr_reader :roles
336
-
337
- # @return [Server] the server this member is on.
338
- attr_reader :server
339
- end
340
-
341
- # Mixin to calculate resulting permissions from overrides etc.
342
- module PermissionCalculator
343
- # Checks whether this user can do the particular action, regardless of whether it has the permission defined,
344
- # through for example being the server owner or having the Manage Roles permission
345
- # @param action [Symbol] The permission that should be checked. See also {Permissions::Flags} for a list.
346
- # @param channel [Channel, nil] If channel overrides should be checked too, this channel specifies where the overrides should be checked.
347
- # @example Check if the bot can send messages to a specific channel in a server.
348
- # bot_profile = bot.profile.on(event.server)
349
- # can_send_messages = bot_profile.permission?(:send_messages, channel)
350
- # @return [true, false] whether or not this user has the permission.
351
- def permission?(action, channel = nil)
352
- # If the member is the server owner, it irrevocably has all permissions.
353
- return true if owner?
354
-
355
- # First, check whether the user has Manage Roles defined.
356
- # (Coincidentally, Manage Permissions is the same permission as Manage Roles, and a
357
- # Manage Permissions deny overwrite will override Manage Roles, so we can just check for
358
- # Manage Roles once and call it a day.)
359
- return true if defined_permission?(:administrator, channel)
360
-
361
- # Otherwise, defer to defined_permission
362
- defined_permission?(action, channel)
363
- end
364
-
365
- # Checks whether this user has a particular permission defined (i.e. not implicit, through for example
366
- # Manage Roles)
367
- # @param action [Symbol] The permission that should be checked. See also {Permissions::Flags} for a list.
368
- # @param channel [Channel, nil] If channel overrides should be checked too, this channel specifies where the overrides should be checked.
369
- # @example Check if a member has the Manage Channels permission defined in the server.
370
- # has_manage_channels = member.defined_permission?(:manage_channels)
371
- # @return [true, false] whether or not this user has the permission defined.
372
- def defined_permission?(action, channel = nil)
373
- # Get the permission the user's roles have
374
- role_permission = defined_role_permission?(action, channel)
375
-
376
- # Once we have checked the role permission, we have to check the channel overrides for the
377
- # specific user
378
- user_specific_override = permission_overwrite(action, channel, id) # Use the ID reader as members have no ID instance variable
379
-
380
- # Merge the two permissions - if an override is defined, it has to be allow, otherwise we only care about the role
381
- return role_permission unless user_specific_override
382
- user_specific_override == :allow
383
- end
384
-
385
- # Define methods for querying permissions
386
- Discordrb::Permissions::Flags.each_value do |flag|
387
- define_method "can_#{flag}?" do |channel = nil|
388
- permission? flag, channel
389
- end
390
- end
391
-
392
- alias_method :can_administrate?, :can_administrator?
393
-
394
- private
395
-
396
- def defined_role_permission?(action, channel)
397
- roles_to_check = [@server.everyone_role] + @roles
398
-
399
- # For each role, check if
400
- # (1) the channel explicitly allows or permits an action for the role and
401
- # (2) if the user is allowed to do the action if the channel doesn't specify
402
- roles_to_check.reduce(false) do |can_act, role|
403
- # Get the override defined for the role on the channel
404
- channel_allow = permission_overwrite(action, channel, role.id)
405
- can_act = if channel_allow
406
- # If the channel has an override, check whether it is an allow - if yes,
407
- # the user can act, if not, it can't
408
- channel_allow == :allow
409
- else
410
- # Otherwise defer to the role
411
- role.permissions.instance_variable_get("@#{action}") || can_act
412
- end
413
- can_act
414
- end
415
- end
416
-
417
- def permission_overwrite(action, channel, id)
418
- # If no overwrites are defined, or no channel is set, no overwrite will be present
419
- return nil unless channel && channel.permission_overwrites[id]
420
-
421
- # Otherwise, check the allow and deny objects
422
- allow = channel.permission_overwrites[id].allow
423
- deny = channel.permission_overwrites[id].deny
424
- if allow.instance_variable_get("@#{action}")
425
- :allow
426
- elsif deny.instance_variable_get("@#{action}")
427
- :deny
428
- end
429
-
430
- # If there's no variable defined, nil will implicitly be returned
431
- end
432
- end
433
-
434
- # A voice state represents the state of a member's connection to a voice channel. It includes data like the voice
435
- # channel the member is connected to and mute/deaf flags.
436
- class VoiceState
437
- # @return [Integer] the ID of the user whose voice state is represented by this object.
438
- attr_reader :user_id
439
-
440
- # @return [true, false] whether this voice state's member is muted server-wide.
441
- attr_reader :mute
442
-
443
- # @return [true, false] whether this voice state's member is deafened server-wide.
444
- attr_reader :deaf
445
-
446
- # @return [true, false] whether this voice state's member has muted themselves.
447
- attr_reader :self_mute
448
-
449
- # @return [true, false] whether this voice state's member has deafened themselves.
450
- attr_reader :self_deaf
451
-
452
- # @return [Channel] the voice channel this voice state's member is in.
453
- attr_reader :voice_channel
454
-
455
- # @!visibility private
456
- def initialize(user_id)
457
- @user_id = user_id
458
- end
459
-
460
- # Update this voice state with new data from Discord
461
- # @note For internal use only.
462
- # @!visibility private
463
- def update(channel, mute, deaf, self_mute, self_deaf)
464
- @voice_channel = channel
465
- @mute = mute
466
- @deaf = deaf
467
- @self_mute = self_mute
468
- @self_deaf = self_deaf
469
- end
470
- end
471
-
472
- # Voice regions are the locations of servers that handle voice communication in Discord
473
- class VoiceRegion
474
- # @return [String] unique ID for the region
475
- attr_reader :id
476
- alias_method :to_s, :id
477
-
478
- # @return [String] name of the region
479
- attr_reader :name
480
-
481
- # @return [String] an example hostname for the region
482
- attr_reader :sample_hostname
483
-
484
- # @return [Integer] an example port for the region
485
- attr_reader :sample_port
486
-
487
- # @return [true, false] if this is a VIP-only server
488
- attr_reader :vip
489
-
490
- # @return [true, false] if this voice server is the closest to the client
491
- attr_reader :optimal
492
-
493
- # @return [true, false] whether this is a deprecated voice region (avoid switching to these)
494
- attr_reader :deprecated
495
-
496
- # @return [true, false] whether this is a custom voice region (used for events/etc)
497
- attr_reader :custom
498
-
499
- def initialize(data)
500
- @id = data['id']
501
-
502
- @name = data['name']
503
-
504
- @sample_hostname = data['sample_hostname']
505
- @sample_port = data['sample_port']
506
-
507
- @vip = data['vip']
508
- @optimal = data['optimal']
509
- @deprecated = data['deprecated']
510
- @custom = data['custom']
511
- end
512
- end
513
-
514
- # A member is a user on a server. It differs from regular users in that it has roles, voice statuses and things like
515
- # that.
516
- class Member < DelegateClass(User)
517
- # @return [true, false] whether this member is muted server-wide.
518
- def mute
519
- voice_state_attribute(:mute)
520
- end
521
-
522
- # @return [true, false] whether this member is deafened server-wide.
523
- def deaf
524
- voice_state_attribute(:deaf)
525
- end
526
-
527
- # @return [true, false] whether this member has muted themselves.
528
- def self_mute
529
- voice_state_attribute(:self_mute)
530
- end
531
-
532
- # @return [true, false] whether this member has deafened themselves.
533
- def self_deaf
534
- voice_state_attribute(:self_deaf)
535
- end
536
-
537
- # @return [Channel] the voice channel this member is in.
538
- def voice_channel
539
- voice_state_attribute(:voice_channel)
540
- end
541
-
542
- alias_method :muted?, :mute
543
- alias_method :deafened?, :deaf
544
- alias_method :self_muted?, :self_mute
545
- alias_method :self_deafened?, :self_deaf
546
-
547
- include MemberAttributes
548
-
549
- # @!visibility private
550
- def initialize(data, server, bot)
551
- @bot = bot
552
-
553
- @user = bot.ensure_user(data['user'])
554
- super @user # Initialize the delegate class
555
-
556
- # Somehow, Discord doesn't send the server ID in the standard member format...
557
- raise ArgumentError, 'Cannot create a member without any information about the server!' if server.nil? && data['guild_id'].nil?
558
- @server = server || bot.server(data['guild_id'].to_i)
559
-
560
- # Initialize the roles by getting the roles from the server one-by-one
561
- update_roles(data['roles'])
562
-
563
- @nick = data['nick']
564
- @joined_at = data['joined_at'] ? Time.parse(data['joined_at']) : nil
565
- end
566
-
567
- # @return [true, false] whether this member is the server owner.
568
- def owner?
569
- @server.owner == self
570
- end
571
-
572
- # @param role [Role, Integer, #resolve_id] the role to check or its ID.
573
- # @return [true, false] whether this member has the specified role.
574
- def role?(role)
575
- role = role.resolve_id
576
- @roles.any? { |e| e.id == role }
577
- end
578
-
579
- # @see Member#set_roles
580
- def roles=(role)
581
- set_roles(role)
582
- end
583
-
584
- # Bulk sets a member's roles.
585
- # @param role [Role, Array<Role>] The role(s) to set.
586
- # @param reason [String] The reason the user's roles are being changed.
587
- def set_roles(role, reason = nil)
588
- role_ids = role_id_array(role)
589
- API::Server.update_member(@bot.token, @server.id, @user.id, roles: role_ids, reason: reason)
590
- end
591
-
592
- # Adds and removes roles from a member.
593
- # @param add [Role, Array<Role>] The role(s) to add.
594
- # @param remove [Role, Array<Role>] The role(s) to remove.
595
- # @param reason [String] The reason the user's roles are being changed.
596
- # @example Remove the 'Member' role from a user, and add the 'Muted' role to them.
597
- # to_add = server.roles.find {|role| role.name == 'Muted'}
598
- # to_remove = server.roles.find {|role| role.name == 'Member'}
599
- # member.modify_roles(to_add, to_remove)
600
- def modify_roles(add, remove, reason = nil)
601
- add_role_ids = role_id_array(add)
602
- remove_role_ids = role_id_array(remove)
603
- old_role_ids = @roles.map(&:id)
604
- new_role_ids = (old_role_ids - remove_role_ids + add_role_ids).uniq
605
-
606
- API::Server.update_member(@bot.token, @server.id, @user.id, roles: new_role_ids, reason: reason)
607
- end
608
-
609
- # Adds one or more roles to this member.
610
- # @param role [Role, Array<Role, #resolve_id>, #resolve_id] The role(s) to add.
611
- # @param reason [String] The reason the user's roles are being changed.
612
- def add_role(role, reason = nil)
613
- role_ids = role_id_array(role)
614
-
615
- if role_ids.count == 1
616
- API::Server.add_member_role(@bot.token, @server.id, @user.id, role_ids[0], reason)
617
- else
618
- old_role_ids = @roles.map(&:id)
619
- new_role_ids = (old_role_ids + role_ids).uniq
620
- API::Server.update_member(@bot.token, @server.id, @user.id, roles: new_role_ids, reason: reason)
621
- end
622
- end
623
-
624
- # Removes one or more roles from this member.
625
- # @param role [Role, Array<Role>] The role(s) to remove.
626
- # @param reason [String] The reason the user's roles are being changed.
627
- def remove_role(role, reason = nil)
628
- role_ids = role_id_array(role)
629
-
630
- if role_ids.count == 1
631
- API::Server.remove_member_role(@bot.token, @server.id, @user.id, role_ids[0], reason)
632
- else
633
- old_role_ids = @roles.map(&:id)
634
- new_role_ids = old_role_ids.reject { |i| role_ids.include?(i) }
635
- API::Server.update_member(@bot.token, @server.id, @user.id, roles: new_role_ids, reason: reason)
636
- end
637
- end
638
-
639
- # @return [Role] the highest role this member has.
640
- def highest_role
641
- @roles.sort_by(&:position).last
642
- end
643
-
644
- # @return [Role, nil] the role this member is being hoisted with.
645
- def hoist_role
646
- hoisted_roles = @roles.select(&:hoist)
647
- return nil if hoisted_roles.empty?
648
- hoisted_roles.sort_by(&:position).last
649
- end
650
-
651
- # @return [Role, nil] the role this member is basing their colour on.
652
- def colour_role
653
- coloured_roles = @roles.select { |v| v.colour.combined.nonzero? }
654
- return nil if coloured_roles.empty?
655
- coloured_roles.sort_by(&:position).last
656
- end
657
- alias_method :color_role, :colour_role
658
-
659
- # @return [ColourRGB, nil] the colour this member has.
660
- def colour
661
- return nil unless colour_role
662
- colour_role.color
663
- end
664
- alias_method :color, :colour
665
-
666
- # Server deafens this member.
667
- def server_deafen
668
- API::Server.update_member(@bot.token, @server.id, @user.id, deaf: true)
669
- end
670
-
671
- # Server undeafens this member.
672
- def server_undeafen
673
- API::Server.update_member(@bot.token, @server.id, @user.id, deaf: false)
674
- end
675
-
676
- # Server mutes this member.
677
- def server_mute
678
- API::Server.update_member(@bot.token, @server.id, @user.id, mute: true)
679
- end
680
-
681
- # Server unmutes this member.
682
- def server_unmute
683
- API::Server.update_member(@bot.token, @server.id, @user.id, mute: false)
684
- end
685
-
686
- # @see Member#set_nick
687
- def nick=(nick)
688
- set_nick(nick)
689
- end
690
-
691
- alias_method :nickname=, :nick=
692
-
693
- # Sets or resets this member's nickname. Requires the Change Nickname permission for the bot itself and Manage
694
- # Nicknames for other users.
695
- # @param nick [String, nil] The string to set the nickname to, or nil if it should be reset.
696
- # @param reason [String] The reason the user's nickname is being changed.
697
- def set_nick(nick, reason = nil)
698
- # Discord uses the empty string to signify 'no nickname' so we convert nil into that
699
- nick ||= ''
700
-
701
- if @user.current_bot?
702
- API::User.change_own_nickname(@bot.token, @server.id, nick, reason)
703
- else
704
- API::Server.update_member(@bot.token, @server.id, @user.id, nick: nick, reason: nil)
705
- end
706
- end
707
-
708
- alias_method :set_nickname, :set_nick
709
-
710
- # @return [String] the name the user displays as (nickname if they have one, username otherwise)
711
- def display_name
712
- nickname || username
713
- end
714
-
715
- # Update this member's roles
716
- # @note For internal use only.
717
- # @!visibility private
718
- def update_roles(role_ids)
719
- @roles = []
720
- role_ids.each do |id|
721
- # It is posible for members to have roles that do not exist
722
- # on the server any longer. See https://github.com/meew0/discordrb/issues/371
723
- role = @server.role(id)
724
- @roles << role if role
725
- end
726
- end
727
-
728
- # Update this member's nick
729
- # @note For internal use only.
730
- # @!visibility private
731
- def update_nick(nick)
732
- @nick = nick
733
- end
734
-
735
- include PermissionCalculator
736
-
737
- # Overwriting inspect for debug purposes
738
- def inspect
739
- "<Member user=#{@user.inspect} server=#{@server.inspect} joined_at=#{@joined_at} roles=#{@roles.inspect} voice_channel=#{@voice_channel.inspect} mute=#{@mute} deaf=#{@deaf} self_mute=#{@self_mute} self_deaf=#{@self_deaf}>"
740
- end
741
-
742
- private
743
-
744
- # Utility method to get a list of role IDs from one role or an array of roles
745
- def role_id_array(role)
746
- if role.is_a? Array
747
- role.map(&:resolve_id)
748
- else
749
- [role.resolve_id]
750
- end
751
- end
752
-
753
- # Utility method to get data out of this member's voice state
754
- def voice_state_attribute(name)
755
- voice_state = @server.voice_states[@user.id]
756
- voice_state.send name if voice_state
757
- end
758
- end
759
-
760
- # Recipients are members on private channels - they exist for completeness purposes, but all
761
- # the attributes will be empty.
762
- class Recipient < DelegateClass(User)
763
- include MemberAttributes
764
-
765
- # @return [Channel] the private channel this recipient is the recipient of.
766
- attr_reader :channel
767
-
768
- # @!visibility private
769
- def initialize(user, channel, bot)
770
- @bot = bot
771
- @channel = channel
772
- raise ArgumentError, 'Tried to create a recipient for a public channel!' unless @channel.private?
773
-
774
- @user = user
775
- super @user
776
-
777
- # Member attributes
778
- @mute = @deaf = @self_mute = @self_deaf = false
779
- @voice_channel = nil
780
- @server = nil
781
- @roles = []
782
- @joined_at = @channel.creation_time
783
- end
784
-
785
- # Overwriting inspect for debug purposes
786
- def inspect
787
- "<Recipient user=#{@user.inspect} channel=#{@channel.inspect}>"
788
- end
789
- end
790
-
791
- # This class is a special variant of User that represents the bot's user profile (things like own username and the avatar).
792
- # It can be accessed using {Bot#profile}.
793
- class Profile < User
794
- def initialize(data, bot)
795
- super(data, bot)
796
- end
797
-
798
- # Whether or not the user is the bot. The Profile can only ever be the bot user, so this always returns true.
799
- # @return [true]
800
- def current_bot?
801
- true
802
- end
803
-
804
- # Sets the bot's username.
805
- # @param username [String] The new username.
806
- def username=(username)
807
- update_profile_data(username: username)
808
- end
809
-
810
- alias_method :name=, :username=
811
-
812
- # Changes the bot's avatar.
813
- # @param avatar [String, #read] A JPG file to be used as the avatar, either
814
- # something readable (e.g. File Object) or as a data URL.
815
- def avatar=(avatar)
816
- if avatar.respond_to? :read
817
- # Set the file to binary mode if supported, so we don't get problems with Windows
818
- avatar.binmode if avatar.respond_to?(:binmode)
819
-
820
- avatar_string = 'data:image/jpg;base64,'
821
- avatar_string += Base64.strict_encode64(avatar.read)
822
- update_profile_data(avatar: avatar_string)
823
- else
824
- update_profile_data(avatar: avatar)
825
- end
826
- end
827
-
828
- # Updates the cached profile data with the new one.
829
- # @note For internal use only.
830
- # @!visibility private
831
- def update_data(new_data)
832
- @username = new_data[:username] || @username
833
- @avatar_id = new_data[:avatar_id] || @avatar_id
834
- end
835
-
836
- # Sets the user status setting to Online.
837
- # @note Only usable on User accounts.
838
- def online
839
- update_profile_status_setting('online')
840
- end
841
-
842
- # Sets the user status setting to Idle.
843
- # @note Only usable on User accounts.
844
- def idle
845
- update_profile_status_setting('idle')
846
- end
847
-
848
- # Sets the user status setting to Do Not Disturb.
849
- # @note Only usable on User accounts.
850
- def dnd
851
- update_profile_status_setting('dnd')
852
- end
853
-
854
- alias_method(:busy, :dnd)
855
-
856
- # Sets the user status setting to Invisible.
857
- # @note Only usable on User accounts.
858
- def invisible
859
- update_profile_status_setting('invisible')
860
- end
861
-
862
- # The inspect method is overwritten to give more useful output
863
- def inspect
864
- "<Profile user=#{super}>"
865
- end
866
-
867
- private
868
-
869
- # Internal handler for updating the user's status setting
870
- def update_profile_status_setting(status)
871
- API::User.change_status_setting(@bot.token, status)
872
- end
873
-
874
- def update_profile_data(new_data)
875
- API::User.update_profile(@bot.token,
876
- nil, nil,
877
- new_data[:username] || @username,
878
- new_data.key?(:avatar) ? new_data[:avatar] : @avatar_id)
879
- update_data(new_data)
880
- end
881
- end
882
-
883
- # A Discord role that contains permissions and applies to certain users
884
- class Role
885
- include IDObject
886
-
887
- # @return [Permissions] this role's permissions.
888
- attr_reader :permissions
889
-
890
- # @return [String] this role's name ("new role" if it hasn't been changed)
891
- attr_reader :name
892
-
893
- # @return [Server] the server this role belongs to
894
- attr_reader :server
895
-
896
- # @return [true, false] whether or not this role should be displayed separately from other users
897
- attr_reader :hoist
898
-
899
- # @return [true, false] whether or not this role is managed by an integration or a bot
900
- attr_reader :managed
901
- alias_method :managed?, :managed
902
-
903
- # @return [true, false] whether this role can be mentioned using a role mention
904
- attr_reader :mentionable
905
- alias_method :mentionable?, :mentionable
906
-
907
- # @return [ColourRGB] the role colour
908
- attr_reader :colour
909
- alias_method :color, :colour
910
-
911
- # @return [Integer] the position of this role in the hierarchy
912
- attr_reader :position
913
-
914
- # This class is used internally as a wrapper to a Role object that allows easy writing of permission data.
915
- class RoleWriter
916
- # @!visibility private
917
- def initialize(role, token)
918
- @role = role
919
- @token = token
920
- end
921
-
922
- # Write the specified permission data to the role, without updating the permission cache
923
- # @param bits [Integer] The packed permissions to write.
924
- def write(bits)
925
- @role.send(:packed=, bits, false)
926
- end
927
-
928
- # The inspect method is overridden, in this case to prevent the token being leaked
929
- def inspect
930
- "<RoleWriter role=#{@role} token=...>"
931
- end
932
- end
933
-
934
- # @!visibility private
935
- def initialize(data, bot, server = nil)
936
- @bot = bot
937
- @server = server
938
- @permissions = Permissions.new(data['permissions'], RoleWriter.new(self, @bot.token))
939
- @name = data['name']
940
- @id = data['id'].to_i
941
-
942
- @position = data['position']
943
-
944
- @hoist = data['hoist']
945
- @mentionable = data['mentionable']
946
- @managed = data['managed']
947
-
948
- @colour = ColourRGB.new(data['color'])
949
- end
950
-
951
- # @return [String] a string that will mention this role, if it is mentionable.
952
- def mention
953
- "<@&#{@id}>"
954
- end
955
-
956
- # @return [Array<Member>] an array of members who have this role.
957
- # @note This requests a member chunk if it hasn't for the server before, which may be slow initially
958
- def members
959
- @server.members.select { |m| m.role? self }
960
- end
961
-
962
- alias_method :users, :members
963
-
964
- # Updates the data cache from another Role object
965
- # @note For internal use only
966
- # @!visibility private
967
- def update_from(other)
968
- @permissions = other.permissions
969
- @name = other.name
970
- @hoist = other.hoist
971
- @colour = other.colour
972
- @position = other.position
973
- @managed = other.managed
974
- end
975
-
976
- # Updates the data cache from a hash containing data
977
- # @note For internal use only
978
- # @!visibility private
979
- def update_data(new_data)
980
- @name = new_data[:name] || new_data['name'] || @name
981
- @hoist = new_data['hoist'] unless new_data['hoist'].nil?
982
- @hoist = new_data[:hoist] unless new_data[:hoist].nil?
983
- @colour = new_data[:colour] || (new_data['color'] ? ColourRGB.new(new_data['color']) : @colour)
984
- end
985
-
986
- # Sets the role name to something new
987
- # @param name [String] The name that should be set
988
- def name=(name)
989
- update_role_data(name: name)
990
- end
991
-
992
- # Changes whether or not this role is displayed at the top of the user list
993
- # @param hoist [true, false] The value it should be changed to
994
- def hoist=(hoist)
995
- update_role_data(hoist: hoist)
996
- end
997
-
998
- # Changes whether or not this role can be mentioned
999
- # @param mentionable [true, false] The value it should be changed to
1000
- def mentionable=(mentionable)
1001
- update_role_data(mentionable: mentionable)
1002
- end
1003
-
1004
- # Sets the role colour to something new
1005
- # @param colour [ColourRGB] The new colour
1006
- def colour=(colour)
1007
- update_role_data(colour: colour)
1008
- end
1009
-
1010
- alias_method :color=, :colour=
1011
-
1012
- # Changes this role's permissions to a fixed bitfield. This allows setting multiple permissions at once with just
1013
- # one API call.
1014
- #
1015
- # Information on how this bitfield is structured can be found at
1016
- # https://discordapp.com/developers/docs/topics/permissions.
1017
- # @example Remove all permissions from a role
1018
- # role.packed = 0
1019
- # @param packed [Integer] A bitfield with the desired permissions value.
1020
- # @param update_perms [true, false] Whether the internal data should also be updated. This should always be true
1021
- # when calling externally.
1022
- def packed=(packed, update_perms = true)
1023
- update_role_data(permissions: packed)
1024
- @permissions.bits = packed if update_perms
1025
- end
1026
-
1027
- # Moves this role above another role in the list.
1028
- # @param other [Role, #resolve_id, nil] The role above which this role should be moved. If it is `nil`,
1029
- # the role will be moved above the @everyone role.
1030
- # @return [Integer] the new position of this role
1031
- def sort_above(other = nil)
1032
- other = @server.role(other.resolve_id) if other
1033
- roles = @server.roles.sort_by(&:position)
1034
- roles.delete_at(@position)
1035
-
1036
- index = other ? roles.index { |role| role.id == other.id } + 1 : 1
1037
- roles.insert(index, self)
1038
-
1039
- updated_roles = roles.map.with_index { |role, position| { id: role.id, position: position } }
1040
- @server.update_role_positions(updated_roles)
1041
- index
1042
- end
1043
-
1044
- alias_method :move_above, :sort_above
1045
-
1046
- # Deletes this role. This cannot be undone without recreating the role!
1047
- # @param reason [String] the reason for this role's deletion
1048
- def delete(reason = nil)
1049
- API::Server.delete_role(@bot.token, @server.id, @id, reason)
1050
- @server.delete_role(@id)
1051
- end
1052
-
1053
- # The inspect method is overwritten to give more useful output
1054
- def inspect
1055
- "<Role name=#{@name} permissions=#{@permissions.inspect} hoist=#{@hoist} colour=#{@colour.inspect} server=#{@server.inspect}>"
1056
- end
1057
-
1058
- private
1059
-
1060
- def update_role_data(new_data)
1061
- API::Server.update_role(@bot.token, @server.id, @id,
1062
- new_data[:name] || @name,
1063
- (new_data[:colour] || @colour).combined,
1064
- new_data[:hoist].nil? ? @hoist : new_data[:hoist],
1065
- new_data[:mentionable].nil? ? @mentionable : new_data[:mentionable],
1066
- new_data[:permissions] || @permissions.bits)
1067
- update_data(new_data)
1068
- end
1069
- end
1070
-
1071
- # A channel referenced by an invite. It has less data than regular channels, so it's a separate class
1072
- class InviteChannel
1073
- include IDObject
1074
-
1075
- # @return [String] this channel's name.
1076
- attr_reader :name
1077
-
1078
- # @return [Integer] this channel's type (0: text, 1: private, 2: voice, 3: group).
1079
- attr_reader :type
1080
-
1081
- # @!visibility private
1082
- def initialize(data, bot)
1083
- @bot = bot
1084
-
1085
- @id = data['id'].to_i
1086
- @name = data['name']
1087
- @type = data['type']
1088
- end
1089
- end
1090
-
1091
- # A server referenced to by an invite
1092
- class InviteServer
1093
- include IDObject
1094
-
1095
- # @return [String] this server's name.
1096
- attr_reader :name
1097
-
1098
- # @return [String, nil] the hash of the server's invite splash screen (for partnered servers) or nil if none is
1099
- # present
1100
- attr_reader :splash_hash
1101
-
1102
- # @!visibility private
1103
- def initialize(data, bot)
1104
- @bot = bot
1105
-
1106
- @id = data['id'].to_i
1107
- @name = data['name']
1108
- @splash_hash = data['splash_hash']
1109
- end
1110
- end
1111
-
1112
- # A Discord invite to a channel
1113
- class Invite
1114
- # @return [InviteChannel] the channel this invite references.
1115
- attr_reader :channel
1116
-
1117
- # @return [InviteServer] the server this invite references.
1118
- attr_reader :server
1119
-
1120
- # @return [Integer] the amount of uses left on this invite.
1121
- attr_reader :uses
1122
- alias_method :max_uses, :uses
1123
-
1124
- # @return [User, nil] the user that made this invite. May also be nil if the user can't be determined.
1125
- attr_reader :inviter
1126
- alias_method :user, :inviter
1127
-
1128
- # @return [true, false] whether or not this invite grants temporary membership. If someone joins a server with this invite, they will be removed from the server when they go offline unless they've received a role.
1129
- attr_reader :temporary
1130
- alias_method :temporary?, :temporary
1131
-
1132
- # @return [true, false] whether this invite is still valid.
1133
- attr_reader :revoked
1134
- alias_method :revoked?, :revoked
1135
-
1136
- # @return [String] this invite's code
1137
- attr_reader :code
1138
-
1139
- # @return [Integer, nil] the amount of members in the server. Will be nil if it has not been resolved.
1140
- attr_reader :member_count
1141
- alias_method :user_count, :member_count
1142
-
1143
- # @return [Integer, nil] the amount of online members in the server. Will be nil if it has not been resolved.
1144
- attr_reader :online_member_count
1145
- alias_method :online_user_count, :online_member_count
1146
-
1147
- # @return [Integer, nil] the invites max age before it expires, or nil if it's unknown. If the max age is 0, the invite will never expire unless it's deleted.
1148
- attr_reader :max_age
1149
-
1150
- # @return [Time, nil] when this invite was created, or nil if it's unknown
1151
- attr_reader :created_at
1152
-
1153
- # @!visibility private
1154
- def initialize(data, bot)
1155
- @bot = bot
1156
-
1157
- @channel = InviteChannel.new(data['channel'], bot)
1158
- @server = InviteServer.new(data['guild'], bot)
1159
- @uses = data['uses']
1160
- @inviter = data['inviter'] ? (@bot.user(data['inviter']['id'].to_i) || User.new(data['inviter'], bot)) : nil
1161
- @temporary = data['temporary']
1162
- @revoked = data['revoked']
1163
- @online_member_count = data['approximate_presence_count']
1164
- @member_count = data['approximate_member_count']
1165
- @max_age = data['max_age']
1166
- @created_at = data['created_at']
1167
-
1168
- @code = data['code']
1169
- end
1170
-
1171
- # Code based comparison
1172
- def ==(other)
1173
- other.respond_to?(:code) ? (@code == other.code) : (@code == other)
1174
- end
1175
-
1176
- # Deletes this invite
1177
- # @param reason [String] The reason the invite is being deleted.
1178
- def delete(reason = nil)
1179
- API::Invite.delete(@bot.token, @code, reason)
1180
- end
1181
-
1182
- alias_method :revoke, :delete
1183
-
1184
- # The inspect method is overwritten to give more useful output
1185
- def inspect
1186
- "<Invite code=#{@code} channel=#{@channel} uses=#{@uses} temporary=#{@temporary} revoked=#{@revoked} created_at=#{@created_at} max_age=#{@max_age}>"
1187
- end
1188
-
1189
- # Creates an invite URL.
1190
- def url
1191
- "https://discord.gg/#{@code}"
1192
- end
1193
- end
1194
-
1195
- # A permissions overwrite, when applied to channels describes additional
1196
- # permissions a member needs to perform certain actions in context.
1197
- class Overwrite
1198
- # @return [Integer] id of the thing associated with this overwrite type
1199
- attr_accessor :id
1200
-
1201
- # @return [Symbol] either :role or :member
1202
- attr_accessor :type
1203
-
1204
- # @return [Permissions] allowed permissions for this overwrite type
1205
- attr_accessor :allow
1206
-
1207
- # @return [Permissions] denied permissions for this overwrite type
1208
- attr_accessor :deny
1209
-
1210
- # Creates a new Overwrite object
1211
- # @example Create an overwrite for a role that can mention everyone, send TTS messages, but can't create instant invites
1212
- # allow = Discordrb::Permissions.new
1213
- # allow.can_mention_everyone = true
1214
- # allow.can_send_tts_messages = true
1215
- #
1216
- # deny = Discordrb::Permissions.new
1217
- # deny.can_create_instant_invite = true
1218
- #
1219
- # # Find some role by name
1220
- # role = server.roles.find { |r| r.name == 'some role' }
1221
- #
1222
- # Overwrite.new(role, allow: allow, deny: deny)
1223
- # @example Create an overwrite by ID and permissions bits
1224
- # Overwrite.new(120571255635181568, type: 'member', allow: 1024, deny: 0)
1225
- # @param object [Integer, #id] the ID or object this overwrite is for
1226
- # @param type [String] the type of object this overwrite is for (only required if object is an Integer)
1227
- # @param allow [Integer, Permissions] allowed permissions for this overwrite, by bits or a Permissions object
1228
- # @param deny [Integer, Permissions] denied permissions for this overwrite, by bits or a Permissions object
1229
- # @raise [ArgumentError] if type is not :member or :role
1230
- def initialize(object = nil, type: nil, allow: 0, deny: 0)
1231
- if type
1232
- type = type.to_sym
1233
- raise ArgumentError, 'Overwrite type must be :member or :role' unless (type != :member) || (type != :role)
1234
- end
1235
-
1236
- @id = object.respond_to?(:id) ? object.id : object
1237
-
1238
- @type = if object.is_a?(User) || object.is_a?(Member) || object.is_a?(Recipient) || object.is_a?(Profile)
1239
- :member
1240
- elsif object.is_a? Role
1241
- :role
1242
- else
1243
- type
1244
- end
1245
-
1246
- @allow = allow.is_a?(Permissions) ? allow : Permissions.new(allow)
1247
- @deny = deny.is_a?(Permissions) ? deny : Permissions.new(deny)
1248
- end
1249
-
1250
- # Comparison by attributes [:id, :type, :allow, :deny]
1251
- def ==(other)
1252
- false unless other.is_a? Discordrb::Overwrite
1253
- id == other.id &&
1254
- type == other.type &&
1255
- allow == other.allow &&
1256
- deny == other.deny
1257
- end
1258
-
1259
- # @return [Overwrite] create an overwrite from a hash payload
1260
- # @!visibility private
1261
- def self.from_hash(data)
1262
- new(
1263
- data['id'].to_i,
1264
- type: data['type'],
1265
- allow: Permissions.new(data['allow']),
1266
- deny: Permissions.new(data['deny'])
1267
- )
1268
- end
1269
-
1270
- # @return [Overwrite] copies an overwrite from another Overwrite
1271
- # @!visibility private
1272
- def self.from_other(other)
1273
- new(
1274
- other.id,
1275
- type: other.type,
1276
- allow: Permissions.new(other.allow.bits),
1277
- deny: Permissions.new(other.deny.bits)
1278
- )
1279
- end
1280
-
1281
- # @return [Hash] hash representation of an overwrite
1282
- # @!visibility private
1283
- def to_hash
1284
- {
1285
- id: id,
1286
- type: type,
1287
- allow: allow.bits,
1288
- deny: deny.bits
1289
- }
1290
- end
1291
- end
1292
-
1293
- # A Discord channel, including data like the topic
1294
- class Channel
1295
- include IDObject
1296
-
1297
- # Map of channel types
1298
- TYPES = {
1299
- text: 0,
1300
- dm: 1,
1301
- voice: 2,
1302
- group: 3,
1303
- category: 4
1304
- }.freeze
1305
-
1306
- # @return [String] this channel's name.
1307
- attr_reader :name
1308
-
1309
- # @return [Server, nil] the server this channel is on. If this channel is a PM channel, it will be nil.
1310
- attr_reader :server
1311
-
1312
- # @return [Integer, nil] the ID of the parent channel, if this channel is inside a cateogry
1313
- attr_reader :parent_id
1314
-
1315
- # @return [Integer] the type of this channel (0: text, 1: private, 2: voice, 3: group)
1316
- attr_reader :type
1317
-
1318
- # @return [Integer, nil] the id of the owner of the group channel or nil if this is not a group channel.
1319
- attr_reader :owner_id
1320
-
1321
- # @return [Array<Recipient>, nil] the array of recipients of the private messages, or nil if this is not a Private channel
1322
- attr_reader :recipients
1323
-
1324
- # @return [String] the channel's topic
1325
- attr_reader :topic
1326
-
1327
- # @return [Integer] the bitrate (in bps) of the channel
1328
- attr_reader :bitrate
1329
-
1330
- # @return [Integer] the amount of users that can be in the channel. `0` means it is unlimited.
1331
- attr_reader :user_limit
1332
- alias_method :limit, :user_limit
1333
-
1334
- # @return [Integer] the channel's position on the channel list
1335
- attr_reader :position
1336
-
1337
- # @return [true, false] if this channel is marked as nsfw
1338
- attr_reader :nsfw
1339
- alias_method :nsfw?, :nsfw
1340
-
1341
- # @return [Integer] the amount of time (in seconds) users need to wait to send in between messages.
1342
- attr_reader :rate_limit_per_user
1343
- alias_method :slowmode_rate, :rate_limit_per_user
1344
-
1345
- # @return [true, false] whether or not this channel is a PM or group channel.
1346
- def private?
1347
- pm? || group?
1348
- end
1349
-
1350
- # @return [String] a string that will mention the channel as a clickable link on Discord.
1351
- def mention
1352
- "<##{@id}>"
1353
- end
1354
-
1355
- # @return [Recipient, nil] the recipient of the private messages, or nil if this is not a PM channel
1356
- def recipient
1357
- @recipients.first if pm?
1358
- end
1359
-
1360
- # @!visibility private
1361
- def initialize(data, bot, server = nil)
1362
- @bot = bot
1363
- # data is sometimes a Hash and other times an array of Hashes, you only want the last one if it's an array
1364
- data = data[-1] if data.is_a?(Array)
1365
-
1366
- @id = data['id'].to_i
1367
- @type = data['type'] || 0
1368
- @topic = data['topic']
1369
- @bitrate = data['bitrate']
1370
- @user_limit = data['user_limit']
1371
- @position = data['position']
1372
- @parent_id = data['parent_id'].to_i if data['parent_id']
1373
-
1374
- if private?
1375
- @recipients = []
1376
- if data['recipients']
1377
- data['recipients'].each do |recipient|
1378
- recipient_user = bot.ensure_user(recipient)
1379
- @recipients << Recipient.new(recipient_user, self, bot)
1380
- end
1381
- end
1382
- if pm?
1383
- @name = @recipients.first.username
1384
- else
1385
- @name = data['name']
1386
- @owner_id = data['owner_id']
1387
- end
1388
- else
1389
- @name = data['name']
1390
- @server = if server
1391
- server
1392
- else
1393
- bot.server(data['guild_id'].to_i)
1394
- end
1395
- end
1396
-
1397
- @nsfw = data['nsfw'] || false || @name.start_with?('nsfw')
1398
- @rate_limit_per_user = data['rate_limit_per_user'] || 0
1399
-
1400
- process_permission_overwrites(data['permission_overwrites'])
1401
- end
1402
-
1403
- # @return [true, false] whether or not this channel is a text channel
1404
- def text?
1405
- @type.zero?
1406
- end
1407
-
1408
- # @return [true, false] whether or not this channel is a PM channel.
1409
- def pm?
1410
- @type == 1
1411
- end
1412
-
1413
- # @return [true, false] whether or not this channel is a voice channel.
1414
- def voice?
1415
- @type == 2
1416
- end
1417
-
1418
- # @return [true, false] whether or not this channel is a group channel.
1419
- def group?
1420
- @type == 3
1421
- end
1422
-
1423
- # @return [true, false]
1424
- def category?
1425
- @type == 4
1426
- end
1427
-
1428
- # @return [Channel, nil] the category channel, if this channel is in a category
1429
- def category
1430
- @bot.channel(@parent_id) if @parent_id
1431
- end
1432
-
1433
- alias_method :parent, :category
1434
-
1435
- # Sets this channels parent category
1436
- # @param channel [Channel, #resolve_id] the target category channel
1437
- # @raise [ArgumentError] if the target channel isn't a category
1438
- def category=(channel)
1439
- channel = @bot.channel(channel)
1440
- raise ArgumentError, 'Cannot set parent category to a channel that isn\'t a category' unless channel.category?
1441
- update_channel_data(parent_id: channel.id)
1442
- end
1443
-
1444
- alias_method :parent=, :category=
1445
-
1446
- # Sorts this channel's position to follow another channel.
1447
- # @param other [Channel, #resolve_id, nil] The channel below which this channel should be sorted. If the given
1448
- # channel is a category, this channel will be sorted at the top of that category. If it is `nil`, the channel will
1449
- # be sorted at the top of the channel list.
1450
- # @param lock_permissions [true, false] Whether the channel's permissions should be synced to the category's
1451
- def sort_after(other = nil, lock_permissions = false)
1452
- raise TypeError, 'other must be one of Channel, NilClass, or #resolve_id' unless other.is_a?(Channel) || other.nil? || other.respond_to?(:resolve_id)
1453
- other = @bot.channel(other.resolve_id) if other
1454
-
1455
- # Container for the API request payload
1456
- move_argument = []
1457
-
1458
- if other
1459
- raise ArgumentError, 'Can only sort a channel after a channel of the same type!' unless other.category? || (@type == other.type)
1460
-
1461
- raise ArgumentError, 'Can only sort a channel after a channel in the same server!' unless other.server == server
1462
-
1463
- # Store `others` parent (or if `other` is a category itself)
1464
- parent = if category? && other.category?
1465
- # If we're sorting two categories, there is no new parent
1466
- nil
1467
- elsif other.category?
1468
- # `other` is the category this channel will be moved into
1469
- other
1470
- else
1471
- # `other`'s parent is the category this channel will be
1472
- # moved into (if it exists)
1473
- other.parent
1474
- end
1475
- end
1476
-
1477
- # Collect and sort the IDs within the context (category or not) that we
1478
- # need to form our payload with
1479
- ids = if parent
1480
- parent.children
1481
- else
1482
- @server.channels.reject(&:parent_id).select { |c| c.type == @type }
1483
- end.sort_by(&:position).map(&:id)
1484
-
1485
- # Move our channel ID after the target ID by deleting it,
1486
- # getting the index of `other`, and inserting it after.
1487
- ids.delete(@id) if ids.include?(@id)
1488
- index = other ? (ids.index { |c| c == other.id } || -1) + 1 : 0
1489
- ids.insert(index, @id)
1490
-
1491
- # Generate `move_argument`, making the positions in order from how
1492
- # we have sorted them in the above logic
1493
- ids.each_with_index do |id, pos|
1494
- # These keys are present in each element
1495
- hash = { id: id, position: pos }
1496
-
1497
- # Conditionally add `lock_permissions` and `parent_id` if we're
1498
- # iterating past ourself
1499
- if id == @id
1500
- hash[:lock_permissions] = true if lock_permissions
1501
- hash[:parent_id] = parent.nil? ? nil : parent.id
1502
- end
1503
-
1504
- # Add it to the stack
1505
- move_argument << hash
1506
- end
1507
-
1508
- API::Server.update_channel_positions(@bot.token, @server.id, move_argument)
1509
- end
1510
-
1511
- # Sets whether this channel is NSFW
1512
- # @param nsfw [true, false]
1513
- # @raise [ArguementError] if value isn't one of true, false
1514
- def nsfw=(nsfw)
1515
- raise ArgumentError, 'nsfw value must be true or false' unless nsfw.is_a?(TrueClass) || nsfw.is_a?(FalseClass)
1516
- update_channel_data(nsfw: nsfw)
1517
- end
1518
-
1519
- # This channel's permission overwrites
1520
- # @overload permission_overwrites
1521
- # The overwrites represented as a hash of role/user ID
1522
- # to an Overwrite object
1523
- # @return [Hash<Integer => Overwrite>] the channel's permission overwrites
1524
- # @overload permission_overwrites(type)
1525
- # Return an array of a certain type of overwrite
1526
- # @param type [Symbol] the kind of overwrite to return
1527
- # @return [Array<Overwrite>]
1528
- def permission_overwrites(type = nil)
1529
- return @permission_overwrites unless type
1530
- @permission_overwrites.values.select { |e| e.type == type }
1531
- end
1532
-
1533
- alias_method :overwrites, :permission_overwrites
1534
-
1535
- # Bulk sets this channels permission overwrites
1536
- # @param overwrites [Array<Overwrite>]
1537
- def permission_overwrites=(overwrites)
1538
- update_channel_data(permission_overwrites: overwrites)
1539
- end
1540
-
1541
- # Sets the amount of time (in seconds) users have to wait in between sending messages.
1542
- # @param rate [Integer]
1543
- # @raise [ArgumentError] if value isn't between 0 and 120
1544
- def rate_limit_per_user=(rate)
1545
- raise ArgumentError, 'rate_limit_per_user must be between 0 and 120' unless rate.between?(0, 120)
1546
- update_channel_data(rate_limit_per_user: rate)
1547
- end
1548
-
1549
- alias_method :slowmode_rate=, :rate_limit_per_user=
1550
-
1551
- # Syncs this channels overwrites with its parent category
1552
- # @raise [RuntimeError] if this channel is not in a category
1553
- def sync_overwrites
1554
- raise 'Cannot sync overwrites on a channel with no parent category' unless parent
1555
- self.permission_overwrites = parent.permission_overwrites
1556
- end
1557
-
1558
- alias_method :sync, :sync_overwrites
1559
-
1560
- # @return [true, false, nil] whether this channels permissions match the permission overwrites of the category that it's in, or nil if it is not in a category
1561
- def synchronized?
1562
- return unless parent
1563
- permission_overwrites == parent.permission_overwrites
1564
- end
1565
-
1566
- alias_method :synced?, :synchronized?
1567
-
1568
- # Returns the children of this channel, if it is a category. Otherwise returns an empty array.
1569
- # @return [Array<Channel>]
1570
- def children
1571
- return [] unless category?
1572
- server.channels.select { |c| c.parent_id == id }
1573
- end
1574
-
1575
- alias_method :channels, :children
1576
-
1577
- # Returns the text channels in this category, if it is a category channel. Otherwise returns an empty array.
1578
- # @return [Array<Channel>]
1579
- def text_channels
1580
- children.select(&:text?)
1581
- end
1582
-
1583
- # Returns the voice channels in this category, if it is a category channel. Otherwise returns an empty array.
1584
- # @return [Array<Channel>]
1585
- def voice_channels
1586
- children.select(&:voice?)
1587
- end
1588
-
1589
- # @return [Overwrite] any member-type permission overwrites on this channel
1590
- def member_overwrites
1591
- permission_overwrites :member
1592
- end
1593
-
1594
- # @return [Overwrite] any role-type permission overwrites on this channel
1595
- def role_overwrites
1596
- permission_overwrites :role
1597
- end
1598
-
1599
- # @return [true, false] whether or not this channel is the default channel
1600
- def default_channel?
1601
- server.default_channel == self
1602
- end
1603
-
1604
- alias_method :default?, :default_channel?
1605
-
1606
- # @return [true, false] whether or not this channel has slowmode enabled
1607
- def slowmode?
1608
- @rate_limit_per_user != 0
1609
- end
1610
-
1611
- # Sends a message to this channel.
1612
- # @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
1613
- # @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
1614
- # @param embed [Hash, Discordrb::Webhooks::Embed, nil] The rich embed to append to this message.
1615
- # @return [Message] the message that was sent.
1616
- def send_message(content, tts = false, embed = nil)
1617
- @bot.send_message(@id, content, tts, embed)
1618
- end
1619
-
1620
- alias_method :send, :send_message
1621
-
1622
- # Sends a temporary message to this channel.
1623
- # @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
1624
- # @param timeout [Float] The amount of time in seconds after which the message sent will be deleted.
1625
- # @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
1626
- # @param embed [Hash, Discordrb::Webhooks::Embed, nil] The rich embed to append to this message.
1627
- def send_temporary_message(content, timeout, tts = false, embed = nil)
1628
- @bot.send_temporary_message(@id, content, timeout, tts, embed)
1629
- end
1630
-
1631
- # Convenience method to send a message with an embed.
1632
- # @example Send a message with an embed
1633
- # channel.send_embed do |embed|
1634
- # embed.title = 'The Ruby logo'
1635
- # embed.image = Discordrb::Webhooks::EmbedImage.new(url: 'https://www.ruby-lang.org/images/header-ruby-logo.png')
1636
- # end
1637
- # @param message [String] The message that should be sent along with the embed. If this is the empty string, only the embed will be shown.
1638
- # @param embed [Discordrb::Webhooks::Embed, nil] The embed to start the building process with, or nil if one should be created anew.
1639
- # @yield [embed] Yields the embed to allow for easy building inside a block.
1640
- # @yieldparam embed [Discordrb::Webhooks::Embed] The embed from the parameters, or a new one.
1641
- # @return [Message] The resulting message.
1642
- def send_embed(message = '', embed = nil)
1643
- embed ||= Discordrb::Webhooks::Embed.new
1644
- yield(embed) if block_given?
1645
- send_message(message, false, embed)
1646
- end
1647
-
1648
- # Sends multiple messages to a channel
1649
- # @param content [Array<String>] The messages to send.
1650
- def send_multiple(content)
1651
- content.each { |e| send_message(e) }
1652
- end
1653
-
1654
- # Splits a message into chunks whose length is at most the Discord character limit, then sends them individually.
1655
- # Useful for sending long messages, but be wary of rate limits!
1656
- def split_send(content)
1657
- send_multiple(Discordrb.split_message(content))
1658
- end
1659
-
1660
- # Sends a file to this channel. If it is an image, it will be embedded.
1661
- # @param file [File] The file to send. There's no clear size limit for this, you'll have to attempt it for yourself (most non-image files are fine, large images may fail to embed)
1662
- # @param caption [string] The caption for the file.
1663
- # @param tts [true, false] Whether or not this file's caption should be sent using Discord text-to-speech.
1664
- # @example Send a file from disk
1665
- # channel.send_file(File.open('rubytaco.png', 'r'))
1666
- def send_file(file, caption: nil, tts: false)
1667
- @bot.send_file(@id, file, caption: caption, tts: tts)
1668
- end
1669
-
1670
- # Deletes a message on this channel. Mostly useful in case a message needs to be deleted when only the ID is known
1671
- # @param message [Message, String, Integer, #resolve_id] The message that should be deleted.
1672
- def delete_message(message)
1673
- API::Channel.delete_message(@bot.token, @id, message.resolve_id)
1674
- end
1675
-
1676
- # Permanently deletes this channel
1677
- # @param reason [String] The reason the for the channel deletion.
1678
- def delete(reason = nil)
1679
- API::Channel.delete(@bot.token, @id, reason)
1680
- end
1681
-
1682
- # Sets this channel's name. The name must be alphanumeric with dashes, unless this is a voice channel (then there are no limitations)
1683
- # @param name [String] The new name.
1684
- def name=(name)
1685
- update_channel_data(name: name)
1686
- end
1687
-
1688
- # Sets this channel's topic.
1689
- # @param topic [String] The new topic.
1690
- def topic=(topic)
1691
- raise 'Tried to set topic on voice channel' if voice?
1692
- update_channel_data(topic: topic)
1693
- end
1694
-
1695
- # Sets this channel's bitrate.
1696
- # @param bitrate [Integer] The new bitrate (in bps). Number has to be between 8000-96000 (128000 for VIP servers)
1697
- def bitrate=(bitrate)
1698
- raise 'Tried to set bitrate on text channel' if text?
1699
- update_channel_data(bitrate: bitrate)
1700
- end
1701
-
1702
- # Sets this channel's user limit.
1703
- # @param limit [Integer] The new user limit. `0` for unlimited, has to be a number between 0-99
1704
- def user_limit=(limit)
1705
- raise 'Tried to set user_limit on text channel' if text?
1706
- update_channel_data(user_limit: limit)
1707
- end
1708
-
1709
- alias_method :limit=, :user_limit=
1710
-
1711
- # Sets this channel's position in the list.
1712
- # @param position [Integer] The new position.
1713
- def position=(position)
1714
- update_channel_data(position: position)
1715
- end
1716
-
1717
- # Defines a permission overwrite for this channel that sets the specified thing to the specified allow and deny
1718
- # permission sets, or change an existing one.
1719
- # @overload define_overwrite(overwrite)
1720
- # @param thing [Overwrite] an Overwrite object to apply to this channel
1721
- # @param reason [String] The reason the for defining the overwrite.
1722
- # @overload define_overwrite(thing, allow, deny)
1723
- # @param thing [User, Role] What to define an overwrite for.
1724
- # @param allow [#bits, Permissions, Integer] The permission sets that should receive an `allow` override (i.e. a
1725
- # green checkmark on Discord)
1726
- # @param deny [#bits, Permissions, Integer] The permission sets that should receive a `deny` override (i.e. a red
1727
- # cross on Discord)
1728
- # @param reason [String] The reason the for defining the overwrite.
1729
- # @example Define a permission overwrite for a user that can then mention everyone and use TTS, but not create any invites
1730
- # allow = Discordrb::Permissions.new
1731
- # allow.can_mention_everyone = true
1732
- # allow.can_send_tts_messages = true
1733
- #
1734
- # deny = Discordrb::Permissions.new
1735
- # deny.can_create_instant_invite = true
1736
- #
1737
- # channel.define_overwrite(user, allow, deny)
1738
- def define_overwrite(thing, allow = 0, deny = 0, reason: nil)
1739
- unless thing.is_a? Overwrite
1740
- allow_bits = allow.respond_to?(:bits) ? allow.bits : allow
1741
- deny_bits = deny.respond_to?(:bits) ? deny.bits : deny
1742
-
1743
- thing = Overwrite.new thing, allow: allow_bits, deny: deny_bits
1744
- end
1745
-
1746
- API::Channel.update_permission(@bot.token, @id, thing.id, thing.allow.bits, thing.deny.bits, thing.type, reason)
1747
- end
1748
-
1749
- # Deletes a permission overwrite for this channel
1750
- # @param target [Member, User, Role, Profile, Recipient, #resolve_id] What permission overwrite to delete
1751
- # @param reason [String] The reason the for the overwrite deletion.
1752
- def delete_overwrite(target, reason = nil)
1753
- raise 'Tried deleting a overwrite for an invalid target' unless target.is_a?(Member) || target.is_a?(User) || target.is_a?(Role) || target.is_a?(Profile) || target.is_a?(Recipient) || target.respond_to?(:resolve_id)
1754
-
1755
- API::Channel.delete_permission(@bot.token, @id, target.resolve_id, reason)
1756
- end
1757
-
1758
- # Updates the cached data from another channel.
1759
- # @note For internal use only
1760
- # @!visibility private
1761
- def update_from(other)
1762
- @topic = other.topic
1763
- @name = other.name
1764
- @position = other.position
1765
- @topic = other.topic
1766
- @recipients = other.recipients
1767
- @bitrate = other.bitrate
1768
- @user_limit = other.user_limit
1769
- @permission_overwrites = other.permission_overwrites
1770
- @nsfw = other.nsfw
1771
- @parent_id = other.parent_id
1772
- @rate_limit_per_user = other.rate_limit_per_user
1773
- end
1774
-
1775
- # The list of users currently in this channel. For a voice channel, it will return all the members currently
1776
- # in that channel. For a text channel, it will return all online members that have permission to read it.
1777
- # @return [Array<Member>] the users in this channel
1778
- def users
1779
- if text?
1780
- @server.online_members(include_idle: true).select { |u| u.can_read_messages? self }
1781
- elsif voice?
1782
- @server.voice_states.map { |id, voice_state| @server.member(id) if !voice_state.voice_channel.nil? && voice_state.voice_channel.id == @id }.compact
1783
- end
1784
- end
1785
-
1786
- # Retrieves some of this channel's message history.
1787
- # @param amount [Integer] How many messages to retrieve. This must be less than or equal to 100, if it is higher
1788
- # than 100 it will be treated as 100 on Discord's side.
1789
- # @param before_id [Integer] The ID of the most recent message the retrieval should start at, or nil if it should
1790
- # start at the current message.
1791
- # @param after_id [Integer] The ID of the oldest message the retrieval should start at, or nil if it should start
1792
- # as soon as possible with the specified amount.
1793
- # @param around_id [Integer] The ID of the message retrieval should start from, reading in both directions
1794
- # @example Count the number of messages in the last 50 messages that contain the letter 'e'.
1795
- # message_count = channel.history(50).count {|message| message.content.include? "e"}
1796
- # @example Get the last 10 messages before the provided message.
1797
- # last_ten_messages = channel.history(10, message.id)
1798
- # @return [Array<Message>] the retrieved messages.
1799
- def history(amount, before_id = nil, after_id = nil, around_id = nil)
1800
- logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
1801
- JSON.parse(logs).map { |message| Message.new(message, @bot) }
1802
- end
1803
-
1804
- # Retrieves message history, but only message IDs for use with prune.
1805
- # @note For internal use only
1806
- # @!visibility private
1807
- def history_ids(amount, before_id = nil, after_id = nil, around_id = nil)
1808
- logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
1809
- JSON.parse(logs).map { |message| message['id'].to_i }
1810
- end
1811
-
1812
- # Returns a single message from this channel's history by ID.
1813
- # @param message_id [Integer] The ID of the message to retrieve.
1814
- # @return [Message, nil] the retrieved message, or `nil` if it couldn't be found.
1815
- def load_message(message_id)
1816
- response = API::Channel.message(@bot.token, @id, message_id)
1817
- return Message.new(JSON.parse(response), @bot)
1818
- rescue RestClient::ResourceNotFound
1819
- return nil
1820
- end
1821
-
1822
- alias_method :message, :load_message
1823
-
1824
- # Requests all pinned messages in a channel.
1825
- # @return [Array<Message>] the received messages.
1826
- def pins
1827
- msgs = API::Channel.pinned_messages(@bot.token, @id)
1828
- JSON.parse(msgs).map { |msg| Message.new(msg, @bot) }
1829
- end
1830
-
1831
- # Delete the last N messages on this channel.
1832
- # @param amount [Integer] The amount of message history to consider for pruning. Must be a value between 2 and 100 (Discord limitation)
1833
- # @param strict [true, false] Whether an error should be raised when a message is reached that is too old to be bulk
1834
- # deleted. If this is false only a warning message will be output to the console.
1835
- # @raise [ArgumentError] if the amount of messages is not a value between 2 and 100
1836
- # @yield [message] Yields each message in this channels history for filtering the messages to delete
1837
- # @example Pruning messages from a specific user ID
1838
- # channel.prune(100) { |m| m.author.id == 83283213010599936 }
1839
- # @return [Integer] The amount of messages that were successfully deleted
1840
- def prune(amount, strict = false, &block)
1841
- raise ArgumentError, 'Can only delete between 1 and 100 messages!' unless amount.between?(1, 100)
1842
-
1843
- messages =
1844
- if block_given?
1845
- history(amount).select(&block).map(&:id)
1846
- else
1847
- history_ids(amount)
1848
- end
1849
-
1850
- case messages.size
1851
- when 0
1852
- 0
1853
- when 1
1854
- API::Channel.delete_message(@bot.token, @id, messages.first)
1855
- 1
1856
- else
1857
- bulk_delete(messages, strict)
1858
- end
1859
- end
1860
-
1861
- # Deletes a collection of messages
1862
- # @param messages [Array<Message, Integer, #resolve_id>] the messages (or message IDs) to delete. Total must be an amount between 2 and 100 (Discord limitation)
1863
- # @param strict [true, false] Whether an error should be raised when a message is reached that is too old to be bulk
1864
- # deleted. If this is false only a warning message will be output to the console.
1865
- # @raise [ArgumentError] if the amount of messages is not a value between 2 and 100
1866
- # @return [Integer] The amount of messages that were successfully deleted
1867
- def delete_messages(messages, strict = false)
1868
- raise ArgumentError, 'Can only delete between 2 and 100 messages!' unless messages.count.between?(2, 100)
1869
-
1870
- messages.map!(&:resolve_id)
1871
- bulk_delete(messages, strict)
1872
- end
1873
-
1874
- # Updates the cached permission overwrites
1875
- # @note For internal use only
1876
- # @!visibility private
1877
- def update_overwrites(overwrites)
1878
- @permission_overwrites = overwrites
1879
- end
1880
-
1881
- # Add an {Await} for a message in this channel. This is identical in functionality to adding a
1882
- # {Discordrb::Events::MessageEvent} await with the `in` attribute as this channel.
1883
- # @see Bot#add_await
1884
- # @deprecated Will be changed to blocking behavior in v4.0. Use {#await!} instead.
1885
- def await(key, attributes = {}, &block)
1886
- @bot.add_await(key, Discordrb::Events::MessageEvent, { in: @id }.merge(attributes), &block)
1887
- end
1888
-
1889
- # Add a blocking {Await} for a message in this channel. This is identical in functionality to adding a
1890
- # {Discordrb::Events::MessageEvent} await with the `in` attribute as this channel.
1891
- # @see Bot#add_await!
1892
- def await!(attributes = {})
1893
- @bot.add_await!(Discordrb::Events::MessageEvent, { in: @id }.merge(attributes))
1894
- end
1895
-
1896
- # Creates a new invite to this channel.
1897
- # @param max_age [Integer] How many seconds this invite should last.
1898
- # @param max_uses [Integer] How many times this invite should be able to be used.
1899
- # @param temporary [true, false] Whether membership should be temporary (kicked after going offline).
1900
- # @param unique [true, false] If true, Discord will always send a unique invite instead of possibly re-using a similar one
1901
- # @param reason [String] The reason the for the creation of this invite.
1902
- # @return [Invite] the created invite.
1903
- def make_invite(max_age = 0, max_uses = 0, temporary = false, unique = false, reason = nil)
1904
- response = API::Channel.create_invite(@bot.token, @id, max_age, max_uses, temporary, unique, reason)
1905
- Invite.new(JSON.parse(response), @bot)
1906
- end
1907
-
1908
- alias_method :invite, :make_invite
1909
-
1910
- # Starts typing, which displays the typing indicator on the client for five seconds.
1911
- # If you want to keep typing you'll have to resend this every five seconds. (An abstraction
1912
- # for this will eventually be coming)
1913
- # @example Send a typing indicator for the bot in a given channel.
1914
- # channel.start_typing()
1915
- def start_typing
1916
- API::Channel.start_typing(@bot.token, @id)
1917
- end
1918
-
1919
- # Creates a Group channel
1920
- # @param user_ids [Array<Integer>] Array of user IDs to add to the new group channel (Excluding
1921
- # the recipient of the PM channel).
1922
- # @return [Channel] the created channel.
1923
- def create_group(user_ids)
1924
- raise 'Attempted to create group channel on a non-pm channel!' unless pm?
1925
- response = API::Channel.create_group(@bot.token, @id, user_ids.shift)
1926
- channel = Channel.new(JSON.parse(response), @bot)
1927
- channel.add_group_users(user_ids)
1928
- end
1929
-
1930
- # Adds a user to a group channel.
1931
- # @param user_ids [Array<#resolve_id>, #resolve_id] User ID or array of user IDs to add to the group channel.
1932
- # @return [Channel] the group channel.
1933
- def add_group_users(user_ids)
1934
- raise 'Attempted to add a user to a non-group channel!' unless group?
1935
- user_ids = [user_ids] unless user_ids.is_a? Array
1936
- user_ids.each do |user_id|
1937
- API::Channel.add_group_user(@bot.token, @id, user_id.resolve_id)
1938
- end
1939
- self
1940
- end
1941
-
1942
- alias_method :add_group_user, :add_group_users
1943
-
1944
- # Removes a user from a group channel.
1945
- # @param user_ids [Array<#resolve_id>, #resolve_id] User ID or array of user IDs to remove from the group channel.
1946
- # @return [Channel] the group channel.
1947
- def remove_group_users(user_ids)
1948
- raise 'Attempted to remove a user from a non-group channel!' unless group?
1949
- user_ids = [user_ids] unless user_ids.is_a? Array
1950
- user_ids.each do |user_id|
1951
- API::Channel.remove_group_user(@bot.token, @id, user_id.resolve_id)
1952
- end
1953
- self
1954
- end
1955
-
1956
- alias_method :remove_group_user, :remove_group_users
1957
-
1958
- # Leaves the group.
1959
- def leave_group
1960
- raise 'Attempted to leave a non-group channel!' unless group?
1961
- API::Channel.leave_group(@bot.token, @id)
1962
- end
1963
-
1964
- alias_method :leave, :leave_group
1965
-
1966
- # Requests a list of Webhooks on the channel.
1967
- # @return [Array<Webhook>] webhooks on the channel.
1968
- def webhooks
1969
- raise 'Tried to request webhooks from a non-server channel' unless server
1970
- webhooks = JSON.parse(API::Channel.webhooks(@bot.token, @id))
1971
- webhooks.map { |webhook_data| Webhook.new(webhook_data, @bot) }
1972
- end
1973
-
1974
- # Requests a list of Invites to the channel.
1975
- # @return [Array<Invite>] invites to the channel.
1976
- def invites
1977
- raise 'Tried to request invites from a non-server channel' unless server
1978
- invites = JSON.parse(API::Channel.invites(@bot.token, @id))
1979
- invites.map { |invite_data| Invite.new(invite_data, @bot) }
1980
- end
1981
-
1982
- # The default `inspect` method is overwritten to give more useful output.
1983
- def inspect
1984
- "<Channel name=#{@name} id=#{@id} topic=\"#{@topic}\" type=#{@type} position=#{@position} server=#{@server}>"
1985
- end
1986
-
1987
- # Adds a recipient to a group channel.
1988
- # @param recipient [Recipient] the recipient to add to the group
1989
- # @raise [ArgumentError] if tried to add a non-recipient
1990
- # @note For internal use only
1991
- # @!visibility private
1992
- def add_recipient(recipient)
1993
- raise 'Tried to add recipient to a non-group channel' unless group?
1994
- raise ArgumentError, 'Tried to add a non-recipient to a group' unless recipient.is_a?(Recipient)
1995
- @recipients << recipient
1996
- end
1997
-
1998
- # Removes a recipient from a group channel.
1999
- # @param recipient [Recipient] the recipient to remove from the group
2000
- # @raise [ArgumentError] if tried to remove a non-recipient
2001
- # @note For internal use only
2002
- # @!visibility private
2003
- def remove_recipient(recipient)
2004
- raise 'Tried to remove recipient from a non-group channel' unless group?
2005
- raise ArgumentError, 'Tried to remove a non-recipient from a group' unless recipient.is_a?(Recipient)
2006
- @recipients.delete(recipient)
2007
- end
2008
-
2009
- # Updates the cached data with new data
2010
- # @note For internal use only
2011
- # @!visibility private
2012
- def update_data(new_data = nil)
2013
- new_data ||= JSON.parse(API::Channel.resolve(@bot.token, @id))
2014
- @name = new_data[:name] || new_data['name'] || @name
2015
- @topic = new_data[:topic] || new_data['topic'] || @topic
2016
- @position = new_data[:position] || new_data['position'] || @position
2017
- @bitrate = new_data[:bitrate] || new_data['bitrate'] || @bitrate
2018
- @user_limit = new_data[:user_limit] || new_data['user_limit'] || @user_limit
2019
- new_nsfw = new_data.key?(:nsfw) ? new_data[:nsfw] : new_data['nsfw']
2020
- @nsfw = new_nsfw.nil? ? @nsfw : new_nsfw
2021
- @parent_id = new_data[:parent_id] || new_data['parent_id'] || @parent_id
2022
- process_permission_overwrites(new_data[:permission_overwrites] || new_data['permission_overwrites'])
2023
- @rate_limit_per_user = new_data[:rate_limit_per_user] || new_data['rate_limit_per_user'] || @rate_limit_per_user
2024
- end
2025
-
2026
- private
2027
-
2028
- # For bulk_delete checking
2029
- TWO_WEEKS = 86_400 * 14
2030
-
2031
- # Deletes a list of messages on this channel using bulk delete.
2032
- def bulk_delete(ids, strict = false)
2033
- min_snowflake = IDObject.synthesise(Time.now - TWO_WEEKS)
2034
-
2035
- ids.reject! do |e|
2036
- next unless e < min_snowflake
2037
-
2038
- message = "Attempted to bulk_delete message #{e} which is too old (min = #{min_snowflake})"
2039
- raise ArgumentError, message if strict
2040
- Discordrb::LOGGER.warn(message)
2041
- true
2042
- end
2043
-
2044
- API::Channel.bulk_delete_messages(@bot.token, @id, ids)
2045
- ids.size
2046
- end
2047
-
2048
- def update_channel_data(new_data)
2049
- new_nsfw = new_data[:nsfw].is_a?(TrueClass) || new_data[:nsfw].is_a?(FalseClass) ? new_nsfw : @nsfw
2050
- # send permission_overwrite only when explicitly set
2051
- overwrites = new_data[:permission_overwrites] ? new_data[:permission_overwrites].map { |_, v| v.to_hash } : nil
2052
- response = JSON.parse(API::Channel.update(@bot.token, @id,
2053
- new_data[:name] || @name,
2054
- new_data[:topic] || @topic,
2055
- new_data[:position] || @position,
2056
- new_data[:bitrate] || @bitrate,
2057
- new_data[:user_limit] || @user_limit,
2058
- new_nsfw,
2059
- overwrites,
2060
- new_data[:parent_id] || @parent_id,
2061
- new_data[:rate_limit_per_user] || @rate_limit_per_user))
2062
- update_data(response)
2063
- end
2064
-
2065
- def process_permission_overwrites(overwrites)
2066
- # Populate permission overwrites
2067
- @permission_overwrites = {}
2068
- return unless overwrites
2069
- overwrites.each do |element|
2070
- id = element['id'].to_i
2071
- @permission_overwrites[id] = Overwrite.from_hash(element)
2072
- end
2073
- end
2074
- end
2075
-
2076
- # An Embed object that is contained in a message
2077
- # A freshly generated embed object will not appear in a message object
2078
- # unless grabbed from its ID in a channel.
2079
- class Embed
2080
- # @return [Message] the message this embed object is contained in.
2081
- attr_reader :message
2082
-
2083
- # @return [String] the URL this embed object is based on.
2084
- attr_reader :url
2085
-
2086
- # @return [String, nil] the title of the embed object. `nil` if there is not a title
2087
- attr_reader :title
2088
-
2089
- # @return [String, nil] the description of the embed object. `nil` if there is not a description
2090
- attr_reader :description
2091
-
2092
- # @return [Symbol] the type of the embed object. Possible types are:
2093
- #
2094
- # * `:link`
2095
- # * `:video`
2096
- # * `:image`
2097
- attr_reader :type
2098
-
2099
- # @return [Time, nil] the timestamp of the embed object. `nil` if there is not a timestamp
2100
- attr_reader :timestamp
2101
-
2102
- # @return [String, nil] the color of the embed object. `nil` if there is not a color
2103
- attr_reader :color
2104
- alias_method :colour, :color
2105
-
2106
- # @return [EmbedFooter, nil] the footer of the embed object. `nil` if there is not a footer
2107
- attr_reader :footer
2108
-
2109
- # @return [EmbedProvider, nil] the provider of the embed object. `nil` if there is not a provider
2110
- attr_reader :provider
2111
-
2112
- # @return [EmbedImage, nil] the image of the embed object. `nil` if there is not an image
2113
- attr_reader :image
2114
-
2115
- # @return [EmbedThumbnail, nil] the thumbnail of the embed object. `nil` if there is not a thumbnail
2116
- attr_reader :thumbnail
2117
-
2118
- # @return [EmbedVideo, nil] the video of the embed object. `nil` if there is not a video
2119
- attr_reader :video
2120
-
2121
- # @return [EmbedAuthor, nil] the author of the embed object. `nil` if there is not an author
2122
- attr_reader :author
2123
-
2124
- # @return [Array<EmbedField>, nil] the fields of the embed object. `nil` if there are no fields
2125
- attr_reader :fields
2126
-
2127
- # @!visibility private
2128
- def initialize(data, message)
2129
- @message = message
2130
-
2131
- @url = data['url']
2132
- @title = data['title']
2133
- @type = data['type'].to_sym
2134
- @description = data['description']
2135
- @timestamp = data['timestamp'].nil? ? nil : Time.parse(data['timestamp'])
2136
- @color = data['color']
2137
- @footer = data['footer'].nil? ? nil : EmbedFooter.new(data['footer'], self)
2138
- @image = data['image'].nil? ? nil : EmbedImage.new(data['image'], self)
2139
- @video = data['video'].nil? ? nil : EmbedVideo.new(data['video'], self)
2140
- @provider = data['provider'].nil? ? nil : EmbedProvider.new(data['provider'], self)
2141
- @thumbnail = data['thumbnail'].nil? ? nil : EmbedThumbnail.new(data['thumbnail'], self)
2142
- @author = data['author'].nil? ? nil : EmbedAuthor.new(data['author'], self)
2143
- @fields = data['fields'].nil? ? nil : data['fields'].map { |field| EmbedField.new(field, self) }
2144
- end
2145
- end
2146
-
2147
- # An Embed footer for the embed object.
2148
- class EmbedFooter
2149
- # @return [Embed] the embed object this is based on.
2150
- attr_reader :embed
2151
-
2152
- # @return [String] the footer text.
2153
- attr_reader :text
2154
-
2155
- # @return [String] the URL of the footer icon.
2156
- attr_reader :icon_url
2157
-
2158
- # @return [String] the proxied URL of the footer icon.
2159
- attr_reader :proxy_icon_url
2160
-
2161
- # @!visibility private
2162
- def initialize(data, embed)
2163
- @embed = embed
2164
-
2165
- @text = data['text']
2166
- @icon_url = data['icon_url']
2167
- @proxy_icon_url = data['proxy_icon_url']
2168
- end
2169
- end
2170
-
2171
- # An Embed image for the embed object.
2172
- class EmbedImage
2173
- # @return [Embed] the embed object this is based on.
2174
- attr_reader :embed
2175
-
2176
- # @return [String] the source URL of the image.
2177
- attr_reader :url
2178
-
2179
- # @return [String] the proxy URL of the image.
2180
- attr_reader :proxy_url
2181
-
2182
- # @return [Integer] the width of the image, in pixels.
2183
- attr_reader :width
2184
-
2185
- # @return [Integer] the height of the image, in pixels.
2186
- attr_reader :height
2187
-
2188
- # @!visibility private
2189
- def initialize(data, embed)
2190
- @embed = embed
2191
-
2192
- @url = data['url']
2193
- @proxy_url = data['proxy_url']
2194
- @width = data['width']
2195
- @height = data['height']
2196
- end
2197
- end
2198
-
2199
- # An Embed video for the embed object
2200
- class EmbedVideo
2201
- # @return [Embed] the embed object this is based on.
2202
- attr_reader :embed
2203
-
2204
- # @return [String] the source URL of the video.
2205
- attr_reader :url
2206
-
2207
- # @return [Integer] the width of the video, in pixels.
2208
- attr_reader :width
2209
-
2210
- # @return [Integer] the height of the video, in pixels.
2211
- attr_reader :height
2212
-
2213
- # @!visibility private
2214
- def initialize(data, embed)
2215
- @embed = embed
2216
-
2217
- @url = data['url']
2218
- @width = data['width']
2219
- @height = data['height']
2220
- end
2221
- end
2222
-
2223
- # An Embed thumbnail for the embed object
2224
- class EmbedThumbnail
2225
- # @return [Embed] the embed object this is based on.
2226
- attr_reader :embed
2227
-
2228
- # @return [String] the CDN URL this thumbnail can be downloaded at.
2229
- attr_reader :url
2230
-
2231
- # @return [String] the thumbnail's proxy URL - I'm not sure what exactly this does, but I think it has something to
2232
- # do with CDNs.
2233
- attr_reader :proxy_url
2234
-
2235
- # @return [Integer] the width of this thumbnail file, in pixels.
2236
- attr_reader :width
2237
-
2238
- # @return [Integer] the height of this thumbnail file, in pixels.
2239
- attr_reader :height
2240
-
2241
- # @!visibility private
2242
- def initialize(data, embed)
2243
- @embed = embed
2244
-
2245
- @url = data['url']
2246
- @proxy_url = data['proxy_url']
2247
- @width = data['width']
2248
- @height = data['height']
2249
- end
2250
- end
2251
-
2252
- # An Embed provider for the embed object
2253
- class EmbedProvider
2254
- # @return [Embed] the embed object this is based on.
2255
- attr_reader :embed
2256
-
2257
- # @return [String] the provider's name.
2258
- attr_reader :name
2259
-
2260
- # @return [String, nil] the URL of the provider, or `nil` if there is no URL.
2261
- attr_reader :url
2262
-
2263
- # @!visibility private
2264
- def initialize(data, embed)
2265
- @embed = embed
2266
-
2267
- @name = data['name']
2268
- @url = data['url']
2269
- end
2270
- end
2271
-
2272
- # An Embed author for the embed object
2273
- class EmbedAuthor
2274
- # @return [Embed] the embed object this is based on.
2275
- attr_reader :embed
2276
-
2277
- # @return [String] the author's name.
2278
- attr_reader :name
2279
-
2280
- # @return [String, nil] the URL of the author's website, or `nil` if there is no URL.
2281
- attr_reader :url
2282
-
2283
- # @return [String, nil] the icon of the author, or `nil` if there is no icon.
2284
- attr_reader :icon_url
2285
-
2286
- # @return [String, nil] the Discord proxy URL, or `nil` if there is no `icon_url`.
2287
- attr_reader :proxy_icon_url
2288
-
2289
- # @!visibility private
2290
- def initialize(data, embed)
2291
- @embed = embed
2292
-
2293
- @name = data['name']
2294
- @url = data['url']
2295
- @icon_url = data['icon_url']
2296
- @proxy_icon_url = data['proxy_icon_url']
2297
- end
2298
- end
2299
-
2300
- # An Embed field for the embed object
2301
- class EmbedField
2302
- # @return [Embed] the embed object this is based on.
2303
- attr_reader :embed
2304
-
2305
- # @return [String] the field's name.
2306
- attr_reader :name
2307
-
2308
- # @return [String] the field's value.
2309
- attr_reader :value
2310
-
2311
- # @return [true, false] whether this field is inline.
2312
- attr_reader :inline
2313
-
2314
- # @!visibility private
2315
- def initialize(data, embed)
2316
- @embed = embed
2317
-
2318
- @name = data['name']
2319
- @value = data['value']
2320
- @inline = data['inline']
2321
- end
2322
- end
2323
-
2324
- # An attachment to a message
2325
- class Attachment
2326
- include IDObject
2327
-
2328
- # @return [Message] the message this attachment belongs to.
2329
- attr_reader :message
2330
-
2331
- # @return [String] the CDN URL this attachment can be downloaded at.
2332
- attr_reader :url
2333
-
2334
- # @return [String] the attachment's proxy URL - I'm not sure what exactly this does, but I think it has something to
2335
- # do with CDNs.
2336
- attr_reader :proxy_url
2337
-
2338
- # @return [String] the attachment's filename.
2339
- attr_reader :filename
2340
-
2341
- # @return [Integer] the attachment's file size in bytes.
2342
- attr_reader :size
2343
-
2344
- # @return [Integer, nil] the width of an image file, in pixels, or `nil` if the file is not an image.
2345
- attr_reader :width
2346
-
2347
- # @return [Integer, nil] the height of an image file, in pixels, or `nil` if the file is not an image.
2348
- attr_reader :height
2349
-
2350
- # @!visibility private
2351
- def initialize(data, message, bot)
2352
- @bot = bot
2353
- @message = message
2354
-
2355
- @id = data['id'].to_i
2356
- @url = data['url']
2357
- @proxy_url = data['proxy_url']
2358
- @filename = data['filename']
2359
-
2360
- @size = data['size']
2361
-
2362
- @width = data['width']
2363
- @height = data['height']
2364
- end
2365
-
2366
- # @return [true, false] whether this file is an image file.
2367
- def image?
2368
- !(@width.nil? || @height.nil?)
2369
- end
2370
- end
2371
-
2372
- # A message on Discord that was sent to a text channel
2373
- class Message
2374
- include IDObject
2375
-
2376
- # @return [String] the content of this message.
2377
- attr_reader :content
2378
- alias_method :text, :content
2379
- alias_method :to_s, :content
2380
-
2381
- # @return [Member, User] the user that sent this message. (Will be a {Member} most of the time, it should only be a
2382
- # {User} for old messages when the author has left the server since then)
2383
- attr_reader :author
2384
- alias_method :user, :author
2385
- alias_method :writer, :author
2386
-
2387
- # @return [Channel] the channel in which this message was sent.
2388
- attr_reader :channel
2389
-
2390
- # @return [Time] the timestamp at which this message was sent.
2391
- attr_reader :timestamp
2392
-
2393
- # @return [Time] the timestamp at which this message was edited. `nil` if the message was never edited.
2394
- attr_reader :edited_timestamp
2395
- alias_method :edit_timestamp, :edited_timestamp
2396
-
2397
- # @return [Array<User>] the users that were mentioned in this message.
2398
- attr_reader :mentions
2399
-
2400
- # @return [Array<Role>] the roles that were mentioned in this message.
2401
- attr_reader :role_mentions
2402
-
2403
- # @return [Array<Attachment>] the files attached to this message.
2404
- attr_reader :attachments
2405
-
2406
- # @return [Array<Embed>] the embed objects contained in this message.
2407
- attr_reader :embeds
2408
-
2409
- # @return [Hash<String => Reaction>] the reaction objects attached to this message keyed by the name of the reaction
2410
- attr_reader :reactions
2411
-
2412
- # @return [true, false] whether the message used Text-To-Speech (TTS) or not.
2413
- attr_reader :tts
2414
- alias_method :tts?, :tts
2415
-
2416
- # @return [String] used for validating a message was sent.
2417
- attr_reader :nonce
2418
-
2419
- # @return [true, false] whether the message was edited or not.
2420
- attr_reader :edited
2421
- alias_method :edited?, :edited
2422
-
2423
- # @return [true, false] whether the message mentioned everyone or not.
2424
- attr_reader :mention_everyone
2425
- alias_method :mention_everyone?, :mention_everyone
2426
- alias_method :mentions_everyone?, :mention_everyone
2427
-
2428
- # @return [true, false] whether the message is pinned or not.
2429
- attr_reader :pinned
2430
- alias_method :pinned?, :pinned
2431
-
2432
- # @return [Integer, nil] the webhook ID that sent this message, or `nil` if it wasn't sent through a webhook.
2433
- attr_reader :webhook_id
2434
-
2435
- # The discriminator that webhook user accounts have.
2436
- ZERO_DISCRIM = '0000'.freeze
2437
-
2438
- # @!visibility private
2439
- def initialize(data, bot)
2440
- @bot = bot
2441
- @content = data['content']
2442
- @channel = bot.channel(data['channel_id'].to_i)
2443
- @pinned = data['pinned']
2444
- @tts = data['tts']
2445
- @nonce = data['nonce']
2446
- @mention_everyone = data['mention_everyone']
2447
-
2448
- @author = if data['author']
2449
- if data['author']['discriminator'] == ZERO_DISCRIM
2450
- # This is a webhook user! It would be pointless to try to resolve a member here, so we just create
2451
- # a User and return that instead.
2452
- Discordrb::LOGGER.debug("Webhook user: #{data['author']['id']}")
2453
- User.new(data['author'], @bot)
2454
- elsif @channel.private?
2455
- # Turn the message user into a recipient - we can't use the channel recipient
2456
- # directly because the bot may also send messages to the channel
2457
- Recipient.new(bot.user(data['author']['id'].to_i), @channel, bot)
2458
- else
2459
- member = @channel.server.member(data['author']['id'].to_i)
2460
-
2461
- unless member
2462
- Discordrb::LOGGER.debug("Member with ID #{data['author']['id']} not cached (possibly left the server).")
2463
- member = @bot.ensure_user(data['author'])
2464
- end
2465
-
2466
- member
2467
- end
2468
- end
2469
-
2470
- @webhook_id = data['webhook_id'].to_i if data['webhook_id']
2471
-
2472
- @timestamp = Time.parse(data['timestamp']) if data['timestamp']
2473
- @edited_timestamp = data['edited_timestamp'].nil? ? nil : Time.parse(data['edited_timestamp'])
2474
- @edited = !@edited_timestamp.nil?
2475
- @id = data['id'].to_i
2476
-
2477
- @emoji = []
2478
-
2479
- @reactions = {}
2480
-
2481
- if data['reactions']
2482
- data['reactions'].each do |element|
2483
- @reactions[element['emoji']['name']] = Reaction.new(element)
2484
- end
2485
- end
2486
-
2487
- @mentions = []
2488
-
2489
- if data['mentions']
2490
- data['mentions'].each do |element|
2491
- @mentions << bot.ensure_user(element)
2492
- end
2493
- end
2494
-
2495
- @role_mentions = []
2496
-
2497
- # Role mentions can only happen on public servers so make sure we only parse them there
2498
- if @channel.text?
2499
- if data['mention_roles']
2500
- data['mention_roles'].each do |element|
2501
- @role_mentions << @channel.server.role(element.to_i)
2502
- end
2503
- end
2504
- end
2505
-
2506
- @attachments = []
2507
- @attachments = data['attachments'].map { |e| Attachment.new(e, self, @bot) } if data['attachments']
2508
-
2509
- @embeds = []
2510
- @embeds = data['embeds'].map { |e| Embed.new(e, self) } if data['embeds']
2511
- end
2512
-
2513
- # Replies to this message with the specified content.
2514
- # @see Channel#send_message
2515
- def reply(content)
2516
- @channel.send_message(content)
2517
- end
2518
-
2519
- # Edits this message to have the specified content instead.
2520
- # You can only edit your own messages.
2521
- # @param new_content [String] the new content the message should have.
2522
- # @param new_embed [Hash, Discordrb::Webhooks::Embed, nil] The new embed the message should have. If `nil` the message will be changed to have no embed.
2523
- # @return [Message] the resulting message.
2524
- def edit(new_content, new_embed = nil)
2525
- response = API::Channel.edit_message(@bot.token, @channel.id, @id, new_content, [], new_embed ? new_embed.to_hash : nil)
2526
- Message.new(JSON.parse(response), @bot)
2527
- end
2528
-
2529
- # Deletes this message.
2530
- def delete
2531
- API::Channel.delete_message(@bot.token, @channel.id, @id)
2532
- nil
2533
- end
2534
-
2535
- # Pins this message
2536
- def pin
2537
- API::Channel.pin_message(@bot.token, @channel.id, @id)
2538
- @pinned = true
2539
- nil
2540
- end
2541
-
2542
- # Unpins this message
2543
- def unpin
2544
- API::Channel.unpin_message(@bot.token, @channel.id, @id)
2545
- @pinned = false
2546
- nil
2547
- end
2548
-
2549
- # Add an {Await} for a message with the same user and channel.
2550
- # @see Bot#add_await
2551
- # @deprecated Will be changed to blocking behavior in v4.0. Use {#await!} instead.
2552
- def await(key, attributes = {}, &block)
2553
- @bot.add_await(key, Discordrb::Events::MessageEvent, { from: @author.id, in: @channel.id }.merge(attributes), &block)
2554
- end
2555
-
2556
- # Add a blocking {Await} for a message with the same user and channel.
2557
- # @see Bot#add_await!
2558
- def await!(attributes = {})
2559
- @bot.add_await!(Discordrb::Events::MessageEvent, { from: @author.id, in: @channel.id }.merge(attributes))
2560
- end
2561
-
2562
- # @return [true, false] whether this message was sent by the current {Bot}.
2563
- def from_bot?
2564
- @author && @author.current_bot?
2565
- end
2566
-
2567
- # @return [true, false] whether this message has been sent over a webhook.
2568
- def webhook?
2569
- !@webhook_id.nil?
2570
- end
2571
-
2572
- # @!visibility private
2573
- # @return [Array<String>] the emoji mentions found in the message
2574
- def scan_for_emoji
2575
- emoji = @content.split
2576
- emoji = emoji.grep(/<(?<animated>a)?:(?<name>\w+):(?<id>\d+)>?/)
2577
- emoji
2578
- end
2579
-
2580
- # @return [Array<Emoji>] the emotes that were used/mentioned in this message.
2581
- def emoji
2582
- return if @content.nil?
2583
-
2584
- emoji = scan_for_emoji
2585
- emoji.each do |element|
2586
- @emoji << @bot.parse_mention(element)
2587
- end
2588
- @emoji
2589
- end
2590
-
2591
- # Check if any emoji were used in this message.
2592
- # @return [true, false] whether or not any emoji were used
2593
- def emoji?
2594
- emoji = scan_for_emoji
2595
- return true unless emoji.empty?
2596
- end
2597
-
2598
- # Check if any reactions were used in this message.
2599
- # @return [true, false] whether or not this message has reactions
2600
- def reactions?
2601
- @reactions.any?
2602
- end
2603
-
2604
- # Returns the reactions made by the current bot or user.
2605
- # @return [Array<Reaction>] the reactions
2606
- def my_reactions
2607
- @reactions.values.select(&:me)
2608
- end
2609
-
2610
- # Reacts to a message.
2611
- # @param reaction [String, #to_reaction] the unicode emoji or {Emoji}
2612
- def create_reaction(reaction)
2613
- reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
2614
- API::Channel.create_reaction(@bot.token, @channel.id, @id, reaction)
2615
- nil
2616
- end
2617
-
2618
- alias_method :react, :create_reaction
2619
-
2620
- # Returns the list of users who reacted with a certain reaction.
2621
- # @param reaction [String, #to_reaction] the unicode emoji or {Emoji}
2622
- # @example Get all the users that reacted with a thumbsup.
2623
- # thumbs_up_reactions = message.reacted_with("\u{1F44D}")
2624
- # @return [Array<User>] the users who used this reaction
2625
- def reacted_with(reaction)
2626
- reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
2627
- response = JSON.parse(API::Channel.get_reactions(@bot.token, @channel.id, @id, reaction))
2628
- response.map { |d| User.new(d, @bot) }
2629
- end
2630
-
2631
- # Deletes a reaction made by a user on this message.
2632
- # @param user [User, #resolve_id] the user who used this reaction
2633
- # @param reaction [String, #to_reaction] the reaction to remove
2634
- def delete_reaction(user, reaction)
2635
- reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
2636
- API::Channel.delete_user_reaction(@bot.token, @channel.id, @id, reaction, user.resolve_id)
2637
- end
2638
-
2639
- # Deletes this client's reaction on this message.
2640
- # @param reaction [String, #to_reaction] the reaction to remove
2641
- def delete_own_reaction(reaction)
2642
- reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
2643
- API::Channel.delete_own_reaction(@bot.token, @channel.id, @id, reaction)
2644
- end
2645
-
2646
- # Removes all reactions from this message.
2647
- def delete_all_reactions
2648
- API::Channel.delete_all_reactions(@bot.token, @channel.id, @id)
2649
- end
2650
-
2651
- # The inspect method is overwritten to give more useful output
2652
- def inspect
2653
- "<Message content=\"#{@content}\" id=#{@id} timestamp=#{@timestamp} author=#{@author} channel=#{@channel}>"
2654
- end
2655
- end
2656
-
2657
- # A reaction to a message.
2658
- class Reaction
2659
- # @return [Integer] the amount of users who have reacted with this reaction
2660
- attr_reader :count
2661
-
2662
- # @return [true, false] whether the current bot or user used this reaction
2663
- attr_reader :me
2664
- alias_method :me?, :me
2665
-
2666
- # @return [Integer] the ID of the emoji, if it was custom
2667
- attr_reader :id
2668
-
2669
- # @return [String] the name or unicode representation of the emoji
2670
- attr_reader :name
2671
-
2672
- def initialize(data)
2673
- @count = data['count']
2674
- @me = data['me']
2675
- @id = data['emoji']['id'].nil? ? nil : data['emoji']['id'].to_i
2676
- @name = data['emoji']['name']
2677
- end
2678
-
2679
- # Converts this Reaction into a string that can be sent back to Discord in other reaction endpoints.
2680
- # If ID is present, it will be rendered into the form of `name:id`.
2681
- # @return [String] the name of this reaction, including the ID if it is a custom emoji
2682
- def to_s
2683
- id.nil? ? name : "#{name}:#{id}"
2684
- end
2685
- end
2686
-
2687
- # Server emoji
2688
- class Emoji
2689
- include IDObject
2690
-
2691
- # @return [String] the emoji name
2692
- attr_reader :name
2693
-
2694
- # @return [Server] the server of this emoji
2695
- attr_reader :server
2696
-
2697
- # @return [Array<Role>] roles this emoji is active for
2698
- attr_reader :roles
2699
-
2700
- # @return [true, false] if the emoji is animated
2701
- attr_reader :animated
2702
- alias_method :animated?, :animated
2703
-
2704
- def initialize(data, bot, server)
2705
- @bot = bot
2706
- @roles = nil
2707
-
2708
- @name = data['name']
2709
- @server = server
2710
- @id = data['id'].nil? ? nil : data['id'].to_i
2711
- @animated = data['animated']
2712
-
2713
- process_roles(data['roles']) if server
2714
- end
2715
-
2716
- # @return [String] the layout to mention it (or have it used) in a message
2717
- def mention
2718
- "<#{'a' if animated}:#{name}:#{id}>"
2719
- end
2720
-
2721
- alias_method :use, :mention
2722
- alias_method :to_s, :mention
2723
-
2724
- # @return [String] the layout to use this emoji in a reaction
2725
- def to_reaction
2726
- "#{name}:#{id}"
2727
- end
2728
-
2729
- # @return [String] the icon URL of the emoji
2730
- def icon_url
2731
- API.emoji_icon_url(id)
2732
- end
2733
-
2734
- # The inspect method is overwritten to give more useful output
2735
- def inspect
2736
- "<Emoji name=#{name} id=#{id} animated=#{animated}>"
2737
- end
2738
-
2739
- # @!visibility private
2740
- def process_roles(roles)
2741
- @roles = []
2742
- return unless roles
2743
- roles.each do |role_id|
2744
- role = server.role(role_id)
2745
- @roles << role
2746
- end
2747
- end
2748
- end
2749
-
2750
- # Basic attributes a server should have
2751
- module ServerAttributes
2752
- # @return [String] this server's name.
2753
- attr_reader :name
2754
-
2755
- # @return [String] the hexadecimal ID used to identify this server's icon.
2756
- attr_reader :icon_id
2757
-
2758
- # Utility function to get the URL for the icon image
2759
- # @return [String] the URL to the icon image
2760
- def icon_url
2761
- return nil unless @icon_id
2762
- API.icon_url(@id, @icon_id)
2763
- end
2764
- end
2765
-
2766
- # Integration Account
2767
- class IntegrationAccount
2768
- # @return [String] this account's name.
2769
- attr_reader :name
2770
-
2771
- # @return [Integer] this account's ID.
2772
- attr_reader :id
2773
-
2774
- def initialize(data)
2775
- @name = data['name']
2776
- @id = data['id'].to_i
2777
- end
2778
- end
2779
-
2780
- # Server integration
2781
- class Integration
2782
- include IDObject
2783
-
2784
- # @return [String] the integration name
2785
- attr_reader :name
2786
-
2787
- # @return [Server] the server the integration is linked to
2788
- attr_reader :server
2789
-
2790
- # @return [User] the user the integration is linked to
2791
- attr_reader :user
2792
-
2793
- # @return [Role, nil] the role that this integration uses for "subscribers"
2794
- attr_reader :role
2795
-
2796
- # @return [true, false] whether emoticons are enabled
2797
- attr_reader :emoticon
2798
- alias_method :emoticon?, :emoticon
2799
-
2800
- # @return [String] the integration type (YouTube, Twitch, etc.)
2801
- attr_reader :type
2802
-
2803
- # @return [true, false] whether the integration is enabled
2804
- attr_reader :enabled
2805
-
2806
- # @return [true, false] whether the integration is syncing
2807
- attr_reader :syncing
2808
-
2809
- # @return [IntegrationAccount] the integration account information
2810
- attr_reader :account
2811
-
2812
- # @return [Time] the time the integration was synced at
2813
- attr_reader :synced_at
2814
-
2815
- # @return [Symbol] the behaviour of expiring subscribers (:remove = Remove User from role; :kick = Kick User from server)
2816
- attr_reader :expire_behaviour
2817
- alias_method :expire_behavior, :expire_behaviour
2818
-
2819
- # @return [Integer] the grace period before subscribers expire (in days)
2820
- attr_reader :expire_grace_period
2821
-
2822
- def initialize(data, bot, server)
2823
- @bot = bot
2824
-
2825
- @name = data['name']
2826
- @server = server
2827
- @id = data['id'].to_i
2828
- @enabled = data['enabled']
2829
- @syncing = data['syncing']
2830
- @type = data['type']
2831
- @account = IntegrationAccount.new(data['account'])
2832
- @synced_at = Time.parse(data['synced_at'])
2833
- @expire_behaviour = %i[remove kick][data['expire_behavior']]
2834
- @expire_grace_period = data['expire_grace_period']
2835
- @user = @bot.ensure_user(data['user'])
2836
- @role = server.role(data['role_id']) || nil
2837
- @emoticon = data['enable_emoticons']
2838
- end
2839
-
2840
- # The inspect method is overwritten to give more useful output
2841
- def inspect
2842
- "<Integration name=#{@name} id=#{@id} type=#{@type} enabled=#{@enabled}>"
2843
- end
2844
- end
2845
-
2846
- # A server on Discord
2847
- class Server
2848
- include IDObject
2849
- include ServerAttributes
2850
-
2851
- # @return [String] the ID of the region the server is on (e.g. `amsterdam`).
2852
- attr_reader :region_id
2853
-
2854
- # @return [Member] The server owner.
2855
- attr_reader :owner
2856
-
2857
- # @return [Array<Channel>] an array of all the channels (text and voice) on this server.
2858
- attr_reader :channels
2859
-
2860
- # @return [Array<Role>] an array of all the roles created on this server.
2861
- attr_reader :roles
2862
-
2863
- # @return [Hash<Integer => Emoji>] a hash of all the emoji available on this server.
2864
- attr_reader :emoji
2865
- alias_method :emojis, :emoji
2866
-
2867
- # @return [true, false] whether or not this server is large (members > 100). If it is,
2868
- # it means the members list may be inaccurate for a couple seconds after starting up the bot.
2869
- attr_reader :large
2870
- alias_method :large?, :large
2871
-
2872
- # @return [Array<Symbol>] the features of the server (eg. "INVITE_SPLASH")
2873
- attr_reader :features
2874
-
2875
- # @return [Integer] the absolute number of members on this server, offline or not.
2876
- attr_reader :member_count
2877
-
2878
- # @return [Integer] the amount of time after which a voice user gets moved into the AFK channel, in seconds.
2879
- attr_reader :afk_timeout
2880
-
2881
- # @return [Hash<Integer => VoiceState>] the hash (user ID => voice state) of voice states of members on this server
2882
- attr_reader :voice_states
2883
-
2884
- # @!visibility private
2885
- def initialize(data, bot, exists = true)
2886
- @bot = bot
2887
- @owner_id = data['owner_id'].to_i
2888
- @id = data['id'].to_i
2889
-
2890
- process_channels(data['channels'])
2891
- update_data(data)
2892
-
2893
- @large = data['large']
2894
- @member_count = data['member_count']
2895
- @splash_id = nil
2896
- @features = data['features'].map { |element| element.downcase.to_sym }
2897
- @members = {}
2898
- @voice_states = {}
2899
- @emoji = {}
2900
-
2901
- process_roles(data['roles'])
2902
- process_emoji(data['emojis'])
2903
- process_members(data['members'])
2904
- process_presences(data['presences'])
2905
- process_voice_states(data['voice_states'])
2906
-
2907
- # Whether this server's members have been chunked (resolved using op 8 and GUILD_MEMBERS_CHUNK) yet
2908
- @chunked = false
2909
- @processed_chunk_members = 0
2910
-
2911
- # Only get the owner of the server actually exists (i.e. not for ServerDeleteEvent)
2912
- @owner = member(@owner_id) if exists
2913
- end
2914
-
2915
- # The default channel is the text channel on this server with the highest position
2916
- # that the bot has Read Messages permission on.
2917
- # @param send_messages [true, false] whether to additionally consider if the bot has Send Messages permission
2918
- # @return [Channel, nil] The default channel on this server, or `nil` if there are no channels that the bot can read.
2919
- def default_channel(send_messages = false)
2920
- bot_member = member(@bot.profile)
2921
- text_channels.sort_by { |e| [e.position, e.id] }.find do |e|
2922
- if send_messages
2923
- bot_member.can_read_messages?(e) && bot_member.can_send_messages?(e)
2924
- else
2925
- bot_member.can_read_messages?(e)
2926
- end
2927
- end
2928
- end
2929
-
2930
- alias_method :general_channel, :default_channel
2931
-
2932
- # @return [Role] The @everyone role on this server
2933
- def everyone_role
2934
- role(@id)
2935
- end
2936
-
2937
- # Gets a role on this server based on its ID.
2938
- # @param id [Integer, String, #resolve_id] The role ID to look for.
2939
- def role(id)
2940
- id = id.resolve_id
2941
- @roles.find { |e| e.id == id }
2942
- end
2943
-
2944
- # Gets a member on this server based on user ID
2945
- # @param id [Integer] The user ID to look for
2946
- # @param request [true, false] Whether the member should be requested from Discord if it's not cached
2947
- def member(id, request = true)
2948
- id = id.resolve_id
2949
- return @members[id] if member_cached?(id)
2950
- return nil unless request
2951
-
2952
- member = @bot.member(self, id)
2953
- @members[id] = member unless member.nil?
2954
- rescue
2955
- nil
2956
- end
2957
-
2958
- # @return [Array<Member>] an array of all the members on this server.
2959
- def members
2960
- return @members.values if @chunked
2961
-
2962
- @bot.debug("Members for server #{@id} not chunked yet - initiating")
2963
- @bot.request_chunks(@id)
2964
- sleep 0.05 until @chunked
2965
- @members.values
2966
- end
2967
-
2968
- alias_method :users, :members
2969
-
2970
- # @return [Array<Integration>] an array of all the integrations connected to this server.
2971
- def integrations
2972
- integration = JSON.parse(API::Server.integrations(@bot.token, @id))
2973
- integration.map { |element| Integration.new(element, @bot, self) }
2974
- end
2975
-
2976
- # @param action [Symbol] The action to only include.
2977
- # @param user [User, #resolve_id] The user to filter entries to.
2978
- # @param limit [Integer] The amount of entries to limit it to.
2979
- # @param before [Entry, #resolve_id] The entry to use to not include all entries after it.
2980
- # @return [AuditLogs] The server's audit logs.
2981
- def audit_logs(action: nil, user: nil, limit: 50, before: nil)
2982
- raise 'Invalid audit log action!' if action && AuditLogs::Actions.key(action).nil?
2983
- action = AuditLogs::Actions.key(action)
2984
- user = user.resolve_id if user
2985
- before = before.resolve_id if before
2986
- AuditLogs.new(self, @bot, JSON.parse(API::Server.audit_logs(@bot.token, @id, limit, user, action, before)))
2987
- end
2988
-
2989
- # Cache @embed
2990
- # @note For internal use only
2991
- # @!visibility private
2992
- def cache_embed_data
2993
- data = JSON.parse(API::Server.embed(@bot.token, @id))
2994
- @embed_enabled = data['enabled']
2995
- @embed_channel_id = data['channel_id']
2996
- end
2997
-
2998
- # @return [true, false] whether or not the server has widget enabled
2999
- def embed_enabled?
3000
- cache_embed_data if @embed_enabled.nil?
3001
- @embed_enabled
3002
- end
3003
- alias_method :widget_enabled, :embed_enabled?
3004
- alias_method :widget?, :embed_enabled?
3005
- alias_method :embed?, :embed_enabled?
3006
-
3007
- # @return [Channel, nil] the channel the server embed will make an invite for.
3008
- def embed_channel
3009
- cache_embed_data if @embed_enabled.nil?
3010
- @bot.channel(@embed_channel_id) if @embed_channel_id
3011
- end
3012
- alias_method :widget_channel, :embed_channel
3013
-
3014
- # Sets whether this server's embed (widget) is enabled
3015
- # @param value [true, false]
3016
- def embed_enabled=(value)
3017
- modify_embed(value, embed_channel)
3018
- end
3019
-
3020
- alias_method :widget_enabled=, :embed_enabled=
3021
-
3022
- # Sets whether this server's embed (widget) is enabled
3023
- # @param value [true, false]
3024
- # @param reason [String, nil] the reason to be shown in the audit log for this action
3025
- def set_embed_enabled(value, reason = nil)
3026
- modify_embed(value, embed_channel, reason)
3027
- end
3028
-
3029
- alias_method :set_widget_enabled, :set_embed_enabled
3030
-
3031
- # Changes the channel on the server's embed (widget)
3032
- # @param channel [Channel, String, Integer, #resolve_id] the channel to be referenced by the embed
3033
- def embed_channel=(channel)
3034
- modify_embed(embed?, channel)
3035
- end
3036
-
3037
- alias_method :widget_channel=, :embed_channel=
3038
-
3039
- # Changes the channel on the server's embed (widget)
3040
- # @param channel [Channel, String, Integer, #resolve_id] the channel to be referenced by the embed
3041
- # @param reason [String, nil] the reason to be shown in the audit log for this action
3042
- def set_embed_channel(channel, reason = nil)
3043
- modify_embed(embed?, channel, reason)
3044
- end
3045
-
3046
- alias_method :set_widget_channel, :set_embed_channel
3047
-
3048
- # Changes the channel on the server's embed (widget), and sets whether it is enabled.
3049
- # @param enabled [true, false] whether the embed (widget) is enabled
3050
- # @param channel [Channel, String, Integer, #resolve_id] the channel to be referenced by the embed
3051
- # @param reason [String, nil] the reason to be shown in the audit log for this action
3052
- def modify_embed(enabled, channel, reason = nil)
3053
- cache_embed_data if @embed_enabled.nil?
3054
- channel_id = channel ? channel.resolve_id : @embed_channel_id
3055
- response = JSON.parse(API::Server.modify_embed(@bot.token, @id, enabled, channel_id, reason))
3056
- @embed_enabled = response['enabled']
3057
- @embed_channel_id = response['channel_id']
3058
- end
3059
-
3060
- alias_method :modify_widget, :modify_embed
3061
-
3062
- # @param include_idle [true, false] Whether to count idle members as online.
3063
- # @param include_bots [true, false] Whether to include bot accounts in the count.
3064
- # @return [Array<Member>] an array of online members on this server.
3065
- def online_members(include_idle: false, include_bots: true)
3066
- @members.values.select do |e|
3067
- ((include_idle ? e.idle? : false) || e.online?) && (include_bots ? true : !e.bot_account?)
3068
- end
3069
- end
3070
-
3071
- alias_method :online_users, :online_members
3072
-
3073
- # Adds a member to this guild that has granted this bot's application an OAuth2 access token
3074
- # with the `guilds.join` scope.
3075
- # For more information about Discord's OAuth2 implementation, see: https://discordapp.com/developers/docs/topics/oauth2
3076
- # @note Your bot must be present in this server, and have permission to create instant invites for this to work.
3077
- # @param user [Integer, User, #resolve_id] the user, or ID of the user to add to this server
3078
- # @param access_token [String] the OAuth2 Bearer token that has been granted the `guilds.join` scope
3079
- # @param nick [String] the nickname to give this member upon joining
3080
- # @param roles [Role, Array<Integer, Role, #resolve_id>] the role (or roles) to give this member upon joining
3081
- # @param deaf [true, false] whether this member will be server deafened upon joining
3082
- # @param mute [true, false] whether this member will be server muted upon joining
3083
- # @return [Member] the created member
3084
- def add_member_using_token(user, access_token, nick: nil, roles: [], deaf: false, mute: false)
3085
- user_id = user.resolve_id
3086
- roles = roles.is_a?(Array) ? roles.map(&:resolve_id) : [roles.resolve_id]
3087
- response = JSON.parse(API::Server.add_member(@bot.token, @id, user_id, access_token, nick, roles, deaf, mute))
3088
- add_member Member.new(response, self, @bot)
3089
- end
3090
-
3091
- # Returns the amount of members that are candidates for pruning
3092
- # @param days [Integer] the number of days to consider for inactivity
3093
- # @return [Integer] number of members to be removed
3094
- # @raise [ArgumentError] if days is not between 1 and 30 (inclusive)
3095
- def prune_count(days)
3096
- raise ArgumentError, 'Days must be between 1 and 30' unless days.between?(1, 30)
3097
-
3098
- response = JSON.parse API::Server.prune_count(@bot.token, @id, days)
3099
- response['pruned']
3100
- end
3101
-
3102
- # Prunes (kicks) an amount of members for inactivity
3103
- # @param days [Integer] the number of days to consider for inactivity (between 1 and 30)
3104
- # @param reason [String] The reason the for the prune.
3105
- # @return [Integer] the number of members removed at the end of the operation
3106
- # @raise [ArgumentError] if days is not between 1 and 30 (inclusive)
3107
- def begin_prune(days, reason = nil)
3108
- raise ArgumentError, 'Days must be between 1 and 30' unless days.between?(1, 30)
3109
-
3110
- response = JSON.parse API::Server.begin_prune(@bot.token, @id, days, reason)
3111
- response['pruned']
3112
- end
3113
-
3114
- alias_method :prune, :begin_prune
3115
-
3116
- # @return [Array<Channel>] an array of text channels on this server
3117
- def text_channels
3118
- @channels.select(&:text?)
3119
- end
3120
-
3121
- # @return [Array<Channel>] an array of voice channels on this server
3122
- def voice_channels
3123
- @channels.select(&:voice?)
3124
- end
3125
-
3126
- # @return [Array<Channel>] an array of category channels on this server
3127
- def categories
3128
- @channels.select(&:category?)
3129
- end
3130
-
3131
- # @return [Array<Channel>] an array of channels on this server that are not in a category
3132
- def orphan_channels
3133
- @channels.reject { |c| c.parent || c.category? }
3134
- end
3135
-
3136
- # @return [String, nil] the widget URL to the server that displays the amount of online members in a
3137
- # stylish way. `nil` if the widget is not enabled.
3138
- def widget_url
3139
- update_data if @embed_enabled.nil?
3140
- return unless @embed_enabled
3141
- API.widget_url(@id)
3142
- end
3143
-
3144
- # @param style [Symbol] The style the picture should have. Possible styles are:
3145
- # * `:banner1` creates a rectangular image with the server name, member count and icon, a "Powered by Discord" message on the bottom and an arrow on the right.
3146
- # * `:banner2` creates a less tall rectangular image that has the same information as `banner1`, but the Discord logo on the right - together with the arrow and separated by a diagonal separator.
3147
- # * `:banner3` creates an image similar in size to `banner1`, but it has the arrow in the bottom part, next to the Discord logo and with a "Chat now" text.
3148
- # * `:banner4` creates a tall, almost square, image that prominently features the Discord logo at the top and has a "Join my server" in a pill-style button on the bottom. The information about the server is in the same format as the other three `banner` styles.
3149
- # * `:shield` creates a very small, long rectangle, of the style you'd find at the top of GitHub `README.md` files. It features a small version of the Discord logo at the left and the member count at the right.
3150
- # @return [String, nil] the widget banner URL to the server that displays the amount of online members,
3151
- # server icon and server name in a stylish way. `nil` if the widget is not enabled.
3152
- def widget_banner_url(style)
3153
- update_data if @embed_enabled.nil?
3154
- return unless @embed_enabled
3155
- API.widget_url(@id, style)
3156
- end
3157
-
3158
- # @return [String] the hexadecimal ID used to identify this server's splash image for their VIP invite page.
3159
- def splash_id
3160
- @splash_id ||= JSON.parse(API::Server.resolve(@bot.token, @id))['splash']
3161
- end
3162
-
3163
- # @return [String, nil] the splash image URL for the server's VIP invite page.
3164
- # `nil` if there is no splash image.
3165
- def splash_url
3166
- splash_id if @splash_id.nil?
3167
- return nil unless @splash_id
3168
- API.splash_url(@id, @splash_id)
3169
- end
3170
-
3171
- # Adds a role to the role cache
3172
- # @note For internal use only
3173
- # @!visibility private
3174
- def add_role(role)
3175
- @roles << role
3176
- end
3177
-
3178
- # Removes a role from the role cache
3179
- # @note For internal use only
3180
- # @!visibility private
3181
- def delete_role(role_id)
3182
- @roles.reject! { |r| r.id == role_id }
3183
- @members.each do |_, member|
3184
- new_roles = member.roles.reject { |r| r.id == role_id }
3185
- member.update_roles(new_roles)
3186
- end
3187
- @channels.each do |channel|
3188
- overwrites = channel.permission_overwrites.reject { |id, _| id == role_id }
3189
- channel.update_overwrites(overwrites)
3190
- end
3191
- end
3192
-
3193
- # Updates the positions of all roles on the server
3194
- # @note For internal use only
3195
- # @!visibility private
3196
- def update_role_positions(role_positions)
3197
- response = JSON.parse(API::Server.update_role_positions(@bot.token, @id, role_positions))
3198
- response.each do |data|
3199
- updated_role = Role.new(data, @bot, self)
3200
- role(updated_role.id).update_from(updated_role)
3201
- end
3202
- end
3203
-
3204
- # Adds a member to the member cache.
3205
- # @note For internal use only
3206
- # @!visibility private
3207
- def add_member(member)
3208
- @member_count += 1
3209
- @members[member.id] = member
3210
- end
3211
-
3212
- # Removes a member from the member cache.
3213
- # @note For internal use only
3214
- # @!visibility private
3215
- def delete_member(user_id)
3216
- @members.delete(user_id)
3217
- @member_count -= 1
3218
- end
3219
-
3220
- # Checks whether a member is cached
3221
- # @note For internal use only
3222
- # @!visibility private
3223
- def member_cached?(user_id)
3224
- @members.include?(user_id)
3225
- end
3226
-
3227
- # Adds a member to the cache
3228
- # @note For internal use only
3229
- # @!visibility private
3230
- def cache_member(member)
3231
- @members[member.id] = member
3232
- end
3233
-
3234
- # Updates a member's voice state
3235
- # @note For internal use only
3236
- # @!visibility private
3237
- def update_voice_state(data)
3238
- user_id = data['user_id'].to_i
3239
-
3240
- if data['channel_id']
3241
- unless @voice_states[user_id]
3242
- # Create a new voice state for the user
3243
- @voice_states[user_id] = VoiceState.new(user_id)
3244
- end
3245
-
3246
- # Update the existing voice state (or the one we just created)
3247
- channel = @channels_by_id[data['channel_id'].to_i]
3248
- @voice_states[user_id].update(
3249
- channel,
3250
- data['mute'],
3251
- data['deaf'],
3252
- data['self_mute'],
3253
- data['self_deaf']
3254
- )
3255
- else
3256
- # The user is not in a voice channel anymore, so delete its voice state
3257
- @voice_states.delete(user_id)
3258
- end
3259
- end
3260
-
3261
- # Creates a channel on this server with the given name.
3262
- # @note If parent is provided, permission overwrites have the follow behavior:
3263
- #
3264
- # 1. If overwrites is null, the new channel inherits the parent's permissions.
3265
- # 2. If overwrites is [], the new channel inherits the parent's permissions.
3266
- # 3. If you supply one or more overwrites, the channel will be created with those permissions and ignore the parents.
3267
- #
3268
- # @param name [String] Name of the channel to create
3269
- # @param type [Integer, Symbol] Type of channel to create (0: text, 2: voice, 4: category)
3270
- # @param topic [String] the topic of this channel, if it will be a text channel
3271
- # @param bitrate [Integer] the bitrate of this channel, if it will be a voice channel
3272
- # @param user_limit [Integer] the user limit of this channel, if it will be a voice channel
3273
- # @param permission_overwrites [Array<Hash>, Array<Overwrite>] permission overwrites for this channel
3274
- # @param parent [Channel, #resolve_id] parent category for this channel to be created in.
3275
- # @param nsfw [true, false] whether this channel should be created as nsfw
3276
- # @param rate_limit_per_user [Integer] how many seconds users need to wait in between messages.
3277
- # @param reason [String] The reason the for the creation of this channel.
3278
- # @return [Channel] the created channel.
3279
- # @raise [ArgumentError] if type is not 0 (text), 2 (voice), or 4 (category)
3280
- def create_channel(name, type = 0, topic: nil, bitrate: nil, user_limit: nil, permission_overwrites: nil, parent: nil, nsfw: false, rate_limit_per_user: nil, reason: nil)
3281
- type = Channel::TYPES[type] if type.is_a?(Symbol)
3282
- raise ArgumentError, 'Channel type must be either 0 (text), 2 (voice), or 4 (category)!' unless [0, 2, 4].include?(type)
3283
- permission_overwrites.map! { |e| e.is_a?(Overwrite) ? e.to_hash : e } if permission_overwrites.is_a?(Array)
3284
- parent_id = parent.respond_to?(:resolve_id) ? parent.resolve_id : nil
3285
- response = API::Server.create_channel(@bot.token, @id, name, type, topic, bitrate, user_limit, permission_overwrites, parent_id, nsfw, rate_limit_per_user, reason)
3286
- Channel.new(JSON.parse(response), @bot)
3287
- end
3288
-
3289
- # Creates a role on this server which can then be modified. It will be initialized
3290
- # with the regular role defaults the client uses unless specified, i.e. name is "new role",
3291
- # permissions are the default, colour is the default etc.
3292
- # @param name [String] Name of the role to create
3293
- # @param colour [Integer, ColourRGB, #combined] The roles colour
3294
- # @param hoist [true, false]
3295
- # @param mentionable [true, false]
3296
- # @param permissions [Integer, Array<Symbol>, Permissions, #bits] The permissions to write to the new role.
3297
- # @param reason [String] The reason the for the creation of this role.
3298
- # @return [Role] the created role.
3299
- def create_role(name: 'new role', colour: 0, hoist: false, mentionable: false, permissions: 104_324_161, reason: nil)
3300
- colour = colour.respond_to?(:combined) ? colour.combined : colour
3301
-
3302
- permissions = if permissions.is_a?(Array)
3303
- Permissions.bits(permissions)
3304
- elsif permissions.respond_to?(:bits)
3305
- permissions.bits
3306
- else
3307
- permissions
3308
- end
3309
-
3310
- response = API::Server.create_role(@bot.token, @id, name, colour, hoist, mentionable, permissions, reason)
3311
-
3312
- role = Role.new(JSON.parse(response), @bot, self)
3313
- @roles << role
3314
- role
3315
- end
3316
-
3317
- # @return [Array<ServerBan>] a list of banned users on this server and the reason they were banned.
3318
- def bans
3319
- response = JSON.parse(API::Server.bans(@bot.token, @id))
3320
- response.map do |e|
3321
- ServerBan.new(self, User.new(e['user'], @bot), e['reason'])
3322
- end
3323
- end
3324
-
3325
- # Bans a user from this server.
3326
- # @param user [User, #resolve_id] The user to ban.
3327
- # @param message_days [Integer] How many days worth of messages sent by the user should be deleted.
3328
- # @param reason [String] The reason the user is being banned.
3329
- def ban(user, message_days = 0, reason: nil)
3330
- API::Server.ban_user(@bot.token, @id, user.resolve_id, message_days, reason)
3331
- end
3332
-
3333
- # Unbans a previously banned user from this server.
3334
- # @param user [User, #resolve_id] The user to unban.
3335
- # @param reason [String] The reason the user is being unbanned.
3336
- def unban(user, reason = nil)
3337
- API::Server.unban_user(@bot.token, @id, user.resolve_id, reason)
3338
- end
3339
-
3340
- # Kicks a user from this server.
3341
- # @param user [User, #resolve_id] The user to kick.
3342
- # @param reason [String] The reason the user is being kicked.
3343
- def kick(user, reason = nil)
3344
- API::Server.remove_member(@bot.token, @id, user.resolve_id, reason)
3345
- end
3346
-
3347
- # Forcibly moves a user into a different voice channel. Only works if the bot has the permission needed.
3348
- # @param user [User, #resolve_id] The user to move.
3349
- # @param channel [Channel, #resolve_id] The voice channel to move into.
3350
- def move(user, channel)
3351
- API::Server.update_member(@bot.token, @id, user.resolve_id, channel_id: channel.resolve_id)
3352
- end
3353
-
3354
- # Deletes this server. Be aware that this is permanent and impossible to undo, so be careful!
3355
- def delete
3356
- API::Server.delete(@bot.token, @id)
3357
- end
3358
-
3359
- # Leave the server.
3360
- def leave
3361
- API::User.leave_server(@bot.token, @id)
3362
- end
3363
-
3364
- # Transfers server ownership to another user.
3365
- # @param user [User, #resolve_id] The user who should become the new owner.
3366
- def owner=(user)
3367
- API::Server.transfer_ownership(@bot.token, @id, user.resolve_id)
3368
- end
3369
-
3370
- # Sets the server's name.
3371
- # @param name [String] The new server name.
3372
- def name=(name)
3373
- update_server_data(name: name)
3374
- end
3375
-
3376
- # @return [Array<VoiceRegion>] collection of available voice regions to this guild
3377
- def available_voice_regions
3378
- return @available_voice_regions if @available_voice_regions
3379
-
3380
- @available_voice_regions = {}
3381
-
3382
- data = JSON.parse API::Server.regions(@bot.token, @id)
3383
- @available_voice_regions = data.map { |e| VoiceRegion.new e }
3384
- end
3385
-
3386
- # @return [VoiceRegion, nil] voice region data for this server's region
3387
- # @note This may return `nil` if this server's voice region is deprecated.
3388
- def region
3389
- available_voice_regions.find { |e| e.id == @region_id }
3390
- end
3391
-
3392
- # Moves the server to another region. This will cause a voice interruption of at most a second.
3393
- # @param region [String] The new region the server should be in.
3394
- def region=(region)
3395
- update_server_data(region: region.to_s)
3396
- end
3397
-
3398
- # Sets the server's icon.
3399
- # @param icon [String, #read] The new icon, in base64-encoded JPG format.
3400
- def icon=(icon)
3401
- if icon.respond_to? :read
3402
- icon_string = 'data:image/jpg;base64,'
3403
- icon_string += Base64.strict_encode64(icon.read)
3404
- update_server_data(icon_id: icon_string)
3405
- else
3406
- update_server_data(icon_id: icon)
3407
- end
3408
- end
3409
-
3410
- # Sets the server's AFK channel.
3411
- # @param afk_channel [Channel, nil] The new AFK channel, or `nil` if there should be none set.
3412
- def afk_channel=(afk_channel)
3413
- update_server_data(afk_channel_id: afk_channel.resolve_id)
3414
- end
3415
-
3416
- # Sets the server's system channel.
3417
- # @param system_channel [Channel, String, Integer, #resolve_id, nil] The new system channel, or `nil` should it be disabled.
3418
- def system_channel=(system_channel)
3419
- update_server_data(system_channel_id: system_channel.resolve_id)
3420
- end
3421
-
3422
- # Sets the amount of time after which a user gets moved into the AFK channel.
3423
- # @param afk_timeout [Integer] The AFK timeout, in seconds.
3424
- def afk_timeout=(afk_timeout)
3425
- update_server_data(afk_timeout: afk_timeout)
3426
- end
3427
-
3428
- # A map of possible server verification levels to symbol names
3429
- VERIFICATION_LEVELS = {
3430
- none: 0,
3431
- low: 1,
3432
- medium: 2,
3433
- high: 3,
3434
- very_high: 4
3435
- }.freeze
3436
-
3437
- # @return [Symbol] the verification level of the server (:none = none, :low = 'Must have a verified email on their Discord account', :medium = 'Has to be registered with Discord for at least 5 minutes', :high = 'Has to be a member of this server for at least 10 minutes', :very_high = 'Must have a verified phone on their Discord account').
3438
- def verification_level
3439
- VERIFICATION_LEVELS.key @verification_level
3440
- end
3441
-
3442
- # Sets the verification level of the server
3443
- # @param level [Integer, Symbol] The verification level from 0-4 or Symbol (see {VERIFICATION_LEVELS})
3444
- def verification_level=(level)
3445
- level = VERIFICATION_LEVELS[level] if level.is_a?(Symbol)
3446
-
3447
- update_server_data(verification_level: level)
3448
- end
3449
-
3450
- # A map of possible message notification levels to symbol names
3451
- NOTIFICATION_LEVELS = {
3452
- all_messages: 0,
3453
- only_mentions: 1
3454
- }.freeze
3455
-
3456
- # @return [Symbol] the default message notifications settings of the server (:all = 'All messages', :mentions = 'Only @mentions').
3457
- def default_message_notifications
3458
- NOTIFICATION_LEVELS.key @default_message_notifications
3459
- end
3460
-
3461
- # Sets the default message notification level
3462
- # @param notification_level [Integer, Symbol] The default message notificiation 0-1 or Symbol (see {NOTIFICATION_LEVELS})
3463
- def default_message_notifications=(notification_level)
3464
- notification_level = NOTIFICATION_LEVELS[notification_level] if notification_level.is_a?(Symbol)
3465
-
3466
- update_server_data(default_message_notifications: notification_level)
3467
- end
3468
-
3469
- alias_method :notification_level=, :default_message_notifications=
3470
-
3471
- # Sets the server splash
3472
- # @param splash_hash [String] The splash hash
3473
- def splash=(splash_hash)
3474
- update_server_data(splash: splash_hash)
3475
- end
3476
-
3477
- # A map of possible content filter levels to symbol names
3478
- FILTER_LEVELS = {
3479
- disabled: 0,
3480
- members_without_roles: 1,
3481
- all_members: 2
3482
- }.freeze
3483
-
3484
- # @return [Symbol] the explicit content filter level of the server (:none = 'Don't scan any messages.', :exclude_roles = 'Scan messages for members without a role.', :all = 'Scan messages sent by all members.').
3485
- def explicit_content_filter
3486
- FILTER_LEVELS.key @explicit_content_filter
3487
- end
3488
-
3489
- alias_method :content_filter_level, :explicit_content_filter
3490
-
3491
- # Sets the server content filter.
3492
- # @param filter_level [Integer, Symbol] The content filter from 0-2 or Symbol (see {FILTER_LEVELS})
3493
- def explicit_content_filter=(filter_level)
3494
- filter_level = FILTER_LEVELS[filter_level] if filter_level.is_a?(Symbol)
3495
-
3496
- update_server_data(explicit_content_filter: filter_level)
3497
- end
3498
-
3499
- # @return [true, false] whether this server has any emoji or not.
3500
- def any_emoji?
3501
- @emoji.any?
3502
- end
3503
-
3504
- alias_method :has_emoji?, :any_emoji?
3505
- alias_method :emoji?, :any_emoji?
3506
-
3507
- # Requests a list of Webhooks on the server.
3508
- # @return [Array<Webhook>] webhooks on the server.
3509
- def webhooks
3510
- webhooks = JSON.parse(API::Server.webhooks(@bot.token, @id))
3511
- webhooks.map { |webhook| Webhook.new(webhook, @bot) }
3512
- end
3513
-
3514
- # Requests a list of Invites to the server.
3515
- # @return [Array<Invite>] invites to the server.
3516
- def invites
3517
- invites = JSON.parse(API::Server.invites(@bot.token, @id))
3518
- invites.map { |invite| Invite.new(invite, @bot) }
3519
- end
3520
-
3521
- # Processes a GUILD_MEMBERS_CHUNK packet, specifically the members field
3522
- # @note For internal use only
3523
- # @!visibility private
3524
- def process_chunk(members)
3525
- process_members(members)
3526
- @processed_chunk_members += members.length
3527
- LOGGER.debug("Processed one chunk on server #{@id} - length #{members.length}")
3528
-
3529
- # Don't bother with the rest of the method if it's not truly the last packet
3530
- return unless @processed_chunk_members == @member_count
3531
-
3532
- LOGGER.debug("Finished chunking server #{@id}")
3533
-
3534
- # Reset everything to normal
3535
- @chunked = true
3536
- @processed_chunk_members = 0
3537
- end
3538
-
3539
- # @return [Channel, nil] the AFK voice channel of this server, or `nil` if none is set.
3540
- def afk_channel
3541
- @bot.channel(@afk_channel_id) if @afk_channel_id
3542
- end
3543
-
3544
- # @return [Channel, nil] the system channel (used for automatic welcome messages) of a server, or `nil` if none is set.
3545
- def system_channel
3546
- @bot.channel(@system_channel_id) if @system_channel_id
3547
- end
3548
-
3549
- # Updates the cached data with new data
3550
- # @note For internal use only
3551
- # @!visibility private
3552
- def update_data(new_data = nil)
3553
- new_data ||= JSON.parse(API::Server.resolve(@bot.token, @id))
3554
- @name = new_data[:name] || new_data['name'] || @name
3555
- @region_id = new_data[:region] || new_data['region'] || @region_id
3556
- @icon_id = new_data[:icon] || new_data['icon'] || @icon_id
3557
- @afk_timeout = new_data[:afk_timeout] || new_data['afk_timeout'] || @afk_timeout
3558
-
3559
- afk_channel_id = new_data[:afk_channel_id] || new_data['afk_channel_id'] || @afk_channel
3560
- @afk_channel_id = afk_channel_id.nil? ? nil : afk_channel_id.resolve_id
3561
- embed_channel_id = new_data[:embed_channel_id] || new_data['embed_channel_id'] || @embed_channel
3562
- @embed_channel_id = embed_channel_id.nil? ? nil : embed_channel_id.resolve_id
3563
- system_channel_id = new_data[:system_channel_id] || new_data['system_channel_id'] || @system_channel
3564
- @system_channel_id = system_channel_id.nil? ? nil : system_channel_id.resolve_id
3565
-
3566
- @embed_enabled = new_data[:embed_enabled] || new_data['embed_enabled']
3567
- @splash = new_data[:splash_id] || new_data['splash_id'] || @splash_id
3568
-
3569
- @verification_level = new_data[:verification_level] || new_data['verification_level'] || @verification_level
3570
- @explicit_content_filter = new_data[:explicit_content_filter] || new_data['explicit_content_filter'] || @explicit_content_filter
3571
- @default_message_notifications = new_data[:default_message_notifications] || new_data['default_message_notifications'] || @default_message_notifications
3572
- end
3573
-
3574
- # Adds a channel to this server's cache
3575
- # @note For internal use only
3576
- # @!visibility private
3577
- def add_channel(channel)
3578
- @channels << channel
3579
- @channels_by_id[channel.id] = channel
3580
- end
3581
-
3582
- # Deletes a channel from this server's cache
3583
- # @note For internal use only
3584
- # @!visibility private
3585
- def delete_channel(id)
3586
- @channels.reject! { |e| e.id == id }
3587
- @channels_by_id.delete(id)
3588
- end
3589
-
3590
- # Updates the cached emoji data with new data
3591
- # @note For internal use only
3592
- # @!visibility private
3593
- def update_emoji_data(new_data)
3594
- @emoji = {}
3595
- process_emoji(new_data['emojis'])
3596
- end
3597
-
3598
- # The inspect method is overwritten to give more useful output
3599
- def inspect
3600
- "<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}>"
3601
- end
3602
-
3603
- private
3604
-
3605
- def update_server_data(new_data)
3606
- response = JSON.parse(API::Server.update(@bot.token, @id,
3607
- new_data[:name] || @name,
3608
- new_data[:region] || @region_id,
3609
- new_data[:icon_id] || @icon_id,
3610
- new_data[:afk_channel_id] || @afk_channel_id,
3611
- new_data[:afk_timeout] || @afk_timeout,
3612
- new_data[:splash] || @splash,
3613
- new_data[:default_message_notifications] || @default_message_notifications,
3614
- new_data[:verification_level] || @verification_level,
3615
- new_data[:explicit_content_filter] || @explicit_content_filter,
3616
- new_data[:system_channel_id] || @system_channel_id))
3617
- update_data(response)
3618
- end
3619
-
3620
- def process_roles(roles)
3621
- # Create roles
3622
- @roles = []
3623
- @roles_by_id = {}
3624
-
3625
- return unless roles
3626
- roles.each do |element|
3627
- role = Role.new(element, @bot, self)
3628
- @roles << role
3629
- @roles_by_id[role.id] = role
3630
- end
3631
- end
3632
-
3633
- def process_emoji(emoji)
3634
- return if emoji.empty?
3635
- emoji.each do |element|
3636
- new_emoji = Emoji.new(element, @bot, self)
3637
- @emoji[new_emoji.id] = new_emoji
3638
- end
3639
- end
3640
-
3641
- def process_members(members)
3642
- return unless members
3643
- members.each do |element|
3644
- member = Member.new(element, self, @bot)
3645
- @members[member.id] = member
3646
- end
3647
- end
3648
-
3649
- def process_presences(presences)
3650
- # Update user statuses with presence info
3651
- return unless presences
3652
- presences.each do |element|
3653
- next unless element['user']
3654
- user_id = element['user']['id'].to_i
3655
- user = @members[user_id]
3656
- if user
3657
- user.update_presence(element)
3658
- else
3659
- LOGGER.warn "Rogue presence update! #{element['user']['id']} on #{@id}"
3660
- end
3661
- end
3662
- end
3663
-
3664
- def process_channels(channels)
3665
- @channels = []
3666
- @channels_by_id = {}
3667
-
3668
- return unless channels
3669
- channels.each do |element|
3670
- channel = @bot.ensure_channel(element, self)
3671
- @channels << channel
3672
- @channels_by_id[channel.id] = channel
3673
- end
3674
- end
3675
-
3676
- def process_voice_states(voice_states)
3677
- return unless voice_states
3678
- voice_states.each do |element|
3679
- update_voice_state(element)
3680
- end
3681
- end
3682
- end
3683
-
3684
- # A ban entry on a server
3685
- class ServerBan
3686
- # @return [String, nil] the reason the user was banned, if provided
3687
- attr_reader :reason
3688
-
3689
- # @return [User] the user that was banned
3690
- attr_reader :user
3691
-
3692
- # @return [Server] the server this ban belongs to
3693
- attr_reader :server
3694
-
3695
- # @!visibility private
3696
- def initialize(server, user, reason)
3697
- @server = server
3698
- @user = user
3699
- @reason = reason
3700
- end
3701
-
3702
- # Removes this ban on the associated user in the server
3703
- # @param reason [String] the reason for removing the ban
3704
- def remove(reason = nil)
3705
- @server.unban(user, reason)
3706
- end
3707
-
3708
- alias_method :unban, :remove
3709
- alias_method :lift, :remove
3710
- end
3711
-
3712
- # A webhook on a server channel
3713
- class Webhook
3714
- include IDObject
3715
-
3716
- # @return [String] the webhook name.
3717
- attr_reader :name
3718
-
3719
- # @return [Channel] the channel that the webhook is currently connected to.
3720
- attr_reader :channel
3721
-
3722
- # @return [Server] the server that the webhook is currently connected to.
3723
- attr_reader :server
3724
-
3725
- # @return [String] the webhook's token.
3726
- attr_reader :token
3727
-
3728
- # @return [String] the webhook's avatar id.
3729
- attr_reader :avatar
3730
-
3731
- # Gets the user object of the creator of the webhook. May be limited to username, discriminator,
3732
- # ID and avatar if the bot cannot reach the owner
3733
- # @return [Member, User, nil] the user object of the owner or nil if the webhook was requested using the token.
3734
- attr_reader :owner
3735
-
3736
- def initialize(data, bot)
3737
- @bot = bot
3738
-
3739
- @name = data['name']
3740
- @id = data['id'].to_i
3741
- @channel = bot.channel(data['channel_id'])
3742
- @server = @channel.server
3743
- @token = data['token']
3744
- @avatar = data['avatar']
3745
-
3746
- # Will not exist if the data was requested through a webhook token
3747
- return unless data['user']
3748
- @owner = @server.member(data['user']['id'].to_i)
3749
- return if @owner
3750
- Discordrb::LOGGER.debug("Member with ID #{data['user']['id']} not cached (possibly left the server).")
3751
- @owner = @bot.ensure_user(data['user'])
3752
- end
3753
-
3754
- # Sets the webhook's avatar.
3755
- # @param avatar [String, #read] The new avatar, in base64-encoded JPG format.
3756
- def avatar=(avatar)
3757
- update_webhook(avatar: avatarise(avatar))
3758
- end
3759
-
3760
- # Deletes the webhook's avatar.
3761
- def delete_avatar
3762
- update_webhook(avatar: nil)
3763
- end
3764
-
3765
- # Sets the webhook's channel
3766
- # @param channel [Channel, String, Integer, #resolve_id] The channel the webhook should use.
3767
- def channel=(channel)
3768
- update_webhook(channel_id: channel.resolve_id)
3769
- end
3770
-
3771
- # Sets the webhook's name.
3772
- # @param name [String] The webhook's new name.
3773
- def name=(name)
3774
- update_webhook(name: name)
3775
- end
3776
-
3777
- # Updates the webhook if you need to edit more than 1 attribute.
3778
- # @param data [Hash] the data to update.
3779
- # @option data [String, #read, nil] :avatar The new avatar, in base64-encoded JPG format, or nil to delete the avatar.
3780
- # @option data [Channel, String, Integer, #resolve_id] :channel The channel the webhook should use.
3781
- # @option data [String] :name The webhook's new name.
3782
- # @option data [String] :reason The reason for the webhook changes.
3783
- def update(data)
3784
- # Only pass a value for avatar if the key is defined as sending nil will delete the
3785
- data[:avatar] = avatarise(data[:avatar]) if data.key?(:avatar)
3786
- data[:channel_id] = data[:channel].resolve_id
3787
- data.delete(:channel)
3788
- update_webhook(data)
3789
- end
3790
-
3791
- # Deletes the webhook.
3792
- # @param reason [String] The reason the invite is being deleted.
3793
- def delete(reason = nil)
3794
- if token?
3795
- API::Webhook.token_delete_webhook(@token, @id, reason)
3796
- else
3797
- API::Webhook.delete_webhook(@bot.token, @id, reason)
3798
- end
3799
- end
3800
-
3801
- # Utility function to get a webhook's avatar URL.
3802
- # @return [String] the URL to the avatar image
3803
- def avatar_url
3804
- return API::User.default_avatar unless @avatar
3805
- API::User.avatar_url(@id, @avatar)
3806
- end
3807
-
3808
- # The `inspect` method is overwritten to give more useful output.
3809
- def inspect
3810
- "<Webhook name=#{@name} id=#{@id}>"
3811
- end
3812
-
3813
- # Utility function to know if the webhook was requested through a webhook token, rather than auth.
3814
- # @return [true, false] whether the webhook was requested by token or not.
3815
- def token?
3816
- @owner.nil?
3817
- end
3818
-
3819
- private
3820
-
3821
- def avatarise(avatar)
3822
- if avatar.respond_to? :read
3823
- "data:image/jpg;base64,#{Base64.strict_encode64(avatar.read)}"
3824
- else
3825
- avatar
3826
- end
3827
- end
3828
-
3829
- def update_internal(data)
3830
- @name = data['name']
3831
- @avatar_id = data['avatar']
3832
- @channel = @bot.channel(data['channel_id'])
3833
- end
3834
-
3835
- def update_webhook(new_data)
3836
- reason = new_data.delete(:reason)
3837
- data = JSON.parse(if token?
3838
- API::Webhook.token_update_webhook(@token, @id, new_data, reason)
3839
- else
3840
- API::Webhook.update_webhook(@bot.token, @id, new_data, reason)
3841
- end)
3842
- # Only update cache if API call worked
3843
- update_internal(data) if data['name']
3844
- end
3845
- end
3846
-
3847
- # A server's audit logs
3848
- class AuditLogs
3849
- # The numbers associated with the type of action.
3850
- Actions = {
3851
- 1 => :server_update,
3852
- 10 => :channel_create,
3853
- 11 => :channel_update,
3854
- 12 => :channel_delete,
3855
- 13 => :channel_overwrite_create,
3856
- 14 => :channel_overwrite_update,
3857
- 15 => :channel_overwrite_delete,
3858
- 20 => :member_kick,
3859
- 21 => :member_prune,
3860
- 22 => :member_ban_add,
3861
- 23 => :member_ban_remove,
3862
- 24 => :member_update,
3863
- 25 => :member_role_update,
3864
- 30 => :role_create,
3865
- 31 => :role_update,
3866
- 32 => :role_delete,
3867
- 40 => :invite_create,
3868
- 41 => :invite_update,
3869
- 42 => :invite_delete,
3870
- 50 => :webhook_create,
3871
- 51 => :webhook_update,
3872
- 52 => :webhook_delete,
3873
- 60 => :emoji_create,
3874
- 61 => :emoji_update,
3875
- 62 => :emoji_delete,
3876
- # 70
3877
- # 71
3878
- 72 => :message_delete
3879
- }.freeze
3880
-
3881
- # @return [Hash<String => User>] the users included in the audit logs.
3882
- attr_reader :users
3883
-
3884
- # @return [Hash<String => Webhook>] the webhooks included in the audit logs.
3885
- attr_reader :webhooks
3886
-
3887
- # @return [Array<Entry>] the entries listed in the audit logs.
3888
- attr_reader :entries
3889
-
3890
- # @!visibility private
3891
- def initialize(server, bot, data)
3892
- @bot = bot
3893
- @server = server
3894
- @users = {}
3895
- @webhooks = {}
3896
- @entries = data['audit_log_entries'].map { |entry| Entry.new(self, @server, @bot, entry) }
3897
-
3898
- process_users(data['users'])
3899
- process_webhooks(data['webhooks'])
3900
- end
3901
-
3902
- # An entry in a server's audit logs.
3903
- class Entry
3904
- include IDObject
3905
-
3906
- # @return [Symbol] the action that was performed.
3907
- attr_reader :action
3908
-
3909
- # @return [Symbol] the type action that was performed. (:create, :delete, :update, :unknown)
3910
- attr_reader :action_type
3911
-
3912
- # @return [Symbol] the type of target being performed on. (:server, :channel, :user, :role, :invite, :webhook, :emoji, :unknown)
3913
- attr_reader :target_type
3914
-
3915
- # @return [Integer, nil] the amount of messages deleted. Only present if the action is `:message_delete`.
3916
- attr_reader :count
3917
- alias_method :amount, :count
3918
-
3919
- # @return [Integer, nil] the amount of days the members were inactive for. Only present if the action is `:member_prune`.
3920
- attr_reader :days
3921
-
3922
- # @return [Integer, nil] the amount of members removed. Only present if the action is `:member_prune`.
3923
- attr_reader :members_removed
3924
-
3925
- # @return [String, nil] the reason for this action occuring.
3926
- attr_reader :reason
3927
-
3928
- # @return [Hash<String => Change>, RoleChange, nil] the changes from this log, listing the key as the key changed. Will be a RoleChange object if the action is `:member_role_update`. Will be nil if the action is either `:message_delete` or `:member_prune`.
3929
- attr_reader :changes
3930
-
3931
- # @!visibility private
3932
- def initialize(logs, server, bot, data)
3933
- @bot = bot
3934
- @id = data['id'].resolve_id
3935
- @logs = logs
3936
- @server = server
3937
- @data = data
3938
- @action = Actions[data['action_type']]
3939
- @reason = data['reason']
3940
- @action_type = AuditLogs.action_type_for(data['action_type'])
3941
- @target_type = AuditLogs.target_type_for(data['action_type'])
3942
-
3943
- # Sets the 'changes' variable to a empty hash if there are no special actions.
3944
- @changes = {} unless @action == :message_delete || @action == :member_prune || @action == :member_role_update
3945
-
3946
- # Sets the 'changes' variable to a RoleChange class if theres a role update.
3947
- @changes = RoleChange.new(data['changes'][0], @server) if @action == :member_role_update
3948
-
3949
- process_changes(data['changes']) unless @action == :member_role_update
3950
- return unless data.include?('options')
3951
-
3952
- # Checks and sets variables for special action options.
3953
- @count = data['options']['count'].to_i unless data['options']['count'].nil?
3954
- @channel_id = data['options']['channel'].to_i unless data['options']['channel'].nil?
3955
- @days = data['options']['delete_member_days'].to_i unless data['options']['delete_member_days'].nil?
3956
- @members_removed = data['options']['members_removed'].to_i unless data['options']['members_removed'].nil?
3957
- end
3958
-
3959
- # @return [Server, Channel, Member, User, Role, Invite, Webhook, Emoji, nil] the target being performed on.
3960
- def target
3961
- @target ||= process_target(@data['target_id'], @target_type)
3962
- end
3963
-
3964
- # @return [Member, User] the user that authored this action. Can be a User object if the user no longer exists in the server.
3965
- def user
3966
- @user ||= @server.member(@data['user_id'].to_i) || @bot.user(@data['user_id'].to_i) || @logs.user(@data['user_id'].to_i)
3967
- end
3968
- alias_method :author, :user
3969
-
3970
- # @return [Channel, nil] the amount of messages deleted. Won't be nil if the action is `:message_delete`.
3971
- def channel
3972
- return nil unless @channel_id
3973
- @channel ||= @bot.channel(@channel_id, @server, bot, self)
3974
- end
3975
-
3976
- # @!visibility private
3977
- def process_target(id, type)
3978
- id = id.resolve_id unless id.nil?
3979
- case type
3980
- when :server then @server # Since it won't be anything else
3981
- when :channel then @bot.channel(id, @server)
3982
- when :user, :message then @server.member(id) || @bot.user(id) || @logs.user(id)
3983
- when :role then @server.role(id)
3984
- when :invite then @bot.invite(@data['changes'].find { |change| change['key'] == 'code' }.values.delete_if { |v| v == 'code' }.first)
3985
- when :webhook then @server.webhooks.find { |webhook| webhook.id == id } || @logs.webhook(id)
3986
- when :emoji then @server.emoji[id]
3987
- end
3988
- end
3989
-
3990
- # The inspect method is overwritten to give more useful output
3991
- def inspect
3992
- "<AuditLogs::Entry id=#{@id} action=#{@action} reason=#{@reason} action_type=#{@action_type} target_type=#{@target_type} count=#{@count} days=#{@days} members_removed=#{@members_removed}>"
3993
- end
3994
-
3995
- # Process action changes
3996
- # @note For internal use only
3997
- # @!visibility private
3998
- def process_changes(changes)
3999
- return unless changes
4000
- changes.each do |element|
4001
- change = Change.new(element, @server, @bot, self)
4002
- @changes[change.key] = change
4003
- end
4004
- end
4005
- end
4006
-
4007
- # A change in a audit log entry.
4008
- class Change
4009
- # @return [String] the key that was changed.
4010
- # @note You should check with the Discord API Documentation on what key gives out what value.
4011
- attr_reader :key
4012
-
4013
- # @return [String, Integer, true, false, Permissions, Overwrite, nil] the value that was changed from.
4014
- attr_reader :old
4015
- alias_method :old_value, :old
4016
-
4017
- # @return [String, Integer, true, false, Permissions, Overwrite, nil] the value that was changed to.
4018
- attr_reader :new
4019
- alias_method :new_value, :new
4020
-
4021
- # @!visibility private
4022
- def initialize(data, server, bot, logs)
4023
- @key = data['key']
4024
- @old = data['old_value']
4025
- @new = data['new_value']
4026
- @server = server
4027
- @bot = bot
4028
- @logs = logs
4029
-
4030
- @old = Permissions.new(@old) if @old && @key == 'permissions'
4031
- @new = Permissions.new(@new) if @new && @key == 'permissions'
4032
-
4033
- @old = @old.map { |o| Overwrite.new(o['id'], type: o['type'].to_sym, allow: o['allow'], deny: o['deny']) } if @old && @key == 'permission_overwrites'
4034
- @new = @new.map { |o| Overwrite.new(o['id'], type: o['type'].to_sym, allow: o['allow'], deny: o['deny']) } if @new && @key == 'permission_overwrites'
4035
- end
4036
-
4037
- # @return [Channel, nil] the channel that was previously used in the server widget. Only present if the key for this change is `widget_channel_id`.
4038
- def old_widget_channel
4039
- @bot.channel(@old, @server) if @old && @key == 'widget_channel_id'
4040
- end
4041
-
4042
- # @return [Channel, nil] the channel that is used in the server widget prior to this change. Only present if the key for this change is `widget_channel_id`.
4043
- def new_widget_channel
4044
- @bot.channel(@new, @server) if @new && @key == 'widget_channel_id'
4045
- end
4046
-
4047
- # @return [Channel, nil] the channel that was previously used in the server as an AFK channel. Only present if the key for this change is `afk_channel_id`.
4048
- def old_afk_channel
4049
- @bot.channel(@old, @server) if @old && @key == 'afk_channel_id'
4050
- end
4051
-
4052
- # @return [Channel, nil] the channel that is used in the server as an AFK channel prior to this change. Only present if the key for this change is `afk_channel_id`.
4053
- def new_afk_channel
4054
- @bot.channel(@new, @server) if @new && @key == 'afk_channel_id'
4055
- end
4056
-
4057
- # @return [Member, User, nil] the member that used to be the owner of the server. Only present if the for key for this change is `owner_id`.
4058
- def old_owner
4059
- @server.member(@old) || @bot.user(@old) || @logs.user(@old) if @old && @key == 'owner_id'
4060
- end
4061
-
4062
- # @return [Member, User, nil] the member that is now the owner of the server prior to this change. Only present if the key for this change is `owner_id`.
4063
- def new_owner
4064
- @server.member(@new) || @bot.user(@new) || @logs.user(@new) if @new && @key == 'owner_id'
4065
- end
4066
- end
4067
-
4068
- # A change that includes roles.
4069
- class RoleChange
4070
- # @return [Symbol] what type of change this is: (:add, :remove)
4071
- attr_reader :type
4072
-
4073
- # @!visibility private
4074
- def initialize(data, server)
4075
- @type = data['key'].delete('$').to_sym
4076
- @role_id = data['new_value'][0]['id'].to_i
4077
- @server = server
4078
- end
4079
-
4080
- # @return [Role] the role being used.
4081
- def role
4082
- @role ||= @server.role(@role_id)
4083
- end
4084
- end
4085
-
4086
- # @return [Entry] the latest entry in the audit logs.
4087
- def latest
4088
- @entries.first
4089
- end
4090
- alias_method :first, :latest
4091
-
4092
- # Gets a user in the audit logs data based on user ID
4093
- # @note This only uses data given by the audit logs request
4094
- # @param id [#resolve_id] The user ID to look for
4095
- def user(id)
4096
- @users[id.resolve_id]
4097
- end
4098
-
4099
- # Gets a webhook in the audit logs data based on webhook ID
4100
- # @note This only uses data given by the audit logs request
4101
- # @param id [#resolve_id] The webhook ID to look for
4102
- def webhook(id)
4103
- @webhooks[id.resolve_id]
4104
- end
4105
-
4106
- # Process user objects given by the request
4107
- # @note For internal use only
4108
- # @!visibility private
4109
- def process_users(users)
4110
- users.each do |element|
4111
- user = User.new(element, @bot)
4112
- @users[user.id] = user
4113
- end
4114
- end
4115
-
4116
- # Process webhook objects given by the request
4117
- # @note For internal use only
4118
- # @!visibility private
4119
- def process_webhooks(webhooks)
4120
- webhooks.each do |element|
4121
- webhook = Webhook.new(element, @bot)
4122
- @webhooks[webhook.id] = webhook
4123
- end
4124
- end
4125
-
4126
- # Find the type of target by it's action number
4127
- # @note For internal use only
4128
- # @!visibility private
4129
- def self.target_type_for(action)
4130
- case action
4131
- when 1..9 then :server
4132
- when 10..19 then :channel
4133
- when 20..29 then :user
4134
- when 30..39 then :role
4135
- when 40..49 then :invite
4136
- when 50..59 then :webhook
4137
- when 60..69 then :emoji
4138
- when 70..79 then :message
4139
- else :unknown
4140
- end
4141
- end
4142
-
4143
- # Find the type of action by its action number
4144
- # @note For internal use only
4145
- # @!visibility private
4146
- def self.action_type_for(action)
4147
- action = Actions[action]
4148
- return :create if %i[channel_create channel_overwrite_create member_ban_add role_create invite_create webhook_create emoji_create].include?(action)
4149
- return :delete if %i[channel_delete channel_overwrite_delete member_kick member_prune member_ban_remove role_delete invite_delete webhook_delete emoji_delete message_delete].include?(action)
4150
- return :update if %i[server_update channel_update channel_overwrite_update member_update member_role_update role_update invite_update webhook_update emoji_update].include?(action)
4151
- :unknown
4152
- end
4153
- end
4154
-
4155
- # A colour (red, green and blue values). Used for role colours. If you prefer the American spelling, the alias
4156
- # {ColorRGB} is also available.
4157
- class ColourRGB
4158
- # @return [Integer] the red part of this colour (0-255).
4159
- attr_reader :red
4160
-
4161
- # @return [Integer] the green part of this colour (0-255).
4162
- attr_reader :green
4163
-
4164
- # @return [Integer] the blue part of this colour (0-255).
4165
- attr_reader :blue
4166
-
4167
- # @return [Integer] the colour's RGB values combined into one integer.
4168
- attr_reader :combined
4169
- alias_method :to_i, :combined
4170
-
4171
- # Make a new colour from the combined value.
4172
- # @param combined [Integer, String] The colour's RGB values combined into one integer or a hexadecimal string
4173
- # @example Initialize a with a base 10 integer
4174
- # ColourRGB.new(7506394) #=> ColourRGB
4175
- # ColourRGB.new(0x7289da) #=> ColourRGB
4176
- # @example Initialize a with a hexadecimal string
4177
- # ColourRGB.new('7289da') #=> ColourRGB
4178
- def initialize(combined)
4179
- @combined = combined.is_a?(String) ? combined.to_i(16) : combined
4180
- @red = (@combined >> 16) & 0xFF
4181
- @green = (@combined >> 8) & 0xFF
4182
- @blue = @combined & 0xFF
4183
- end
4184
-
4185
- # @return [String] the colour as a hexadecimal.
4186
- def hex
4187
- @combined.to_s(16)
4188
- end
4189
- alias_method :hexadecimal, :hex
4190
- end
4191
-
4192
- # Alias for the class {ColourRGB}
4193
- ColorRGB = ColourRGB
4194
- end
20
+ require 'discordrb/data/activity'
21
+ require 'discordrb/data/application'
22
+ require 'discordrb/data/user'
23
+ require 'discordrb/data/voice_state'
24
+ require 'discordrb/data/voice_region'
25
+ require 'discordrb/data/member'
26
+ require 'discordrb/data/recipient'
27
+ require 'discordrb/data/profile'
28
+ require 'discordrb/data/role'
29
+ require 'discordrb/data/invite'
30
+ require 'discordrb/data/overwrite'
31
+ require 'discordrb/data/channel'
32
+ require 'discordrb/data/embed'
33
+ require 'discordrb/data/attachment'
34
+ require 'discordrb/data/message'
35
+ require 'discordrb/data/reaction'
36
+ require 'discordrb/data/emoji'
37
+ require 'discordrb/data/integration'
38
+ require 'discordrb/data/server'
39
+ require 'discordrb/data/webhook'
40
+ require 'discordrb/data/audit_logs'
41
+ require 'discordrb/data/interaction'
42
+ require 'discordrb/data/component'