discordrb 3.2.1 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of discordrb might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.gitignore +4 -0
- data/.rubocop.yml +3 -3
- data/.travis.yml +28 -3
- data/.yardopts +1 -1
- data/CHANGELOG.md +555 -144
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +0 -4
- data/README.md +86 -15
- data/Rakefile +2 -2
- data/bin/travis_build_docs.sh +17 -0
- data/discordrb-webhooks.gemspec +2 -1
- data/discordrb.gemspec +12 -5
- data/lib/discordrb.rb +2 -2
- data/lib/discordrb/api.rb +94 -25
- data/lib/discordrb/api/channel.rb +53 -17
- data/lib/discordrb/api/invite.rb +7 -4
- data/lib/discordrb/api/server.rb +173 -36
- data/lib/discordrb/api/user.rb +18 -4
- data/lib/discordrb/api/webhook.rb +83 -0
- data/lib/discordrb/await.rb +1 -1
- data/lib/discordrb/bot.rb +191 -102
- data/lib/discordrb/cache.rb +39 -9
- data/lib/discordrb/commands/command_bot.rb +79 -24
- data/lib/discordrb/commands/container.rb +16 -2
- data/lib/discordrb/commands/parser.rb +46 -7
- data/lib/discordrb/commands/rate_limiter.rb +8 -6
- data/lib/discordrb/container.rb +51 -7
- data/lib/discordrb/data.rb +1729 -286
- data/lib/discordrb/errors.rb +34 -1
- data/lib/discordrb/events/generic.rb +1 -1
- data/lib/discordrb/events/guilds.rb +1 -0
- data/lib/discordrb/events/message.rb +18 -12
- data/lib/discordrb/events/presence.rb +7 -2
- data/lib/discordrb/events/reactions.rb +13 -4
- data/lib/discordrb/events/roles.rb +7 -6
- data/lib/discordrb/events/typing.rb +1 -1
- data/lib/discordrb/events/webhooks.rb +61 -0
- data/lib/discordrb/gateway.rb +85 -32
- data/lib/discordrb/light.rb +1 -1
- data/lib/discordrb/logger.rb +8 -7
- data/lib/discordrb/permissions.rb +41 -4
- data/lib/discordrb/version.rb +1 -1
- data/lib/discordrb/voice/encoder.rb +10 -8
- data/lib/discordrb/voice/voice_bot.rb +4 -4
- data/lib/discordrb/websocket.rb +2 -2
- metadata +59 -14
data/lib/discordrb/container.rb
CHANGED
@@ -37,7 +37,7 @@ module Discordrb
|
|
37
37
|
register_event(MessageEvent, attributes, block)
|
38
38
|
end
|
39
39
|
|
40
|
-
# This **event** is raised when the READY packet is received, i.
|
40
|
+
# This **event** is raised when the READY packet is received, i.e. servers and channels have finished
|
41
41
|
# initialization. It's the recommended way to do things when the bot has finished starting up.
|
42
42
|
# @param attributes [Hash] Event attributes, none in this particular case
|
43
43
|
# @yield The block is executed when the event is raised.
|
@@ -237,7 +237,8 @@ module Discordrb
|
|
237
237
|
register_event(ChannelRecipientRemoveEvent, attributes, block)
|
238
238
|
end
|
239
239
|
|
240
|
-
# This **event** is raised when a user's voice state changes.
|
240
|
+
# This **event** is raised when a user's voice state changes. This includes when a user joins, leaves, or
|
241
|
+
# moves between voice channels, as well as their mute and deaf status for themselves and on the server.
|
241
242
|
# @param attributes [Hash] The event's attributes.
|
242
243
|
# @option attributes [String, Integer, User] :from Matches the user that sent the message.
|
243
244
|
# @option attributes [String, Integer, Channel] :channel Matches the voice channel the user has joined.
|
@@ -263,7 +264,8 @@ module Discordrb
|
|
263
264
|
register_event(ServerMemberAddEvent, attributes, block)
|
264
265
|
end
|
265
266
|
|
266
|
-
# This **event** is raised when a member update happens.
|
267
|
+
# This **event** is raised when a member update happens. This includes when a members nickname
|
268
|
+
# or roles are updated.
|
267
269
|
# @param attributes [Hash] The event's attributes.
|
268
270
|
# @option attributes [String] :username Matches the username of the updated user.
|
269
271
|
# @yield The block is executed when the event is raised.
|
@@ -305,9 +307,8 @@ module Discordrb
|
|
305
307
|
register_event(UserUnbanEvent, attributes, block)
|
306
308
|
end
|
307
309
|
|
308
|
-
# This **event** is raised when a server is created respective to the bot, i.
|
309
|
-
# a new one itself.
|
310
|
-
# things the bot itself does, but one can never know.
|
310
|
+
# This **event** is raised when a server is created respective to the bot, i.e. the bot joins a server or creates
|
311
|
+
# a new one itself.
|
311
312
|
# @param attributes [Hash] The event's attributes.
|
312
313
|
# @option attributes [String, Integer, Server] :server Matches the server that was created.
|
313
314
|
# @yield The block is executed when the event is raised.
|
@@ -385,6 +386,48 @@ module Discordrb
|
|
385
386
|
register_event(ServerEmojiUpdateEvent, attributes, block)
|
386
387
|
end
|
387
388
|
|
389
|
+
# This **event** is raised when a role is created.
|
390
|
+
# @param attributes [Hash] The event's attributes.
|
391
|
+
# @option attributes [String] :name Matches the role name.
|
392
|
+
# @yield The block is executed when the event is raised.
|
393
|
+
# @yieldparam event [ServerRoleCreateEvent] The event that was raised.
|
394
|
+
# @return [ServerRoleCreateEventHandler] the event handler that was registered.
|
395
|
+
def server_role_create(attributes = {}, &block)
|
396
|
+
register_event(ServerRoleCreateEvent, attributes, block)
|
397
|
+
end
|
398
|
+
|
399
|
+
# This **event** is raised when a role is deleted.
|
400
|
+
# @param attributes [Hash] The event's attributes.
|
401
|
+
# @option attributes [#resolve_id] :id Matches the role id.
|
402
|
+
# @yield The block is executed when the event is raised.
|
403
|
+
# @yieldparam event [ServerRoleDeleteEvent] The event that was raised.
|
404
|
+
# @return [ServerRoleDeleteEventHandler] the event handler that was registered.
|
405
|
+
def server_role_delete(attributes = {}, &block)
|
406
|
+
register_event(ServerRoleDeleteEvent, attributes, block)
|
407
|
+
end
|
408
|
+
|
409
|
+
# This **event** is raised when a role is updated.
|
410
|
+
# @param attributes [Hash] The event's attributes.
|
411
|
+
# @option attributes [String] :name Matches the role name.
|
412
|
+
# @yield The block is executed when the event is raised.
|
413
|
+
# @yieldparam event [ServerRoleUpdateEvent] The event that was raised.
|
414
|
+
# @return [ServerRoleUpdateEventHandler] the event handler that was registered.
|
415
|
+
def server_role_update(attributes = {}, &block)
|
416
|
+
register_event(ServerRoleUpdateEvent, attributes, block)
|
417
|
+
end
|
418
|
+
|
419
|
+
# This **event** is raised when a webhook is updated.
|
420
|
+
# @param attributes [Hash] The event's attributes.
|
421
|
+
# @option attributes [String, Integer, Server] :server Matches the server by name, id or instance.
|
422
|
+
# @option attributes [String, Integer, Channel] :channel Matches the channel by name, id or instance.
|
423
|
+
# @option attribute [String, Integer, Webhook] :webhook Matches the webhook by name, id or instance.
|
424
|
+
# @yield The block is executed when the event is raised.
|
425
|
+
# @yieldparam event [WebhookUpdateEvent] The event that was raised.
|
426
|
+
# @return [WebhookUpdateEventHandler] the event handler that was registered.
|
427
|
+
def webhook_update(attributes = {}, &block)
|
428
|
+
register_event(WebhookUpdateEvent, attributes, block)
|
429
|
+
end
|
430
|
+
|
388
431
|
# This **event** is raised when an {Await} is triggered. It provides an easy way to execute code
|
389
432
|
# on an await without having to rely on the await's block.
|
390
433
|
# @param attributes [Hash] The event's attributes.
|
@@ -460,6 +503,7 @@ module Discordrb
|
|
460
503
|
def add_handler(handler)
|
461
504
|
clazz = EventContainer.event_class(handler.class)
|
462
505
|
@event_handlers ||= {}
|
506
|
+
@event_handlers[clazz] ||= []
|
463
507
|
@event_handlers[clazz] << handler
|
464
508
|
end
|
465
509
|
|
@@ -487,7 +531,7 @@ module Discordrb
|
|
487
531
|
# Returns the event class for a handler class type
|
488
532
|
# @see #handler_class
|
489
533
|
# @param handler_class [Class] The handler type
|
490
|
-
# @return [Class, nil] the event type, or nil if the handler_class isn't a handler class (i.
|
534
|
+
# @return [Class, nil] the event type, or nil if the handler_class isn't a handler class (i.e. ends with Handler)
|
491
535
|
def self.event_class(handler_class)
|
492
536
|
class_name = handler_class.to_s
|
493
537
|
return nil unless class_name.end_with? 'Handler'
|
data/lib/discordrb/data.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
# These classes hold relevant Discord data, such as messages or channels.
|
4
4
|
|
5
|
-
require 'ostruct'
|
6
5
|
require 'discordrb/permissions'
|
7
6
|
require 'discordrb/errors'
|
8
7
|
require 'discordrb/api'
|
@@ -10,6 +9,7 @@ require 'discordrb/api/channel'
|
|
10
9
|
require 'discordrb/api/server'
|
11
10
|
require 'discordrb/api/invite'
|
12
11
|
require 'discordrb/api/user'
|
12
|
+
require 'discordrb/api/webhook'
|
13
13
|
require 'discordrb/webhooks/embeds'
|
14
14
|
require 'time'
|
15
15
|
require 'base64'
|
@@ -71,12 +71,15 @@ module Discordrb
|
|
71
71
|
# @return [Integer] the ID which uniquely identifies this object across Discord.
|
72
72
|
attr_reader :id
|
73
73
|
alias_method :resolve_id, :id
|
74
|
+
alias_method :hash, :id
|
74
75
|
|
75
76
|
# ID based comparison
|
76
77
|
def ==(other)
|
77
78
|
Discordrb.id_compare(@id, other)
|
78
79
|
end
|
79
80
|
|
81
|
+
alias_method :eql?, :==
|
82
|
+
|
80
83
|
# Estimates the time this object was generated on based on the beginning of the ID. This is fairly accurate but
|
81
84
|
# shouldn't be relied on as Discord might change its algorithm at any time
|
82
85
|
# @return [Time] when this object was created at
|
@@ -125,16 +128,18 @@ module Discordrb
|
|
125
128
|
"<@#{@id}>"
|
126
129
|
end
|
127
130
|
|
128
|
-
# Utility function to get Discord's distinct representation of a user, i.
|
131
|
+
# Utility function to get Discord's distinct representation of a user, i.e. username + discriminator
|
129
132
|
# @return [String] distinct representation of user
|
130
133
|
def distinct
|
131
134
|
"#{@username}##{@discriminator}"
|
132
135
|
end
|
133
136
|
|
134
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.
|
135
139
|
# @return [String] the URL to the avatar image.
|
136
|
-
def avatar_url
|
137
|
-
API::User.
|
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)
|
138
143
|
end
|
139
144
|
end
|
140
145
|
|
@@ -196,6 +201,8 @@ module Discordrb
|
|
196
201
|
# @param file [File] The file to send to the user
|
197
202
|
# @param caption [String] The caption of the file being sent
|
198
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'))
|
199
206
|
def send_file(file, caption = nil)
|
200
207
|
pm.send_file(file, caption: caption)
|
201
208
|
end
|
@@ -231,6 +238,13 @@ module Discordrb
|
|
231
238
|
@bot.add_await(key, Discordrb::Events::MessageEvent, { from: @id }.merge(attributes), &block)
|
232
239
|
end
|
233
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
|
+
|
234
248
|
# Gets the member this user is on a server
|
235
249
|
# @param server [Server] The server to get the member for
|
236
250
|
# @return [Member] this user as a member on a particular server
|
@@ -250,7 +264,7 @@ module Discordrb
|
|
250
264
|
@discriminator == Message::ZERO_DISCRIM
|
251
265
|
end
|
252
266
|
|
253
|
-
[
|
267
|
+
%i[offline idle online].each do |e|
|
254
268
|
define_method(e.to_s + '?') do
|
255
269
|
@status.to_sym == e
|
256
270
|
end
|
@@ -272,14 +286,14 @@ module Discordrb
|
|
272
286
|
# @return [String] the application description
|
273
287
|
attr_reader :description
|
274
288
|
|
275
|
-
# @return [Array<String>] the
|
289
|
+
# @return [Array<String>] the application's origins permitted to use RPC
|
276
290
|
attr_reader :rpc_origins
|
277
291
|
|
278
292
|
# @return [Integer]
|
279
293
|
attr_reader :flags
|
280
294
|
|
281
295
|
# Gets the user object of the owner. May be limited to username, discriminator,
|
282
|
-
# ID and avatar if the bot cannot reach the owner.
|
296
|
+
# ID, and avatar if the bot cannot reach the owner.
|
283
297
|
# @return [User] the user object of the owner
|
284
298
|
attr_reader :owner
|
285
299
|
|
@@ -296,7 +310,7 @@ module Discordrb
|
|
296
310
|
end
|
297
311
|
|
298
312
|
# Utility function to get a application's icon URL.
|
299
|
-
# @return [String, nil] the URL
|
313
|
+
# @return [String, nil] the URL of the icon image (nil if no image is set).
|
300
314
|
def icon_url
|
301
315
|
return nil if @icon_id.nil?
|
302
316
|
API.app_icon_url(@id, @icon_id)
|
@@ -313,7 +327,7 @@ module Discordrb
|
|
313
327
|
# @return [Time] when this member joined the server.
|
314
328
|
attr_reader :joined_at
|
315
329
|
|
316
|
-
# @return [String, nil] the nickname this member has, or nil if it has none.
|
330
|
+
# @return [String, nil] the nickname this member has, or `nil` if it has none.
|
317
331
|
attr_reader :nick
|
318
332
|
alias_method :nickname, :nick
|
319
333
|
|
@@ -348,7 +362,7 @@ module Discordrb
|
|
348
362
|
defined_permission?(action, channel)
|
349
363
|
end
|
350
364
|
|
351
|
-
# Checks whether this user has a particular permission defined (i.
|
365
|
+
# Checks whether this user has a particular permission defined (i.e. not implicit, through for example
|
352
366
|
# Manage Roles)
|
353
367
|
# @param action [Symbol] The permission that should be checked. See also {Permissions::Flags} for a list.
|
354
368
|
# @param channel [Channel, nil] If channel overrides should be checked too, this channel specifies where the overrides should be checked.
|
@@ -380,10 +394,12 @@ module Discordrb
|
|
380
394
|
private
|
381
395
|
|
382
396
|
def defined_role_permission?(action, channel)
|
397
|
+
roles_to_check = [@server.everyone_role] + @roles
|
398
|
+
|
383
399
|
# For each role, check if
|
384
400
|
# (1) the channel explicitly allows or permits an action for the role and
|
385
401
|
# (2) if the user is allowed to do the action if the channel doesn't specify
|
386
|
-
|
402
|
+
roles_to_check.reduce(false) do |can_act, role|
|
387
403
|
# Get the override defined for the role on the channel
|
388
404
|
channel_allow = permission_overwrite(action, channel, role.id)
|
389
405
|
can_act = if channel_allow
|
@@ -453,7 +469,47 @@ module Discordrb
|
|
453
469
|
end
|
454
470
|
end
|
455
471
|
|
456
|
-
#
|
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
|
457
513
|
|
458
514
|
# A member is a user on a server. It differs from regular users in that it has roles, voice statuses and things like
|
459
515
|
# that.
|
@@ -520,48 +576,92 @@ module Discordrb
|
|
520
576
|
@roles.any? { |e| e.id == role }
|
521
577
|
end
|
522
578
|
|
579
|
+
# @see Member#set_roles
|
580
|
+
def roles=(role)
|
581
|
+
set_roles(role)
|
582
|
+
end
|
583
|
+
|
523
584
|
# Bulk sets a member's roles.
|
524
585
|
# @param role [Role, Array<Role>] The role(s) to set.
|
525
|
-
|
586
|
+
# @param reason [String] The reason the user's roles are being changed.
|
587
|
+
def set_roles(role, reason = nil)
|
526
588
|
role_ids = role_id_array(role)
|
527
|
-
API::Server.update_member(@bot.token, @server.id, @user.id, roles: role_ids)
|
589
|
+
API::Server.update_member(@bot.token, @server.id, @user.id, roles: role_ids, reason: reason)
|
528
590
|
end
|
529
591
|
|
530
592
|
# Adds and removes roles from a member.
|
531
593
|
# @param add [Role, Array<Role>] The role(s) to add.
|
532
594
|
# @param remove [Role, Array<Role>] The role(s) to remove.
|
595
|
+
# @param reason [String] The reason the user's roles are being changed.
|
533
596
|
# @example Remove the 'Member' role from a user, and add the 'Muted' role to them.
|
534
597
|
# to_add = server.roles.find {|role| role.name == 'Muted'}
|
535
598
|
# to_remove = server.roles.find {|role| role.name == 'Member'}
|
536
599
|
# member.modify_roles(to_add, to_remove)
|
537
|
-
def modify_roles(add, remove)
|
600
|
+
def modify_roles(add, remove, reason = nil)
|
538
601
|
add_role_ids = role_id_array(add)
|
539
602
|
remove_role_ids = role_id_array(remove)
|
540
603
|
old_role_ids = @roles.map(&:id)
|
541
604
|
new_role_ids = (old_role_ids - remove_role_ids + add_role_ids).uniq
|
542
605
|
|
543
|
-
API::Server.update_member(@bot.token, @server.id, @user.id, roles: new_role_ids)
|
606
|
+
API::Server.update_member(@bot.token, @server.id, @user.id, roles: new_role_ids, reason: reason)
|
544
607
|
end
|
545
608
|
|
546
609
|
# Adds one or more roles to this member.
|
547
|
-
# @param role [Role, Array<Role
|
548
|
-
|
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)
|
549
613
|
role_ids = role_id_array(role)
|
550
|
-
old_role_ids = @roles.map(&:id)
|
551
|
-
new_role_ids = (old_role_ids + role_ids).uniq
|
552
614
|
|
553
|
-
|
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
|
554
622
|
end
|
555
623
|
|
556
624
|
# Removes one or more roles from this member.
|
557
625
|
# @param role [Role, Array<Role>] The role(s) to remove.
|
558
|
-
|
559
|
-
|
626
|
+
# @param reason [String] The reason the user's roles are being changed.
|
627
|
+
def remove_role(role, reason = nil)
|
560
628
|
role_ids = role_id_array(role)
|
561
|
-
new_role_ids = old_role_ids.reject { |i| role_ids.include?(i) }
|
562
629
|
|
563
|
-
|
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
|
564
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
|
565
665
|
|
566
666
|
# Server deafens this member.
|
567
667
|
def server_deafen
|
@@ -583,21 +683,29 @@ module Discordrb
|
|
583
683
|
API::Server.update_member(@bot.token, @server.id, @user.id, mute: false)
|
584
684
|
end
|
585
685
|
|
686
|
+
# @see Member#set_nick
|
687
|
+
def nick=(nick)
|
688
|
+
set_nick(nick)
|
689
|
+
end
|
690
|
+
|
691
|
+
alias_method :nickname=, :nick=
|
692
|
+
|
586
693
|
# Sets or resets this member's nickname. Requires the Change Nickname permission for the bot itself and Manage
|
587
694
|
# Nicknames for other users.
|
588
695
|
# @param nick [String, nil] The string to set the nickname to, or nil if it should be reset.
|
589
|
-
|
696
|
+
# @param reason [String] The reason the user's nickname is being changed.
|
697
|
+
def set_nick(nick, reason = nil)
|
590
698
|
# Discord uses the empty string to signify 'no nickname' so we convert nil into that
|
591
699
|
nick ||= ''
|
592
700
|
|
593
701
|
if @user.current_bot?
|
594
|
-
API::User.change_own_nickname(@bot.token, @server.id, nick)
|
702
|
+
API::User.change_own_nickname(@bot.token, @server.id, nick, reason)
|
595
703
|
else
|
596
|
-
API::Server.update_member(@bot.token, @server.id, @user.id, nick: nick)
|
704
|
+
API::Server.update_member(@bot.token, @server.id, @user.id, nick: nick, reason: nil)
|
597
705
|
end
|
598
706
|
end
|
599
707
|
|
600
|
-
alias_method :
|
708
|
+
alias_method :set_nickname, :set_nick
|
601
709
|
|
602
710
|
# @return [String] the name the user displays as (nickname if they have one, username otherwise)
|
603
711
|
def display_name
|
@@ -607,9 +715,13 @@ module Discordrb
|
|
607
715
|
# Update this member's roles
|
608
716
|
# @note For internal use only.
|
609
717
|
# @!visibility private
|
610
|
-
def update_roles(
|
611
|
-
@roles =
|
612
|
-
|
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
|
613
725
|
end
|
614
726
|
end
|
615
727
|
|
@@ -699,7 +811,7 @@ module Discordrb
|
|
699
811
|
|
700
812
|
# Changes the bot's avatar.
|
701
813
|
# @param avatar [String, #read] A JPG file to be used as the avatar, either
|
702
|
-
# something readable (e.
|
814
|
+
# something readable (e.g. File Object) or as a data URL.
|
703
815
|
def avatar=(avatar)
|
704
816
|
if avatar.respond_to? :read
|
705
817
|
# Set the file to binary mode if supported, so we don't get problems with Windows
|
@@ -778,9 +890,16 @@ module Discordrb
|
|
778
890
|
# @return [String] this role's name ("new role" if it hasn't been changed)
|
779
891
|
attr_reader :name
|
780
892
|
|
893
|
+
# @return [Server] the server this role belongs to
|
894
|
+
attr_reader :server
|
895
|
+
|
781
896
|
# @return [true, false] whether or not this role should be displayed separately from other users
|
782
897
|
attr_reader :hoist
|
783
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
|
+
|
784
903
|
# @return [true, false] whether this role can be mentioned using a role mention
|
785
904
|
attr_reader :mentionable
|
786
905
|
alias_method :mentionable?, :mentionable
|
@@ -824,6 +943,7 @@ module Discordrb
|
|
824
943
|
|
825
944
|
@hoist = data['hoist']
|
826
945
|
@mentionable = data['mentionable']
|
946
|
+
@managed = data['managed']
|
827
947
|
|
828
948
|
@colour = ColourRGB.new(data['color'])
|
829
949
|
end
|
@@ -836,7 +956,7 @@ module Discordrb
|
|
836
956
|
# @return [Array<Member>] an array of members who have this role.
|
837
957
|
# @note This requests a member chunk if it hasn't for the server before, which may be slow initially
|
838
958
|
def members
|
839
|
-
@server.members.select { |m| m.role?
|
959
|
+
@server.members.select { |m| m.role? self }
|
840
960
|
end
|
841
961
|
|
842
962
|
alias_method :users, :members
|
@@ -850,6 +970,7 @@ module Discordrb
|
|
850
970
|
@hoist = other.hoist
|
851
971
|
@colour = other.colour
|
852
972
|
@position = other.position
|
973
|
+
@managed = other.managed
|
853
974
|
end
|
854
975
|
|
855
976
|
# Updates the data cache from a hash containing data
|
@@ -903,9 +1024,29 @@ module Discordrb
|
|
903
1024
|
@permissions.bits = packed if update_perms
|
904
1025
|
end
|
905
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
|
+
|
906
1046
|
# Deletes this role. This cannot be undone without recreating the role!
|
907
|
-
|
908
|
-
|
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)
|
909
1050
|
@server.delete_role(@id)
|
910
1051
|
end
|
911
1052
|
|
@@ -984,7 +1125,7 @@ module Discordrb
|
|
984
1125
|
attr_reader :inviter
|
985
1126
|
alias_method :user, :inviter
|
986
1127
|
|
987
|
-
# @return [true, false] whether or not this invite
|
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.
|
988
1129
|
attr_reader :temporary
|
989
1130
|
alias_method :temporary?, :temporary
|
990
1131
|
|
@@ -995,6 +1136,20 @@ module Discordrb
|
|
995
1136
|
# @return [String] this invite's code
|
996
1137
|
attr_reader :code
|
997
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
|
+
|
998
1153
|
# @!visibility private
|
999
1154
|
def initialize(data, bot)
|
1000
1155
|
@bot = bot
|
@@ -1005,6 +1160,10 @@ module Discordrb
|
|
1005
1160
|
@inviter = data['inviter'] ? (@bot.user(data['inviter']['id'].to_i) || User.new(data['inviter'], bot)) : nil
|
1006
1161
|
@temporary = data['temporary']
|
1007
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']
|
1008
1167
|
|
1009
1168
|
@code = data['code']
|
1010
1169
|
end
|
@@ -1015,15 +1174,16 @@ module Discordrb
|
|
1015
1174
|
end
|
1016
1175
|
|
1017
1176
|
# Deletes this invite
|
1018
|
-
|
1019
|
-
|
1177
|
+
# @param reason [String] The reason the invite is being deleted.
|
1178
|
+
def delete(reason = nil)
|
1179
|
+
API::Invite.delete(@bot.token, @code, reason)
|
1020
1180
|
end
|
1021
1181
|
|
1022
1182
|
alias_method :revoke, :delete
|
1023
1183
|
|
1024
1184
|
# The inspect method is overwritten to give more useful output
|
1025
1185
|
def inspect
|
1026
|
-
"<Invite code=#{@code} channel=#{@channel} uses=#{@uses} temporary=#{@temporary} revoked=#{@revoked}>"
|
1186
|
+
"<Invite code=#{@code} channel=#{@channel} uses=#{@uses} temporary=#{@temporary} revoked=#{@revoked} created_at=#{@created_at} max_age=#{@max_age}>"
|
1027
1187
|
end
|
1028
1188
|
|
1029
1189
|
# Creates an invite URL.
|
@@ -1032,16 +1192,126 @@ module Discordrb
|
|
1032
1192
|
end
|
1033
1193
|
end
|
1034
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
|
+
|
1035
1293
|
# A Discord channel, including data like the topic
|
1036
1294
|
class Channel
|
1037
1295
|
include IDObject
|
1038
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
|
+
|
1039
1306
|
# @return [String] this channel's name.
|
1040
1307
|
attr_reader :name
|
1041
1308
|
|
1042
1309
|
# @return [Server, nil] the server this channel is on. If this channel is a PM channel, it will be nil.
|
1043
1310
|
attr_reader :server
|
1044
1311
|
|
1312
|
+
# @return [Integer, nil] the ID of the parent channel, if this channel is inside a cateogry
|
1313
|
+
attr_reader :parent_id
|
1314
|
+
|
1045
1315
|
# @return [Integer] the type of this channel (0: text, 1: private, 2: voice, 3: group)
|
1046
1316
|
attr_reader :type
|
1047
1317
|
|
@@ -1064,11 +1334,13 @@ module Discordrb
|
|
1064
1334
|
# @return [Integer] the channel's position on the channel list
|
1065
1335
|
attr_reader :position
|
1066
1336
|
|
1067
|
-
#
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
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
|
1072
1344
|
|
1073
1345
|
# @return [true, false] whether or not this channel is a PM or group channel.
|
1074
1346
|
def private?
|
@@ -1088,7 +1360,7 @@ module Discordrb
|
|
1088
1360
|
# @!visibility private
|
1089
1361
|
def initialize(data, bot, server = nil)
|
1090
1362
|
@bot = bot
|
1091
|
-
# data is
|
1363
|
+
# data is sometimes a Hash and other times an array of Hashes, you only want the last one if it's an array
|
1092
1364
|
data = data[-1] if data.is_a?(Array)
|
1093
1365
|
|
1094
1366
|
@id = data['id'].to_i
|
@@ -1097,6 +1369,7 @@ module Discordrb
|
|
1097
1369
|
@bitrate = data['bitrate']
|
1098
1370
|
@user_limit = data['user_limit']
|
1099
1371
|
@position = data['position']
|
1372
|
+
@parent_id = data['parent_id'].to_i if data['parent_id']
|
1100
1373
|
|
1101
1374
|
if private?
|
1102
1375
|
@recipients = []
|
@@ -1121,17 +1394,10 @@ module Discordrb
|
|
1121
1394
|
end
|
1122
1395
|
end
|
1123
1396
|
|
1124
|
-
|
1125
|
-
@
|
1126
|
-
|
1127
|
-
data['permission_overwrites']
|
1128
|
-
role_id = element['id'].to_i
|
1129
|
-
deny = Permissions.new(element['deny'])
|
1130
|
-
allow = Permissions.new(element['allow'])
|
1131
|
-
@permission_overwrites[role_id] = OpenStruct.new
|
1132
|
-
@permission_overwrites[role_id].deny = deny
|
1133
|
-
@permission_overwrites[role_id].allow = allow
|
1134
|
-
end
|
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'])
|
1135
1401
|
end
|
1136
1402
|
|
1137
1403
|
# @return [true, false] whether or not this channel is a text channel
|
@@ -1154,6 +1420,194 @@ module Discordrb
|
|
1154
1420
|
@type == 3
|
1155
1421
|
end
|
1156
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
|
+
|
1157
1611
|
# Sends a message to this channel.
|
1158
1612
|
# @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
|
1159
1613
|
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
@@ -1207,6 +1661,8 @@ module Discordrb
|
|
1207
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)
|
1208
1662
|
# @param caption [string] The caption for the file.
|
1209
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'))
|
1210
1666
|
def send_file(file, caption: nil, tts: false)
|
1211
1667
|
@bot.send_file(@id, file, caption: caption, tts: tts)
|
1212
1668
|
end
|
@@ -1218,39 +1674,36 @@ module Discordrb
|
|
1218
1674
|
end
|
1219
1675
|
|
1220
1676
|
# Permanently deletes this channel
|
1221
|
-
|
1222
|
-
|
1677
|
+
# @param reason [String] The reason the for the channel deletion.
|
1678
|
+
def delete(reason = nil)
|
1679
|
+
API::Channel.delete(@bot.token, @id, reason)
|
1223
1680
|
end
|
1224
1681
|
|
1225
1682
|
# Sets this channel's name. The name must be alphanumeric with dashes, unless this is a voice channel (then there are no limitations)
|
1226
1683
|
# @param name [String] The new name.
|
1227
1684
|
def name=(name)
|
1228
|
-
|
1229
|
-
update_channel_data
|
1685
|
+
update_channel_data(name: name)
|
1230
1686
|
end
|
1231
1687
|
|
1232
1688
|
# Sets this channel's topic.
|
1233
1689
|
# @param topic [String] The new topic.
|
1234
1690
|
def topic=(topic)
|
1235
1691
|
raise 'Tried to set topic on voice channel' if voice?
|
1236
|
-
|
1237
|
-
update_channel_data
|
1692
|
+
update_channel_data(topic: topic)
|
1238
1693
|
end
|
1239
1694
|
|
1240
1695
|
# Sets this channel's bitrate.
|
1241
1696
|
# @param bitrate [Integer] The new bitrate (in bps). Number has to be between 8000-96000 (128000 for VIP servers)
|
1242
1697
|
def bitrate=(bitrate)
|
1243
1698
|
raise 'Tried to set bitrate on text channel' if text?
|
1244
|
-
|
1245
|
-
update_channel_data
|
1699
|
+
update_channel_data(bitrate: bitrate)
|
1246
1700
|
end
|
1247
1701
|
|
1248
1702
|
# Sets this channel's user limit.
|
1249
1703
|
# @param limit [Integer] The new user limit. `0` for unlimited, has to be a number between 0-99
|
1250
1704
|
def user_limit=(limit)
|
1251
1705
|
raise 'Tried to set user_limit on text channel' if text?
|
1252
|
-
|
1253
|
-
update_channel_data
|
1706
|
+
update_channel_data(user_limit: limit)
|
1254
1707
|
end
|
1255
1708
|
|
1256
1709
|
alias_method :limit=, :user_limit=
|
@@ -1258,47 +1711,48 @@ module Discordrb
|
|
1258
1711
|
# Sets this channel's position in the list.
|
1259
1712
|
# @param position [Integer] The new position.
|
1260
1713
|
def position=(position)
|
1261
|
-
|
1262
|
-
update_channel_data
|
1714
|
+
update_channel_data(position: position)
|
1263
1715
|
end
|
1264
1716
|
|
1265
1717
|
# Defines a permission overwrite for this channel that sets the specified thing to the specified allow and deny
|
1266
1718
|
# permission sets, or change an existing one.
|
1267
|
-
# @
|
1268
|
-
#
|
1269
|
-
#
|
1270
|
-
# @
|
1271
|
-
#
|
1272
|
-
#
|
1273
|
-
#
|
1274
|
-
#
|
1275
|
-
#
|
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
|
1276
1733
|
#
|
1277
|
-
#
|
1278
|
-
#
|
1734
|
+
# deny = Discordrb::Permissions.new
|
1735
|
+
# deny.can_create_instant_invite = true
|
1279
1736
|
#
|
1280
|
-
#
|
1281
|
-
def define_overwrite(thing, allow, deny)
|
1282
|
-
|
1283
|
-
|
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
|
1284
1742
|
|
1285
|
-
|
1286
|
-
|
1287
|
-
elsif thing.is_a? Role
|
1288
|
-
:role
|
1289
|
-
else
|
1290
|
-
raise ArgumentError, '`thing` in define_overwrite needs to be a kind of User (User, Member, Recipient, Profile) or a Role!'
|
1291
|
-
end
|
1743
|
+
thing = Overwrite.new thing, allow: allow_bits, deny: deny_bits
|
1744
|
+
end
|
1292
1745
|
|
1293
|
-
API::Channel.update_permission(@bot.token, @id, thing.id,
|
1746
|
+
API::Channel.update_permission(@bot.token, @id, thing.id, thing.allow.bits, thing.deny.bits, thing.type, reason)
|
1294
1747
|
end
|
1295
1748
|
|
1296
1749
|
# Deletes a permission overwrite for this channel
|
1297
1750
|
# @param target [Member, User, Role, Profile, Recipient, #resolve_id] What permission overwrite to delete
|
1298
|
-
|
1751
|
+
# @param reason [String] The reason the for the overwrite deletion.
|
1752
|
+
def delete_overwrite(target, reason = nil)
|
1299
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)
|
1300
1754
|
|
1301
|
-
API::Channel.delete_permission(@bot.token, @id, target.resolve_id)
|
1755
|
+
API::Channel.delete_permission(@bot.token, @id, target.resolve_id, reason)
|
1302
1756
|
end
|
1303
1757
|
|
1304
1758
|
# Updates the cached data from another channel.
|
@@ -1313,6 +1767,9 @@ module Discordrb
|
|
1313
1767
|
@bitrate = other.bitrate
|
1314
1768
|
@user_limit = other.user_limit
|
1315
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
|
1316
1773
|
end
|
1317
1774
|
|
1318
1775
|
# The list of users currently in this channel. For a voice channel, it will return all the members currently
|
@@ -1333,25 +1790,28 @@ module Discordrb
|
|
1333
1790
|
# start at the current message.
|
1334
1791
|
# @param after_id [Integer] The ID of the oldest message the retrieval should start at, or nil if it should start
|
1335
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
|
1336
1794
|
# @example Count the number of messages in the last 50 messages that contain the letter 'e'.
|
1337
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)
|
1338
1798
|
# @return [Array<Message>] the retrieved messages.
|
1339
|
-
def history(amount, before_id = nil, after_id = nil)
|
1340
|
-
logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id)
|
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)
|
1341
1801
|
JSON.parse(logs).map { |message| Message.new(message, @bot) }
|
1342
1802
|
end
|
1343
1803
|
|
1344
|
-
# Retrieves message history, but only message IDs for use with prune
|
1804
|
+
# Retrieves message history, but only message IDs for use with prune.
|
1345
1805
|
# @note For internal use only
|
1346
1806
|
# @!visibility private
|
1347
|
-
def history_ids(amount, before_id = nil, after_id = nil)
|
1348
|
-
logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id)
|
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)
|
1349
1809
|
JSON.parse(logs).map { |message| message['id'].to_i }
|
1350
1810
|
end
|
1351
1811
|
|
1352
1812
|
# Returns a single message from this channel's history by ID.
|
1353
1813
|
# @param message_id [Integer] The ID of the message to retrieve.
|
1354
|
-
# @return [Message] the retrieved message.
|
1814
|
+
# @return [Message, nil] the retrieved message, or `nil` if it couldn't be found.
|
1355
1815
|
def load_message(message_id)
|
1356
1816
|
response = API::Channel.message(@bot.token, @id, message_id)
|
1357
1817
|
return Message.new(JSON.parse(response), @bot)
|
@@ -1361,7 +1821,7 @@ module Discordrb
|
|
1361
1821
|
|
1362
1822
|
alias_method :message, :load_message
|
1363
1823
|
|
1364
|
-
# Requests all pinned messages
|
1824
|
+
# Requests all pinned messages in a channel.
|
1365
1825
|
# @return [Array<Message>] the received messages.
|
1366
1826
|
def pins
|
1367
1827
|
msgs = API::Channel.pinned_messages(@bot.token, @id)
|
@@ -1369,22 +1829,41 @@ module Discordrb
|
|
1369
1829
|
end
|
1370
1830
|
|
1371
1831
|
# Delete the last N messages on this channel.
|
1372
|
-
# @param amount [Integer]
|
1832
|
+
# @param amount [Integer] The amount of message history to consider for pruning. Must be a value between 2 and 100 (Discord limitation)
|
1373
1833
|
# @param strict [true, false] Whether an error should be raised when a message is reached that is too old to be bulk
|
1374
1834
|
# deleted. If this is false only a warning message will be output to the console.
|
1375
1835
|
# @raise [ArgumentError] if the amount of messages is not a value between 2 and 100
|
1376
|
-
|
1377
|
-
|
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
|
1378
1849
|
|
1379
|
-
messages
|
1380
|
-
|
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
|
1381
1859
|
end
|
1382
1860
|
|
1383
1861
|
# Deletes a collection of messages
|
1384
|
-
# @param messages [Array<Message, Integer>] the messages (or message IDs) to delete. Total must be an amount between 2 and 100 (Discord limitation)
|
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)
|
1385
1863
|
# @param strict [true, false] Whether an error should be raised when a message is reached that is too old to be bulk
|
1386
1864
|
# deleted. If this is false only a warning message will be output to the console.
|
1387
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
|
1388
1867
|
def delete_messages(messages, strict = false)
|
1389
1868
|
raise ArgumentError, 'Can only delete between 2 and 100 messages!' unless messages.count.between?(2, 100)
|
1390
1869
|
|
@@ -1402,17 +1881,27 @@ module Discordrb
|
|
1402
1881
|
# Add an {Await} for a message in this channel. This is identical in functionality to adding a
|
1403
1882
|
# {Discordrb::Events::MessageEvent} await with the `in` attribute as this channel.
|
1404
1883
|
# @see Bot#add_await
|
1884
|
+
# @deprecated Will be changed to blocking behavior in v4.0. Use {#await!} instead.
|
1405
1885
|
def await(key, attributes = {}, &block)
|
1406
1886
|
@bot.add_await(key, Discordrb::Events::MessageEvent, { in: @id }.merge(attributes), &block)
|
1407
1887
|
end
|
1408
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
|
+
|
1409
1896
|
# Creates a new invite to this channel.
|
1410
1897
|
# @param max_age [Integer] How many seconds this invite should last.
|
1411
1898
|
# @param max_uses [Integer] How many times this invite should be able to be used.
|
1412
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.
|
1413
1902
|
# @return [Invite] the created invite.
|
1414
|
-
def make_invite(max_age = 0, max_uses = 0, temporary = false)
|
1415
|
-
response = API::Channel.create_invite(@bot.token, @id, max_age, max_uses, temporary)
|
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)
|
1416
1905
|
Invite.new(JSON.parse(response), @bot)
|
1417
1906
|
end
|
1418
1907
|
|
@@ -1421,13 +1910,15 @@ module Discordrb
|
|
1421
1910
|
# Starts typing, which displays the typing indicator on the client for five seconds.
|
1422
1911
|
# If you want to keep typing you'll have to resend this every five seconds. (An abstraction
|
1423
1912
|
# for this will eventually be coming)
|
1913
|
+
# @example Send a typing indicator for the bot in a given channel.
|
1914
|
+
# channel.start_typing()
|
1424
1915
|
def start_typing
|
1425
1916
|
API::Channel.start_typing(@bot.token, @id)
|
1426
1917
|
end
|
1427
1918
|
|
1428
1919
|
# Creates a Group channel
|
1429
1920
|
# @param user_ids [Array<Integer>] Array of user IDs to add to the new group channel (Excluding
|
1430
|
-
#
|
1921
|
+
# the recipient of the PM channel).
|
1431
1922
|
# @return [Channel] the created channel.
|
1432
1923
|
def create_group(user_ids)
|
1433
1924
|
raise 'Attempted to create group channel on a non-pm channel!' unless pm?
|
@@ -1436,7 +1927,7 @@ module Discordrb
|
|
1436
1927
|
channel.add_group_users(user_ids)
|
1437
1928
|
end
|
1438
1929
|
|
1439
|
-
# Adds a user to a
|
1930
|
+
# Adds a user to a group channel.
|
1440
1931
|
# @param user_ids [Array<#resolve_id>, #resolve_id] User ID or array of user IDs to add to the group channel.
|
1441
1932
|
# @return [Channel] the group channel.
|
1442
1933
|
def add_group_users(user_ids)
|
@@ -1464,7 +1955,7 @@ module Discordrb
|
|
1464
1955
|
|
1465
1956
|
alias_method :remove_group_user, :remove_group_users
|
1466
1957
|
|
1467
|
-
# Leaves the group
|
1958
|
+
# Leaves the group.
|
1468
1959
|
def leave_group
|
1469
1960
|
raise 'Attempted to leave a non-group channel!' unless group?
|
1470
1961
|
API::Channel.leave_group(@bot.token, @id)
|
@@ -1472,7 +1963,23 @@ module Discordrb
|
|
1472
1963
|
|
1473
1964
|
alias_method :leave, :leave_group
|
1474
1965
|
|
1475
|
-
#
|
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.
|
1476
1983
|
def inspect
|
1477
1984
|
"<Channel name=#{@name} id=#{@id} topic=\"#{@topic}\" type=#{@type} position=#{@position} server=#{@server}>"
|
1478
1985
|
end
|
@@ -1499,12 +2006,29 @@ module Discordrb
|
|
1499
2006
|
@recipients.delete(recipient)
|
1500
2007
|
end
|
1501
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
|
+
|
1502
2026
|
private
|
1503
2027
|
|
1504
2028
|
# For bulk_delete checking
|
1505
2029
|
TWO_WEEKS = 86_400 * 14
|
1506
2030
|
|
1507
|
-
# Deletes a list of messages on this channel using bulk delete
|
2031
|
+
# Deletes a list of messages on this channel using bulk delete.
|
1508
2032
|
def bulk_delete(ids, strict = false)
|
1509
2033
|
min_snowflake = IDObject.synthesise(Time.now - TWO_WEEKS)
|
1510
2034
|
|
@@ -1514,14 +2038,38 @@ module Discordrb
|
|
1514
2038
|
message = "Attempted to bulk_delete message #{e} which is too old (min = #{min_snowflake})"
|
1515
2039
|
raise ArgumentError, message if strict
|
1516
2040
|
Discordrb::LOGGER.warn(message)
|
1517
|
-
|
2041
|
+
true
|
1518
2042
|
end
|
1519
2043
|
|
1520
2044
|
API::Channel.bulk_delete_messages(@bot.token, @id, ids)
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
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
|
1525
2073
|
end
|
1526
2074
|
end
|
1527
2075
|
|
@@ -1548,15 +2096,34 @@ module Discordrb
|
|
1548
2096
|
# * `:image`
|
1549
2097
|
attr_reader :type
|
1550
2098
|
|
1551
|
-
# @return [
|
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
|
1552
2110
|
attr_reader :provider
|
1553
2111
|
|
1554
|
-
# @return [
|
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
|
1555
2116
|
attr_reader :thumbnail
|
1556
2117
|
|
1557
|
-
# @return [
|
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
|
1558
2122
|
attr_reader :author
|
1559
2123
|
|
2124
|
+
# @return [Array<EmbedField>, nil] the fields of the embed object. `nil` if there are no fields
|
2125
|
+
attr_reader :fields
|
2126
|
+
|
1560
2127
|
# @!visibility private
|
1561
2128
|
def initialize(data, message)
|
1562
2129
|
@message = message
|
@@ -1565,9 +2132,91 @@ module Discordrb
|
|
1565
2132
|
@title = data['title']
|
1566
2133
|
@type = data['type'].to_sym
|
1567
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)
|
1568
2140
|
@provider = data['provider'].nil? ? nil : EmbedProvider.new(data['provider'], self)
|
1569
2141
|
@thumbnail = data['thumbnail'].nil? ? nil : EmbedThumbnail.new(data['thumbnail'], self)
|
1570
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']
|
1571
2220
|
end
|
1572
2221
|
end
|
1573
2222
|
|
@@ -1580,7 +2229,7 @@ module Discordrb
|
|
1580
2229
|
attr_reader :url
|
1581
2230
|
|
1582
2231
|
# @return [String] the thumbnail's proxy URL - I'm not sure what exactly this does, but I think it has something to
|
1583
|
-
# do with CDNs
|
2232
|
+
# do with CDNs.
|
1584
2233
|
attr_reader :proxy_url
|
1585
2234
|
|
1586
2235
|
# @return [Integer] the width of this thumbnail file, in pixels.
|
@@ -1608,7 +2257,7 @@ module Discordrb
|
|
1608
2257
|
# @return [String] the provider's name.
|
1609
2258
|
attr_reader :name
|
1610
2259
|
|
1611
|
-
# @return [String, nil] the URL of the provider
|
2260
|
+
# @return [String, nil] the URL of the provider, or `nil` if there is no URL.
|
1612
2261
|
attr_reader :url
|
1613
2262
|
|
1614
2263
|
# @!visibility private
|
@@ -1628,20 +2277,52 @@ module Discordrb
|
|
1628
2277
|
# @return [String] the author's name.
|
1629
2278
|
attr_reader :name
|
1630
2279
|
|
1631
|
-
# @return [String, nil] the URL of the author's website
|
2280
|
+
# @return [String, nil] the URL of the author's website, or `nil` if there is no URL.
|
1632
2281
|
attr_reader :url
|
1633
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
|
+
|
1634
2289
|
# @!visibility private
|
1635
2290
|
def initialize(data, embed)
|
1636
2291
|
@embed = embed
|
1637
2292
|
|
1638
2293
|
@name = data['name']
|
1639
2294
|
@url = data['url']
|
2295
|
+
@icon_url = data['icon_url']
|
2296
|
+
@proxy_icon_url = data['proxy_icon_url']
|
1640
2297
|
end
|
1641
2298
|
end
|
1642
2299
|
|
1643
|
-
# An
|
1644
|
-
class
|
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
|
1645
2326
|
include IDObject
|
1646
2327
|
|
1647
2328
|
# @return [Message] the message this attachment belongs to.
|
@@ -1651,7 +2332,7 @@ module Discordrb
|
|
1651
2332
|
attr_reader :url
|
1652
2333
|
|
1653
2334
|
# @return [String] the attachment's proxy URL - I'm not sure what exactly this does, but I think it has something to
|
1654
|
-
# do with CDNs
|
2335
|
+
# do with CDNs.
|
1655
2336
|
attr_reader :proxy_url
|
1656
2337
|
|
1657
2338
|
# @return [String] the attachment's filename.
|
@@ -1660,10 +2341,10 @@ module Discordrb
|
|
1660
2341
|
# @return [Integer] the attachment's file size in bytes.
|
1661
2342
|
attr_reader :size
|
1662
2343
|
|
1663
|
-
# @return [Integer, nil] the width of an image file, in pixels, or nil if the file is not an image.
|
2344
|
+
# @return [Integer, nil] the width of an image file, in pixels, or `nil` if the file is not an image.
|
1664
2345
|
attr_reader :width
|
1665
2346
|
|
1666
|
-
# @return [Integer, nil] the height of an image file, in pixels, or nil if the file is not an image.
|
2347
|
+
# @return [Integer, nil] the height of an image file, in pixels, or `nil` if the file is not an image.
|
1667
2348
|
attr_reader :height
|
1668
2349
|
|
1669
2350
|
# @!visibility private
|
@@ -1671,6 +2352,7 @@ module Discordrb
|
|
1671
2352
|
@bot = bot
|
1672
2353
|
@message = message
|
1673
2354
|
|
2355
|
+
@id = data['id'].to_i
|
1674
2356
|
@url = data['url']
|
1675
2357
|
@proxy_url = data['proxy_url']
|
1676
2358
|
@filename = data['filename']
|
@@ -1724,14 +2406,14 @@ module Discordrb
|
|
1724
2406
|
# @return [Array<Embed>] the embed objects contained in this message.
|
1725
2407
|
attr_reader :embeds
|
1726
2408
|
|
1727
|
-
# @return [Hash<String
|
2409
|
+
# @return [Hash<String => Reaction>] the reaction objects attached to this message keyed by the name of the reaction
|
1728
2410
|
attr_reader :reactions
|
1729
2411
|
|
1730
2412
|
# @return [true, false] whether the message used Text-To-Speech (TTS) or not.
|
1731
2413
|
attr_reader :tts
|
1732
2414
|
alias_method :tts?, :tts
|
1733
2415
|
|
1734
|
-
# @return [String] used for validating a message was sent
|
2416
|
+
# @return [String] used for validating a message was sent.
|
1735
2417
|
attr_reader :nonce
|
1736
2418
|
|
1737
2419
|
# @return [true, false] whether the message was edited or not.
|
@@ -1747,7 +2429,7 @@ module Discordrb
|
|
1747
2429
|
attr_reader :pinned
|
1748
2430
|
alias_method :pinned?, :pinned
|
1749
2431
|
|
1750
|
-
# @return [Integer, nil] the webhook ID that sent this message, or nil if it wasn't sent through a webhook.
|
2432
|
+
# @return [Integer, nil] the webhook ID that sent this message, or `nil` if it wasn't sent through a webhook.
|
1751
2433
|
attr_reader :webhook_id
|
1752
2434
|
|
1753
2435
|
# The discriminator that webhook user accounts have.
|
@@ -1778,7 +2460,7 @@ module Discordrb
|
|
1778
2460
|
|
1779
2461
|
unless member
|
1780
2462
|
Discordrb::LOGGER.debug("Member with ID #{data['author']['id']} not cached (possibly left the server).")
|
1781
|
-
member = @bot.
|
2463
|
+
member = @bot.ensure_user(data['author'])
|
1782
2464
|
end
|
1783
2465
|
|
1784
2466
|
member
|
@@ -1837,7 +2519,7 @@ module Discordrb
|
|
1837
2519
|
# Edits this message to have the specified content instead.
|
1838
2520
|
# You can only edit your own messages.
|
1839
2521
|
# @param new_content [String] the new content the message should have.
|
1840
|
-
# @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.
|
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.
|
1841
2523
|
# @return [Message] the resulting message.
|
1842
2524
|
def edit(new_content, new_embed = nil)
|
1843
2525
|
response = API::Channel.edit_message(@bot.token, @channel.id, @id, new_content, [], new_embed ? new_embed.to_hash : nil)
|
@@ -1866,10 +2548,17 @@ module Discordrb
|
|
1866
2548
|
|
1867
2549
|
# Add an {Await} for a message with the same user and channel.
|
1868
2550
|
# @see Bot#add_await
|
2551
|
+
# @deprecated Will be changed to blocking behavior in v4.0. Use {#await!} instead.
|
1869
2552
|
def await(key, attributes = {}, &block)
|
1870
2553
|
@bot.add_await(key, Discordrb::Events::MessageEvent, { from: @author.id, in: @channel.id }.merge(attributes), &block)
|
1871
2554
|
end
|
1872
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
|
+
|
1873
2562
|
# @return [true, false] whether this message was sent by the current {Bot}.
|
1874
2563
|
def from_bot?
|
1875
2564
|
@author && @author.current_bot?
|
@@ -1884,11 +2573,11 @@ module Discordrb
|
|
1884
2573
|
# @return [Array<String>] the emoji mentions found in the message
|
1885
2574
|
def scan_for_emoji
|
1886
2575
|
emoji = @content.split
|
1887
|
-
emoji = emoji.grep(
|
2576
|
+
emoji = emoji.grep(/<(?<animated>a)?:(?<name>\w+):(?<id>\d+)>?/)
|
1888
2577
|
emoji
|
1889
2578
|
end
|
1890
2579
|
|
1891
|
-
# @return [Array<Emoji>] the emotes that were used/mentioned in this message
|
2580
|
+
# @return [Array<Emoji>] the emotes that were used/mentioned in this message.
|
1892
2581
|
def emoji
|
1893
2582
|
return if @content.nil?
|
1894
2583
|
|
@@ -1899,27 +2588,27 @@ module Discordrb
|
|
1899
2588
|
@emoji
|
1900
2589
|
end
|
1901
2590
|
|
1902
|
-
# Check if any emoji
|
1903
|
-
# @return [true, false] whether or not any emoji
|
2591
|
+
# Check if any emoji were used in this message.
|
2592
|
+
# @return [true, false] whether or not any emoji were used
|
1904
2593
|
def emoji?
|
1905
2594
|
emoji = scan_for_emoji
|
1906
2595
|
return true unless emoji.empty?
|
1907
2596
|
end
|
1908
2597
|
|
1909
|
-
# Check if any reactions
|
2598
|
+
# Check if any reactions were used in this message.
|
1910
2599
|
# @return [true, false] whether or not this message has reactions
|
1911
2600
|
def reactions?
|
1912
2601
|
@reactions.any?
|
1913
2602
|
end
|
1914
2603
|
|
1915
|
-
# Returns the reactions made by the current bot or user
|
2604
|
+
# Returns the reactions made by the current bot or user.
|
1916
2605
|
# @return [Array<Reaction>] the reactions
|
1917
2606
|
def my_reactions
|
1918
|
-
@reactions.select(&:me)
|
2607
|
+
@reactions.values.select(&:me)
|
1919
2608
|
end
|
1920
2609
|
|
1921
|
-
# Reacts to a message
|
1922
|
-
# @param [String, #to_reaction] the unicode emoji
|
2610
|
+
# Reacts to a message.
|
2611
|
+
# @param reaction [String, #to_reaction] the unicode emoji or {Emoji}
|
1923
2612
|
def create_reaction(reaction)
|
1924
2613
|
reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
|
1925
2614
|
API::Channel.create_reaction(@bot.token, @channel.id, @id, reaction)
|
@@ -1928,8 +2617,10 @@ module Discordrb
|
|
1928
2617
|
|
1929
2618
|
alias_method :react, :create_reaction
|
1930
2619
|
|
1931
|
-
# Returns the list of users who reacted with a certain reaction
|
1932
|
-
# @param [String, #to_reaction] the unicode emoji
|
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}")
|
1933
2624
|
# @return [Array<User>] the users who used this reaction
|
1934
2625
|
def reacted_with(reaction)
|
1935
2626
|
reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
|
@@ -1937,22 +2628,22 @@ module Discordrb
|
|
1937
2628
|
response.map { |d| User.new(d, @bot) }
|
1938
2629
|
end
|
1939
2630
|
|
1940
|
-
# Deletes a reaction made by a user on this message
|
1941
|
-
# @param [User, #resolve_id] the user who used this reaction
|
1942
|
-
# @param [String, #to_reaction] the reaction to remove
|
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
|
1943
2634
|
def delete_reaction(user, reaction)
|
1944
2635
|
reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
|
1945
2636
|
API::Channel.delete_user_reaction(@bot.token, @channel.id, @id, reaction, user.resolve_id)
|
1946
2637
|
end
|
1947
2638
|
|
1948
|
-
#
|
1949
|
-
# @param [String, #to_reaction] the reaction to remove
|
2639
|
+
# Deletes this client's reaction on this message.
|
2640
|
+
# @param reaction [String, #to_reaction] the reaction to remove
|
1950
2641
|
def delete_own_reaction(reaction)
|
1951
2642
|
reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
|
1952
2643
|
API::Channel.delete_own_reaction(@bot.token, @channel.id, @id, reaction)
|
1953
2644
|
end
|
1954
2645
|
|
1955
|
-
# Removes all reactions from this message
|
2646
|
+
# Removes all reactions from this message.
|
1956
2647
|
def delete_all_reactions
|
1957
2648
|
API::Channel.delete_all_reactions(@bot.token, @channel.id, @id)
|
1958
2649
|
end
|
@@ -1963,7 +2654,7 @@ module Discordrb
|
|
1963
2654
|
end
|
1964
2655
|
end
|
1965
2656
|
|
1966
|
-
# A reaction to a message
|
2657
|
+
# A reaction to a message.
|
1967
2658
|
class Reaction
|
1968
2659
|
# @return [Integer] the amount of users who have reacted with this reaction
|
1969
2660
|
attr_reader :count
|
@@ -1984,6 +2675,13 @@ module Discordrb
|
|
1984
2675
|
@id = data['emoji']['id'].nil? ? nil : data['emoji']['id'].to_i
|
1985
2676
|
@name = data['emoji']['name']
|
1986
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
|
1987
2685
|
end
|
1988
2686
|
|
1989
2687
|
# Server emoji
|
@@ -1999,6 +2697,10 @@ module Discordrb
|
|
1999
2697
|
# @return [Array<Role>] roles this emoji is active for
|
2000
2698
|
attr_reader :roles
|
2001
2699
|
|
2700
|
+
# @return [true, false] if the emoji is animated
|
2701
|
+
attr_reader :animated
|
2702
|
+
alias_method :animated?, :animated
|
2703
|
+
|
2002
2704
|
def initialize(data, bot, server)
|
2003
2705
|
@bot = bot
|
2004
2706
|
@roles = nil
|
@@ -2006,13 +2708,14 @@ module Discordrb
|
|
2006
2708
|
@name = data['name']
|
2007
2709
|
@server = server
|
2008
2710
|
@id = data['id'].nil? ? nil : data['id'].to_i
|
2711
|
+
@animated = data['animated']
|
2009
2712
|
|
2010
2713
|
process_roles(data['roles']) if server
|
2011
2714
|
end
|
2012
2715
|
|
2013
2716
|
# @return [String] the layout to mention it (or have it used) in a message
|
2014
2717
|
def mention
|
2015
|
-
"
|
2718
|
+
"<#{'a' if animated}:#{name}:#{id}>"
|
2016
2719
|
end
|
2017
2720
|
|
2018
2721
|
alias_method :use, :mention
|
@@ -2020,17 +2723,17 @@ module Discordrb
|
|
2020
2723
|
|
2021
2724
|
# @return [String] the layout to use this emoji in a reaction
|
2022
2725
|
def to_reaction
|
2023
|
-
"#{
|
2726
|
+
"#{name}:#{id}"
|
2024
2727
|
end
|
2025
2728
|
|
2026
2729
|
# @return [String] the icon URL of the emoji
|
2027
2730
|
def icon_url
|
2028
|
-
API.emoji_icon_url(
|
2731
|
+
API.emoji_icon_url(id)
|
2029
2732
|
end
|
2030
2733
|
|
2031
2734
|
# The inspect method is overwritten to give more useful output
|
2032
2735
|
def inspect
|
2033
|
-
"<Emoji name=#{
|
2736
|
+
"<Emoji name=#{name} id=#{id} animated=#{animated}>"
|
2034
2737
|
end
|
2035
2738
|
|
2036
2739
|
# @!visibility private
|
@@ -2044,61 +2747,6 @@ module Discordrb
|
|
2044
2747
|
end
|
2045
2748
|
end
|
2046
2749
|
|
2047
|
-
# Emoji that is not tailored to a server
|
2048
|
-
class GlobalEmoji
|
2049
|
-
include IDObject
|
2050
|
-
|
2051
|
-
# @return [String] the emoji name
|
2052
|
-
attr_reader :name
|
2053
|
-
|
2054
|
-
# @return [Hash<Integer => Array<Role>>] roles this emoji is active for in every server
|
2055
|
-
attr_reader :role_associations
|
2056
|
-
|
2057
|
-
def initialize(data, bot)
|
2058
|
-
@bot = bot
|
2059
|
-
@roles = nil
|
2060
|
-
|
2061
|
-
@name = data.name
|
2062
|
-
@id = data.id
|
2063
|
-
@role_associations = Hash.new([])
|
2064
|
-
@role_associations[data.server.id] = data.roles
|
2065
|
-
end
|
2066
|
-
|
2067
|
-
# @return [String] the layout to mention it (or have it used) in a message
|
2068
|
-
def mention
|
2069
|
-
"<:#{@name}:#{@id}>"
|
2070
|
-
end
|
2071
|
-
|
2072
|
-
alias_method :use, :mention
|
2073
|
-
alias_method :to_s, :mention
|
2074
|
-
|
2075
|
-
# @return [String] the layout to use this emoji in a reaction
|
2076
|
-
def to_reaction
|
2077
|
-
"#{@name}:#{@id}"
|
2078
|
-
end
|
2079
|
-
|
2080
|
-
# @return [String] the icon URL of the emoji
|
2081
|
-
def icon_url
|
2082
|
-
API.emoji_icon_url(@id)
|
2083
|
-
end
|
2084
|
-
|
2085
|
-
# The inspect method is overwritten to give more useful output
|
2086
|
-
def inspect
|
2087
|
-
"<GlobalEmoji name=#{@name} id=#{@id}>"
|
2088
|
-
end
|
2089
|
-
|
2090
|
-
# @!visibility private
|
2091
|
-
def process_roles(roles)
|
2092
|
-
new_roles = []
|
2093
|
-
return unless roles
|
2094
|
-
roles.each do
|
2095
|
-
role = server.role(role_id)
|
2096
|
-
new_roles << role
|
2097
|
-
end
|
2098
|
-
new_roles
|
2099
|
-
end
|
2100
|
-
end
|
2101
|
-
|
2102
2750
|
# Basic attributes a server should have
|
2103
2751
|
module ServerAttributes
|
2104
2752
|
# @return [String] this server's name.
|
@@ -2149,7 +2797,7 @@ module Discordrb
|
|
2149
2797
|
attr_reader :emoticon
|
2150
2798
|
alias_method :emoticon?, :emoticon
|
2151
2799
|
|
2152
|
-
# @return [String] the integration type (
|
2800
|
+
# @return [String] the integration type (YouTube, Twitch, etc.)
|
2153
2801
|
attr_reader :type
|
2154
2802
|
|
2155
2803
|
# @return [true, false] whether the integration is enabled
|
@@ -2182,7 +2830,7 @@ module Discordrb
|
|
2182
2830
|
@type = data['type']
|
2183
2831
|
@account = IntegrationAccount.new(data['account'])
|
2184
2832
|
@synced_at = Time.parse(data['synced_at'])
|
2185
|
-
@expire_behaviour = [
|
2833
|
+
@expire_behaviour = %i[remove kick][data['expire_behavior']]
|
2186
2834
|
@expire_grace_period = data['expire_grace_period']
|
2187
2835
|
@user = @bot.ensure_user(data['user'])
|
2188
2836
|
@role = server.role(data['role_id']) || nil
|
@@ -2200,8 +2848,8 @@ module Discordrb
|
|
2200
2848
|
include IDObject
|
2201
2849
|
include ServerAttributes
|
2202
2850
|
|
2203
|
-
# @return [String] the region the server is on (e.
|
2204
|
-
attr_reader :
|
2851
|
+
# @return [String] the ID of the region the server is on (e.g. `amsterdam`).
|
2852
|
+
attr_reader :region_id
|
2205
2853
|
|
2206
2854
|
# @return [Member] The server owner.
|
2207
2855
|
attr_reader :owner
|
@@ -2212,7 +2860,7 @@ module Discordrb
|
|
2212
2860
|
# @return [Array<Role>] an array of all the roles created on this server.
|
2213
2861
|
attr_reader :roles
|
2214
2862
|
|
2215
|
-
# @return [Hash<Integer
|
2863
|
+
# @return [Hash<Integer => Emoji>] a hash of all the emoji available on this server.
|
2216
2864
|
attr_reader :emoji
|
2217
2865
|
alias_method :emojis, :emoji
|
2218
2866
|
|
@@ -2227,15 +2875,9 @@ module Discordrb
|
|
2227
2875
|
# @return [Integer] the absolute number of members on this server, offline or not.
|
2228
2876
|
attr_reader :member_count
|
2229
2877
|
|
2230
|
-
# @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').
|
2231
|
-
attr_reader :verification_level
|
2232
|
-
|
2233
2878
|
# @return [Integer] the amount of time after which a voice user gets moved into the AFK channel, in seconds.
|
2234
2879
|
attr_reader :afk_timeout
|
2235
2880
|
|
2236
|
-
# @return [Channel, nil] the AFK voice channel of this server, or nil if none is set
|
2237
|
-
attr_reader :afk_channel
|
2238
|
-
|
2239
2881
|
# @return [Hash<Integer => VoiceState>] the hash (user ID => voice state) of voice states of members on this server
|
2240
2882
|
attr_reader :voice_states
|
2241
2883
|
|
@@ -2244,13 +2886,13 @@ module Discordrb
|
|
2244
2886
|
@bot = bot
|
2245
2887
|
@owner_id = data['owner_id'].to_i
|
2246
2888
|
@id = data['id'].to_i
|
2889
|
+
|
2890
|
+
process_channels(data['channels'])
|
2247
2891
|
update_data(data)
|
2248
2892
|
|
2249
2893
|
@large = data['large']
|
2250
2894
|
@member_count = data['member_count']
|
2251
|
-
@verification_level = [:none, :low, :medium, :high][data['verification_level']]
|
2252
2895
|
@splash_id = nil
|
2253
|
-
@embed = nil
|
2254
2896
|
@features = data['features'].map { |element| element.downcase.to_sym }
|
2255
2897
|
@members = {}
|
2256
2898
|
@voice_states = {}
|
@@ -2260,24 +2902,38 @@ module Discordrb
|
|
2260
2902
|
process_emoji(data['emojis'])
|
2261
2903
|
process_members(data['members'])
|
2262
2904
|
process_presences(data['presences'])
|
2263
|
-
process_channels(data['channels'])
|
2264
2905
|
process_voice_states(data['voice_states'])
|
2265
2906
|
|
2266
2907
|
# Whether this server's members have been chunked (resolved using op 8 and GUILD_MEMBERS_CHUNK) yet
|
2267
2908
|
@chunked = false
|
2268
2909
|
@processed_chunk_members = 0
|
2269
2910
|
|
2270
|
-
# Only get the owner of the server actually exists (i.
|
2911
|
+
# Only get the owner of the server actually exists (i.e. not for ServerDeleteEvent)
|
2271
2912
|
@owner = member(@owner_id) if exists
|
2272
2913
|
end
|
2273
2914
|
|
2274
|
-
#
|
2275
|
-
|
2276
|
-
|
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
|
2277
2928
|
end
|
2278
2929
|
|
2279
2930
|
alias_method :general_channel, :default_channel
|
2280
2931
|
|
2932
|
+
# @return [Role] The @everyone role on this server
|
2933
|
+
def everyone_role
|
2934
|
+
role(@id)
|
2935
|
+
end
|
2936
|
+
|
2281
2937
|
# Gets a role on this server based on its ID.
|
2282
2938
|
# @param id [Integer, String, #resolve_id] The role ID to look for.
|
2283
2939
|
def role(id)
|
@@ -2294,7 +2950,7 @@ module Discordrb
|
|
2294
2950
|
return nil unless request
|
2295
2951
|
|
2296
2952
|
member = @bot.member(self, id)
|
2297
|
-
@members[id] = member
|
2953
|
+
@members[id] = member unless member.nil?
|
2298
2954
|
rescue
|
2299
2955
|
nil
|
2300
2956
|
end
|
@@ -2317,19 +2973,92 @@ module Discordrb
|
|
2317
2973
|
integration.map { |element| Integration.new(element, @bot, self) }
|
2318
2974
|
end
|
2319
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
|
+
|
2320
2989
|
# Cache @embed
|
2321
2990
|
# @note For internal use only
|
2322
2991
|
# @!visibility private
|
2323
|
-
def
|
2324
|
-
|
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']
|
2325
2996
|
end
|
2326
2997
|
|
2327
2998
|
# @return [true, false] whether or not the server has widget enabled
|
2328
|
-
def
|
2329
|
-
|
2330
|
-
@
|
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)
|
2331
3018
|
end
|
2332
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
|
+
|
2333
3062
|
# @param include_idle [true, false] Whether to count idle members as online.
|
2334
3063
|
# @param include_bots [true, false] Whether to include bot accounts in the count.
|
2335
3064
|
# @return [Array<Member>] an array of online members on this server.
|
@@ -2341,6 +3070,49 @@ module Discordrb
|
|
2341
3070
|
|
2342
3071
|
alias_method :online_users, :online_members
|
2343
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
|
+
|
2344
3116
|
# @return [Array<Channel>] an array of text channels on this server
|
2345
3117
|
def text_channels
|
2346
3118
|
@channels.select(&:text?)
|
@@ -2351,11 +3123,21 @@ module Discordrb
|
|
2351
3123
|
@channels.select(&:voice?)
|
2352
3124
|
end
|
2353
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
|
+
|
2354
3136
|
# @return [String, nil] the widget URL to the server that displays the amount of online members in a
|
2355
3137
|
# stylish way. `nil` if the widget is not enabled.
|
2356
3138
|
def widget_url
|
2357
|
-
|
2358
|
-
return
|
3139
|
+
update_data if @embed_enabled.nil?
|
3140
|
+
return unless @embed_enabled
|
2359
3141
|
API.widget_url(@id)
|
2360
3142
|
end
|
2361
3143
|
|
@@ -2368,8 +3150,8 @@ module Discordrb
|
|
2368
3150
|
# @return [String, nil] the widget banner URL to the server that displays the amount of online members,
|
2369
3151
|
# server icon and server name in a stylish way. `nil` if the widget is not enabled.
|
2370
3152
|
def widget_banner_url(style)
|
2371
|
-
|
2372
|
-
|
3153
|
+
update_data if @embed_enabled.nil?
|
3154
|
+
return unless @embed_enabled
|
2373
3155
|
API.widget_url(@id, style)
|
2374
3156
|
end
|
2375
3157
|
|
@@ -2408,12 +3190,23 @@ module Discordrb
|
|
2408
3190
|
end
|
2409
3191
|
end
|
2410
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
|
+
|
2411
3204
|
# Adds a member to the member cache.
|
2412
3205
|
# @note For internal use only
|
2413
3206
|
# @!visibility private
|
2414
3207
|
def add_member(member)
|
2415
|
-
@members[member.id] = member
|
2416
3208
|
@member_count += 1
|
3209
|
+
@members[member.id] = member
|
2417
3210
|
end
|
2418
3211
|
|
2419
3212
|
# Removes a member from the member cache.
|
@@ -2466,50 +3259,89 @@ module Discordrb
|
|
2466
3259
|
end
|
2467
3260
|
|
2468
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
|
+
#
|
2469
3268
|
# @param name [String] Name of the channel to create
|
2470
|
-
# @param type [Integer] Type of channel to create (0: text, 2: voice)
|
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.
|
2471
3278
|
# @return [Channel] the created channel.
|
2472
|
-
# @raise [ArgumentError] if type is not 0 or
|
2473
|
-
def create_channel(name, type = 0)
|
2474
|
-
|
2475
|
-
|
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)
|
2476
3286
|
Channel.new(JSON.parse(response), @bot)
|
2477
3287
|
end
|
2478
3288
|
|
2479
|
-
# Creates a role on this server which can then be modified. It will be initialized
|
2480
|
-
# with the regular role defaults the client uses, i.
|
2481
|
-
# colour is the default etc.
|
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.
|
2482
3298
|
# @return [Role] the created role.
|
2483
|
-
def create_role
|
2484
|
-
|
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
|
+
|
2485
3312
|
role = Role.new(JSON.parse(response), @bot, self)
|
2486
3313
|
@roles << role
|
2487
3314
|
role
|
2488
3315
|
end
|
2489
3316
|
|
2490
|
-
# @return [Array<
|
3317
|
+
# @return [Array<ServerBan>] a list of banned users on this server and the reason they were banned.
|
2491
3318
|
def bans
|
2492
|
-
|
2493
|
-
|
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
|
2494
3323
|
end
|
2495
3324
|
|
2496
3325
|
# Bans a user from this server.
|
2497
3326
|
# @param user [User, #resolve_id] The user to ban.
|
2498
3327
|
# @param message_days [Integer] How many days worth of messages sent by the user should be deleted.
|
2499
|
-
|
2500
|
-
|
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)
|
2501
3331
|
end
|
2502
3332
|
|
2503
3333
|
# Unbans a previously banned user from this server.
|
2504
3334
|
# @param user [User, #resolve_id] The user to unban.
|
2505
|
-
|
2506
|
-
|
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)
|
2507
3338
|
end
|
2508
3339
|
|
2509
3340
|
# Kicks a user from this server.
|
2510
3341
|
# @param user [User, #resolve_id] The user to kick.
|
2511
|
-
|
2512
|
-
|
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)
|
2513
3345
|
end
|
2514
3346
|
|
2515
3347
|
# Forcibly moves a user into a different voice channel. Only works if the bot has the permission needed.
|
@@ -2524,7 +3356,7 @@ module Discordrb
|
|
2524
3356
|
API::Server.delete(@bot.token, @id)
|
2525
3357
|
end
|
2526
3358
|
|
2527
|
-
# Leave the server
|
3359
|
+
# Leave the server.
|
2528
3360
|
def leave
|
2529
3361
|
API::User.leave_server(@bot.token, @id)
|
2530
3362
|
end
|
@@ -2541,6 +3373,22 @@ module Discordrb
|
|
2541
3373
|
update_server_data(name: name)
|
2542
3374
|
end
|
2543
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
|
+
|
2544
3392
|
# Moves the server to another region. This will cause a voice interruption of at most a second.
|
2545
3393
|
# @param region [String] The new region the server should be in.
|
2546
3394
|
def region=(region)
|
@@ -2553,9 +3401,9 @@ module Discordrb
|
|
2553
3401
|
if icon.respond_to? :read
|
2554
3402
|
icon_string = 'data:image/jpg;base64,'
|
2555
3403
|
icon_string += Base64.strict_encode64(icon.read)
|
2556
|
-
update_server_data(
|
3404
|
+
update_server_data(icon_id: icon_string)
|
2557
3405
|
else
|
2558
|
-
update_server_data(
|
3406
|
+
update_server_data(icon_id: icon)
|
2559
3407
|
end
|
2560
3408
|
end
|
2561
3409
|
|
@@ -2565,12 +3413,89 @@ module Discordrb
|
|
2565
3413
|
update_server_data(afk_channel_id: afk_channel.resolve_id)
|
2566
3414
|
end
|
2567
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
|
+
|
2568
3422
|
# Sets the amount of time after which a user gets moved into the AFK channel.
|
2569
3423
|
# @param afk_timeout [Integer] The AFK timeout, in seconds.
|
2570
3424
|
def afk_timeout=(afk_timeout)
|
2571
3425
|
update_server_data(afk_timeout: afk_timeout)
|
2572
3426
|
end
|
2573
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
|
+
|
2574
3499
|
# @return [true, false] whether this server has any emoji or not.
|
2575
3500
|
def any_emoji?
|
2576
3501
|
@emoji.any?
|
@@ -2579,6 +3504,20 @@ module Discordrb
|
|
2579
3504
|
alias_method :has_emoji?, :any_emoji?
|
2580
3505
|
alias_method :emoji?, :any_emoji?
|
2581
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
|
+
|
2582
3521
|
# Processes a GUILD_MEMBERS_CHUNK packet, specifically the members field
|
2583
3522
|
# @note For internal use only
|
2584
3523
|
# @!visibility private
|
@@ -2597,23 +3536,39 @@ module Discordrb
|
|
2597
3536
|
@processed_chunk_members = 0
|
2598
3537
|
end
|
2599
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
|
+
|
2600
3549
|
# Updates the cached data with new data
|
2601
3550
|
# @note For internal use only
|
2602
3551
|
# @!visibility private
|
2603
|
-
def update_data(new_data)
|
3552
|
+
def update_data(new_data = nil)
|
3553
|
+
new_data ||= JSON.parse(API::Server.resolve(@bot.token, @id))
|
2604
3554
|
@name = new_data[:name] || new_data['name'] || @name
|
2605
|
-
@
|
3555
|
+
@region_id = new_data[:region] || new_data['region'] || @region_id
|
2606
3556
|
@icon_id = new_data[:icon] || new_data['icon'] || @icon_id
|
2607
|
-
@afk_timeout = new_data[:afk_timeout] || new_data['afk_timeout']
|
3557
|
+
@afk_timeout = new_data[:afk_timeout] || new_data['afk_timeout'] || @afk_timeout
|
2608
3558
|
|
2609
|
-
|
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
|
2610
3565
|
|
2611
|
-
|
2612
|
-
|
2613
|
-
|
2614
|
-
|
2615
|
-
|
2616
|
-
|
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
|
2617
3572
|
end
|
2618
3573
|
|
2619
3574
|
# Adds a channel to this server's cache
|
@@ -2642,19 +3597,24 @@ module Discordrb
|
|
2642
3597
|
|
2643
3598
|
# The inspect method is overwritten to give more useful output
|
2644
3599
|
def inspect
|
2645
|
-
"<Server name=#{@name} id=#{@id} large=#{@large} region=#{@region} owner=#{@owner} afk_channel_id=#{@afk_channel_id} afk_timeout=#{@afk_timeout}>"
|
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}>"
|
2646
3601
|
end
|
2647
3602
|
|
2648
3603
|
private
|
2649
3604
|
|
2650
3605
|
def update_server_data(new_data)
|
2651
|
-
API::Server.update(@bot.token, @id,
|
2652
|
-
|
2653
|
-
|
2654
|
-
|
2655
|
-
|
2656
|
-
|
2657
|
-
|
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)
|
2658
3618
|
end
|
2659
3619
|
|
2660
3620
|
def process_roles(roles)
|
@@ -2721,6 +3681,477 @@ module Discordrb
|
|
2721
3681
|
end
|
2722
3682
|
end
|
2723
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
|
+
|
2724
4155
|
# A colour (red, green and blue values). Used for role colours. If you prefer the American spelling, the alias
|
2725
4156
|
# {ColorRGB} is also available.
|
2726
4157
|
class ColourRGB
|
@@ -2735,15 +4166,27 @@ module Discordrb
|
|
2735
4166
|
|
2736
4167
|
# @return [Integer] the colour's RGB values combined into one integer.
|
2737
4168
|
attr_reader :combined
|
4169
|
+
alias_method :to_i, :combined
|
2738
4170
|
|
2739
4171
|
# Make a new colour from the combined value.
|
2740
|
-
# @param combined [Integer] The colour's RGB values combined into one integer
|
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
|
2741
4178
|
def initialize(combined)
|
2742
|
-
@combined = combined
|
2743
|
-
@red = (combined >> 16) & 0xFF
|
2744
|
-
@green = (combined >> 8) & 0xFF
|
2745
|
-
@blue = combined & 0xFF
|
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)
|
2746
4188
|
end
|
4189
|
+
alias_method :hexadecimal, :hex
|
2747
4190
|
end
|
2748
4191
|
|
2749
4192
|
# Alias for the class {ColourRGB}
|