discordrb 1.5.4 → 1.6.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.

@@ -82,7 +82,13 @@ module Discordrb::Commands
82
82
  end
83
83
 
84
84
  def command(name, attributes = {}, &block)
85
- @commands[name] = Command.new(name, attributes, &block)
85
+ if name.is_a? Array
86
+ new_command = Command.new(name[0], attributes, &block)
87
+ name.each { |n| @commands[n] = new_command }
88
+ new_command
89
+ else
90
+ @commands[name] = Command.new(name, attributes, &block)
91
+ end
86
92
  end
87
93
 
88
94
  def execute_command(name, event, arguments, chained = false)
@@ -98,7 +104,6 @@ module Discordrb::Commands
98
104
  result.to_s
99
105
  else
100
106
  event.respond "You don't have permission to execute command `#{name}`!"
101
- return
102
107
  end
103
108
  end
104
109
 
@@ -181,6 +181,8 @@ module Discordrb::Commands
181
181
 
182
182
  result = new_result
183
183
  # TODO: more chain arguments
184
+ else
185
+ # ignore
184
186
  end
185
187
  end
186
188
 
@@ -11,15 +11,48 @@ require 'base64'
11
11
  module Discordrb
12
12
  # Compares two objects based on IDs - either the objects' IDs are equal, or one object is equal to the other's ID.
13
13
  def self.id_compare(one_id, other)
14
- other.respond_to?(:id) ? (one_id == other.id) : (one_id == other)
14
+ other.respond_to?(:resolve_id) ? (one_id.resolve_id == other.resolve_id) : (one_id == other)
15
15
  end
16
16
 
17
17
  # User on Discord, including internal data like discriminators
18
18
  class User
19
- attr_reader :username, :id, :discriminator, :avatar, :voice_channel, :roles
20
- attr_accessor :status, :game, :server_mute, :server_deaf, :self_mute, :self_deaf
19
+ # @return [String] this user's username
20
+ attr_reader :username
21
+
22
+ # @return [Integer] this user's ID which uniquely identifies them across Discord.
23
+ attr_reader :id
24
+
25
+ # @return [String] this user's discriminator which is used internally to identify users with identical usernames.
26
+ attr_reader :discriminator
27
+
28
+ # @return [String] the ID of this user's current avatar, can be used to generate an avatar URL.
29
+ # @see #avatar_url
30
+ attr_reader :avatar_id
31
+
32
+ # @return [Channel, nil] the voice channel this user is on currently.
33
+ attr_reader :voice_channel
34
+
35
+ # @return [Hash<Integer => Array<Role>>] the roles this user has, grouped by server ID.
36
+ attr_reader :roles
37
+
38
+ # @!attribute [r] status
39
+ # @return [Symbol] the current online status of the user (`:online`, `:offline` or `:idle`)
40
+ attr_accessor :status
41
+
42
+ # @!attribute [r] game
43
+ # @return [String, nil] the game the user is currently playing, or `nil` if none is being played.
44
+ attr_accessor :game
45
+
46
+ # @!attribute [r] self_mute
47
+ # @return [true, false] whether or not the user is currently muted by the bot.
48
+ attr_accessor :self_mute
49
+
50
+ # @todo Fix these (server_mute and _deaf should be server specific, not sure about self_deaf or what it does anyway)
51
+ # @!visibility private
52
+ attr_accessor :server_mute, :server_deaf, :self_deaf
21
53
 
22
54
  alias_method :name, :username
55
+ alias_method :resolve_id, :id
23
56
 
24
57
  def initialize(data, bot)
25
58
  @bot = bot
@@ -27,7 +60,7 @@ module Discordrb
27
60
  @username = data['username']
28
61
  @id = data['id'].to_i
29
62
  @discriminator = data['discriminator']
30
- @avatar = data['avatar']
63
+ @avatar_id = data['avatar']
31
64
  @roles = {}
32
65
 
33
66
  @status = :offline
@@ -38,12 +71,33 @@ module Discordrb
38
71
  Discordrb.id_compare(@id, other)
39
72
  end
40
73
 
74
+ # Gets the user's avatar ID.
75
+ # @deprecated Use {#avatar_id} instead.
76
+ def avatar
77
+ LOGGER.debug('Warning: Deprecated reader User.avatar was used! Use User.avatar_id (or User.avatar_url if you just want the URL) instead.', true)
78
+ @avatar_id
79
+ end
80
+
41
81
  # Utility function to mention users in messages
82
+ # @return [String] the mention code in the form of <@id>
42
83
  def mention
43
84
  "<@#{@id}>"
44
85
  end
45
86
 
46
- # Utility function to send a PM
87
+ # Utility function to get a user's avatar URL.
88
+ # @return [String] the URL to the avatar image.
89
+ def avatar_url
90
+ API.avatar_url(@id, @avatar_id)
91
+ end
92
+
93
+ # Get a user's PM channel or send them a PM
94
+ # @overload pm
95
+ # Creates a private message channel for this user or returns an existing one if it already exists
96
+ # @return [Channel] the PM channel to this user.
97
+ # @overload pm(content)
98
+ # Sends a private to this user.
99
+ # @param content [String] The content to send.
100
+ # @return [Message] the message sent to this user.
47
101
  def pm(content = nil)
48
102
  if content
49
103
  # Recursively call pm to get the channel, then send a message to it
@@ -55,12 +109,17 @@ module Discordrb
55
109
  end
56
110
  end
57
111
 
58
- # Move a user into a voice channel
112
+ # Changes a user's voice channel.
113
+ # @note For internal use only
114
+ # @!visibility private
59
115
  def move(to_channel)
60
116
  return if to_channel && to_channel.type != 'voice'
61
117
  @voice_channel = to_channel
62
118
  end
63
119
 
120
+ # Adds a role to this user on the specified server.
121
+ # @param server [Server] The server on which to add the role.
122
+ # @param role [Role] The role to add.
64
123
  def add_role(server, role)
65
124
  user_roles = @roles[server.id] || []
66
125
  user_roles << role
@@ -68,6 +127,9 @@ module Discordrb
68
127
  API.update_user_roles(@bot.token, server.id, @id, ids)
69
128
  end
70
129
 
130
+ # Removes a role from this user on the specified server.
131
+ # @param server [Server] The server on which to remove the role.
132
+ # @param role [Role] The role to remove.
71
133
  def remove_role(server, role)
72
134
  user_roles = @roles[server.id] || []
73
135
 
@@ -77,39 +139,50 @@ module Discordrb
77
139
  API.update_user_roles(@bot.token, server.id, @id, ids)
78
140
  end
79
141
 
80
- # Set this user's roles
142
+ # Set this user's roles in the cache
143
+ # @note For internal use only
144
+ # @!visibility private
81
145
  def update_roles(server, roles)
82
146
  @roles ||= {}
83
147
  @roles[server.id] = roles
84
148
  end
85
149
 
86
150
  # Merge this user's roles with the roles from another instance of this user (from another server)
151
+ # @note For internal use only
152
+ # @!visibility private
87
153
  def merge_roles(server, roles)
88
- if @roles[server.id]
89
- @roles[server.id] = (@roles[server.id] + roles).uniq
90
- else
91
- @roles[server.id] = roles
92
- end
154
+ @roles[server.id] = if @roles[server.id]
155
+ (@roles[server.id] + roles).uniq
156
+ else
157
+ roles
158
+ end
93
159
  end
94
160
 
95
161
  # Delete a specific server from the roles (in case a user leaves a server)
162
+ # @note For internal use only
163
+ # @!visibility private
96
164
  def delete_roles(server_id)
97
165
  @roles.delete(server_id)
98
166
  end
99
167
 
100
- # Add an await for a message from this user
168
+ # Add an await for a message from this user. Specifically, this adds a global await for a MessageEvent with this
169
+ # user's ID as a :from attribute.
170
+ # @see Bot#add_await
101
171
  def await(key, attributes = {}, &block)
102
172
  @bot.add_await(key, Discordrb::Events::MessageEvent, { from: @id }.merge(attributes), &block)
103
173
  end
104
174
 
105
175
  # Is the user the bot?
176
+ # @return [true, false] whether this user is the bot
106
177
  def bot?
107
178
  @bot.bot_user.id == @id
108
179
  end
109
180
 
110
- # Determine if the user has permission to do an action
111
- # action is a permission from Permissions::Flags.
112
- # channel is the channel in which the action takes place (not applicable for server-wide actions).
181
+ # Determines whether this user has a specific permission on a server (and channel).
182
+ # @param action [Symbol] The permission that should be checked. See also {Permissions::Flags} for a list.
183
+ # @param server [Server] The server on which the permission should be checked.
184
+ # @param channel [Channel, nil] If channel overrides should be checked too, this channel specifies where the overrides should be checked.
185
+ # @return [true, false] whether or not this user has the permission.
113
186
  def permission?(action, server, channel = nil)
114
187
  # For each role, check if
115
188
  # (1) the channel explicitly allows or permits an action for the role and
@@ -128,13 +201,11 @@ module Discordrb
128
201
  end
129
202
  # If the channel has nothing to say on the matter, we can defer to the role itself
130
203
  end
131
- if channel_allow == false
132
- can_act = false
133
- elsif channel_allow == true
134
- can_act = true
135
- else # channel_allow == nil
136
- can_act = role.permissions.instance_variable_get("@#{action}") || can_act
137
- end
204
+ can_act = if channel_allow.nil?
205
+ role.permissions.instance_variable_get("@#{action}") || can_act
206
+ else
207
+ channel_allow
208
+ end
138
209
  can_act
139
210
  end
140
211
  end
@@ -147,7 +218,8 @@ module Discordrb
147
218
  end
148
219
  end
149
220
 
150
- # A class that represents the bot user itself and has methods to change stuff
221
+ # This class is a special variant of User that represents the bot's user profile (things like email addresses and the avatar).
222
+ # It can be accessed using {Bot#profile}.
151
223
  class Profile < User
152
224
  def initialize(data, bot, email, password)
153
225
  super(data, bot)
@@ -155,22 +227,33 @@ module Discordrb
155
227
  @password = password
156
228
  end
157
229
 
230
+ # Whether or not the user is the bot. The Profile can only ever be the bot user, so this always returns true.
231
+ # @return [true]
158
232
  def bot?
159
233
  true
160
234
  end
161
235
 
236
+ # Sets the bot's username.
237
+ # @param username [String] The new username.
162
238
  def username=(username)
163
239
  update_server_data(username: username)
164
240
  end
165
241
 
242
+ # Sets the bot's email address. If you use this method, make sure that the login email in the script matches this
243
+ # one afterwards, so the bot doesn't have any trouble logging in in the future.
244
+ # @param email [String] The new email address.
166
245
  def email=(email)
167
246
  update_server_data(email: email)
168
247
  end
169
248
 
249
+ # Changes the bot's password. This will invalidate all tokens so you will have to relog the bot.
250
+ # @param password [String] The new password.
170
251
  def password=(password)
171
252
  update_server_data(new_password: password)
172
253
  end
173
254
 
255
+ # Changes the bot's avatar.
256
+ # @param avatar [String, File] A JPG file to be used as the avatar, either as a File object or as a base64-encoded String.
174
257
  def avatar=(avatar)
175
258
  if avatar.is_a? File
176
259
  avatar_string = 'data:image/jpg;base64,'
@@ -181,11 +264,14 @@ module Discordrb
181
264
  end
182
265
  end
183
266
 
267
+ # Updates the cached profile data with the new one.
268
+ # @note For internal use only.
269
+ # @!visibility private
184
270
  def update_data(new_data)
185
271
  @email = new_data[:email] || @email
186
272
  @password = new_data[:new_password] || @password
187
273
  @username = new_data[:username] || @username
188
- @avatar = new_data[:avatar] || @avatar
274
+ @avatar_id = new_data[:avatar_id] || @avatar_id
189
275
  end
190
276
 
191
277
  private
@@ -195,7 +281,7 @@ module Discordrb
195
281
  new_data[:email] || @email,
196
282
  @password,
197
283
  new_data[:username] || @username,
198
- new_data[:avatar] || @avatar,
284
+ new_data[:avatar_id] || @avatar_id,
199
285
  new_data[:new_password] || nil)
200
286
  update_data(new_data)
201
287
  end
@@ -203,21 +289,40 @@ module Discordrb
203
289
 
204
290
  # A Discord role that contains permissions and applies to certain users
205
291
  class Role
206
- attr_reader :permissions, :name, :id, :hoist, :colour
292
+ # @return [Permissions] this role's permissions.
293
+ attr_reader :permissions
294
+
295
+ # @return [String] this role's name ("new role" if it hasn't been changed)
296
+ attr_reader :name
297
+
298
+ # @return [Integer] the ID used to identify this role internally
299
+ attr_reader :id
300
+
301
+ # @return [true, false] whether or not this role should be displayed separately from other users
302
+ attr_reader :hoist
303
+
304
+ # @return [ColourRGB] the role colour
305
+ attr_reader :colour
306
+
207
307
  alias_method :color, :colour
308
+ alias_method :resolve_id, :id
208
309
 
209
- # Class that writes data for a Permissions object
310
+ # This class is used internally as a wrapper to a Role object that allows easy writing of permission data.
210
311
  class RoleWriter
312
+ # @!visibility private
211
313
  def initialize(role, token)
212
314
  @role = role
213
315
  @token = token
214
316
  end
215
317
 
318
+ # Write the specified permission data to the role, without updating the permission cache
319
+ # @param bits [Integer] The packed permissions to write.
216
320
  def write(bits)
217
321
  @role.send(:packed=, bits, false)
218
322
  end
219
323
  end
220
324
 
325
+ # @!visibility private
221
326
  def initialize(data, bot, server = nil)
222
327
  @bot = bot
223
328
  @server = server
@@ -233,6 +338,9 @@ module Discordrb
233
338
  Discordrb.id_compare(@id, other)
234
339
  end
235
340
 
341
+ # Updates the data cache from another Role object
342
+ # @note For internal use only
343
+ # @!visibility private
236
344
  def update_from(other)
237
345
  @permissions = other.permissions
238
346
  @name = other.name
@@ -240,6 +348,9 @@ module Discordrb
240
348
  @colour = other.colour
241
349
  end
242
350
 
351
+ # Updates the data cache from a hash containing data
352
+ # @note For internal use only
353
+ # @!visibility private
243
354
  def update_data(new_data)
244
355
  @name = new_data[:name] || new_data['name'] || @name
245
356
  @hoist = new_data['hoist'] unless new_data['hoist'].nil?
@@ -247,25 +358,35 @@ module Discordrb
247
358
  @colour = new_data[:colour] || (new_data['color'] ? ColourRGB.new(new_data['color']) : @colour)
248
359
  end
249
360
 
361
+ # Sets the role name to something new
362
+ # @param name [String] The name that should be set
250
363
  def name=(name)
251
364
  update_role_data(name: name)
252
365
  end
253
366
 
367
+ # Changes whether or not this role is displayed at the top of the user list
368
+ # @param hoist [true, false] The value it should be changed to
254
369
  def hoist=(hoist)
255
370
  update_role_data(hoist: hoist)
256
371
  end
257
372
 
373
+ # Sets the role colour to something new
374
+ # @param colour [ColourRGB] The new colour
258
375
  def colour=(colour)
259
376
  update_role_data(colour: colour)
260
377
  end
261
378
 
262
379
  alias_method :color=, :colour=
263
380
 
381
+ # Changes the internal packed permissions
382
+ # @note For internal use only
383
+ # @!visibility private
264
384
  def packed=(packed, update_perms = true)
265
385
  update_role_data(permissions: packed)
266
386
  @permissions.bits = packed if update_perms
267
387
  end
268
388
 
389
+ # Delets this role. This cannot be undone without recreating the role!
269
390
  def delete
270
391
  API.delete_role(@bot.token, @server.id, @id)
271
392
  @server.delete_role(@id)
@@ -277,7 +398,7 @@ module Discordrb
277
398
  API.update_role(@bot.token, @server.id, @id,
278
399
  new_data[:name] || @name,
279
400
  (new_data[:colour] || @colour).combined,
280
- !(!(new_data[:hoist].nil? ? new_data[:hoist] : @hoist)),
401
+ new_data[:hoist].nil? ? false : !@hoist.nil?,
281
402
  new_data[:permissions] || @permissions.bits)
282
403
  update_data(new_data)
283
404
  end
@@ -285,7 +406,30 @@ module Discordrb
285
406
 
286
407
  # A Discord invite to a channel
287
408
  class Invite
288
- attr_reader :channel, :uses, :inviter, :temporary, :revoked, :xkcd, :code
409
+ # @return [Channel] the channel this invite references.
410
+ attr_reader :channel
411
+
412
+ # @return [Server] the server this invite references.
413
+ attr_reader :server
414
+
415
+ # @return [Integer] the amount of uses left on this invite.
416
+ attr_reader :uses
417
+
418
+ # @return [User, nil] the user that made this invite. May also be nil if the user can't be determined.
419
+ attr_reader :inviter
420
+
421
+ # @return [true, false] whether or not this invite is temporary.
422
+ attr_reader :temporary
423
+
424
+ # @return [true, false] whether this invite is still valid.
425
+ attr_reader :revoked
426
+
427
+ # @return [true, false] whether this invite is in xkcd format (i. e. "Human readable" in the invite settings)
428
+ attr_reader :xkcd
429
+
430
+ # @return [String] this invite's code
431
+ attr_reader :code
432
+
289
433
  alias_method :max_uses, :uses
290
434
  alias_method :user, :inviter
291
435
 
@@ -293,14 +437,14 @@ module Discordrb
293
437
  alias_method :revoked?, :revoked
294
438
  alias_method :xkcd?, :xkcd
295
439
 
296
- delegate :server, to: :channel
297
-
440
+ # @!visibility private
298
441
  def initialize(data, bot)
299
442
  @bot = bot
300
443
 
301
444
  @channel = Channel.new(data['channel'], bot)
445
+ @server = Server.new(data['guild'], bot)
302
446
  @uses = data['uses']
303
- @inviter = @bot.user(data['inviter']['id'].to_i) || User.new(data['inviter'], bot)
447
+ @inviter = data['inviter'] ? (@bot.user(data['inviter']['id'].to_i) || User.new(data['inviter'], bot)) : nil
304
448
  @temporary = data['temporary']
305
449
  @revoked = data['revoked']
306
450
  @xkcd = data['xkcdpass']
@@ -308,23 +452,63 @@ module Discordrb
308
452
  @code = data['code']
309
453
  end
310
454
 
455
+ # Code based comparison
311
456
  def ==(other)
312
457
  other.respond_to?(:code) ? (@code == other.code) : (@code == other)
313
458
  end
314
459
 
460
+ # Deletes this invite
315
461
  def delete
316
462
  API.delete_invite(@bot.token, @code)
317
463
  end
464
+
465
+ alias_method :revoke, :delete
318
466
  end
319
467
 
320
468
  # A Discord channel, including data like the topic
321
469
  class Channel
322
- attr_reader :name, :server, :type, :id, :is_private, :recipient, :topic, :position, :permission_overwrites
470
+ # @return [String] this channel's name.
471
+ attr_reader :name
472
+
473
+ # @return [Server] the server this channel is on.
474
+ attr_reader :server
475
+
476
+ # @return [String] the type of this channel (currently either 'text' or 'voice')
477
+ attr_reader :type
478
+
479
+ # @note If this channel is a #general channel, its ID will be equal to the server on which it is on.
480
+ # @return [Integer] the channel's unique ID.
481
+ attr_reader :id
482
+
483
+ # @note This data is sent by Discord and it's possible for this to falsely be true for certain kinds of integration
484
+ # channels (like Twitch subscriber ones). This appears to be a Discord bug that I can't reproduce myself, due to
485
+ # not having any integrations in place. If this occurs to you please tell me.
486
+ # @deprecated Use {#private?} instead, it's guaranteed to be accurate.
487
+ # @return [true, false] whether or not this channel is a private messaging channel.
488
+ attr_reader :is_private
489
+
490
+ # @return [User, nil] the recipient of the private messages, or nil if this is not a PM channel
491
+ attr_reader :recipient
492
+
493
+ # @return [String] the channel's topic
494
+ attr_reader :topic
495
+
496
+ # @return [Integer] the channel's position on the channel list
497
+ attr_reader :position
498
+
499
+ # This channel's permission overwrites, represented as a hash of role/user ID to an OpenStruct which has the
500
+ # `allow` and `deny` properties which are {Permissions} objects respectively.
501
+ # @return [Hash<Integer => OpenStruct>] the channel's permission overwrites
502
+ attr_reader :permission_overwrites
323
503
 
504
+ alias_method :resolve_id, :id
505
+
506
+ # @return [true, false] whether or not this channel is a PM channel, with more accuracy than {#is_private}.
324
507
  def private?
325
508
  @server.nil?
326
509
  end
327
510
 
511
+ # @!visibility private
328
512
  def initialize(data, bot, server = nil)
329
513
  @bot = bot
330
514
 
@@ -364,33 +548,48 @@ module Discordrb
364
548
  Discordrb.id_compare(@id, other)
365
549
  end
366
550
 
551
+ # Sends a message to this channel.
552
+ # @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
553
+ # @return [Message] the message that was sent.
367
554
  def send_message(content)
368
555
  @bot.send_message(@id, content)
369
556
  end
370
557
 
558
+ # Sends a file to this channel. If it is an image, it will be embedded.
559
+ # @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)
371
560
  def send_file(file)
372
561
  @bot.send_file(@id, file)
373
562
  end
374
563
 
564
+ # Permanently deletes this channel
375
565
  def delete
376
566
  API.delete_channel(@bot.token, @id)
377
567
  end
378
568
 
569
+ # Sets this channel's name. The name must be alphanumeric with dashes, unless this is a voice channel (then there are no limitations)
570
+ # @param name [String] The new name.
379
571
  def name=(name)
380
572
  @name = name
381
573
  update_channel_data
382
574
  end
383
575
 
576
+ # Sets this channel's topic.
577
+ # @param topic [String] The new topic.
384
578
  def topic=(topic)
385
579
  @topic = topic
386
580
  update_channel_data
387
581
  end
388
582
 
583
+ # Sets this channel's position in the list.
584
+ # @param position [Integer] The new position.
389
585
  def position=(position)
390
586
  @position = position
391
587
  update_channel_data
392
588
  end
393
589
 
590
+ # Updates the cached data from another channel.
591
+ # @note For internal use only
592
+ # @!visibility private
394
593
  def update_from(other)
395
594
  @topic = other.topic
396
595
  @name = other.name
@@ -399,7 +598,9 @@ module Discordrb
399
598
  @permission_overwrites = other.permission_overwrites
400
599
  end
401
600
 
402
- # List of users currently in a channel
601
+ # The list of users currently in this channel. This is mostly useful for a voice channel, for a text channel it will
602
+ # just return the users on the server that are online.
603
+ # @return [Array<User>] the users in this channel
403
604
  def users
404
605
  if @type == 'text'
405
606
  @server.members.select { |u| u.status != :offline }
@@ -410,16 +611,29 @@ module Discordrb
410
611
  end
411
612
  end
412
613
 
614
+ # Retrieves some of this channel's message history.
615
+ # @param amount [Integer] How many messages to retrieve. This must be less than or equal to 100, if it is higher
616
+ # than 100 it will be treated as 100 on Discord's side.
617
+ # @param before_id [Integer] The ID of the most recent message the retrieval should start at, or nil if it should
618
+ # start at the current message.
619
+ # @param after_id [Integer] The ID of the oldest message the retrieval should start at, or nil if it should start
620
+ # as soon as possible with the specified amount.
621
+ # @return [Array<Message>] the retrieved messages.
413
622
  def history(amount, before_id = nil, after_id = nil)
414
623
  logs = API.channel_log(@bot.token, @id, amount, before_id, after_id)
415
624
  JSON.parse(logs).map { |message| Message.new(message, @bot) }
416
625
  end
417
626
 
627
+ # Updates the cached permission overwrites
628
+ # @note For internal use only
629
+ # @!visibility private
418
630
  def update_overwrites(overwrites)
419
631
  @permission_overwrites = overwrites
420
632
  end
421
633
 
422
- # Add an await for a message in this channel
634
+ # Add an {Await} for a message in this channel. This is identical in functionality to adding a
635
+ # {Discordrb::Events::MessageEvent} await with the `in` attribute as this channel.
636
+ # @see Bot#add_await
423
637
  def await(key, attributes = {}, &block)
424
638
  @bot.add_await(key, Discordrb::Events::MessageEvent, { in: @id }.merge(attributes), &block)
425
639
  end
@@ -449,11 +663,30 @@ module Discordrb
449
663
 
450
664
  # A message on Discord that was sent to a text channel
451
665
  class Message
452
- attr_reader :content, :author, :channel, :timestamp, :id, :mentions
666
+ # @return [String] the content of this message.
667
+ attr_reader :content
668
+
669
+ # @return [User] the user that sent this message.
670
+ attr_reader :author
671
+
672
+ # @return [Channel] the channel in which this message was sent.
673
+ attr_reader :channel
674
+
675
+ # @return [Time] the timestamp at which this message was sent.
676
+ attr_reader :timestamp
677
+
678
+ # @return [Integer] the ID used to uniquely identify this message.
679
+ attr_reader :id
680
+
681
+ # @return [Array<User>] the users that were mentioned in this message.
682
+ attr_reader :mentions
683
+
453
684
  alias_method :user, :author
454
685
  alias_method :text, :content
455
686
  alias_method :to_s, :content
687
+ alias_method :resolve_id, :id
456
688
 
689
+ # @!visibility private
457
690
  def initialize(data, bot)
458
691
  @bot = bot
459
692
  @content = data['content']
@@ -474,23 +707,30 @@ module Discordrb
474
707
  Discordrb.id_compare(@id, other)
475
708
  end
476
709
 
710
+ # Replies to this message with the specified content.
711
+ # @see Channel#send_message
477
712
  def reply(content)
478
713
  @channel.send_message(content)
479
714
  end
480
715
 
716
+ # Edits this message to have the specified content instead.
717
+ # @param new_content [String] the new content the message should have.
481
718
  def edit(new_content)
482
719
  API.edit_message(@bot.token, @channel.id, @id, new_content)
483
720
  end
484
721
 
722
+ # Deletes this message.
485
723
  def delete
486
724
  API.delete_message(@bot.token, @channel.id, @id)
487
725
  end
488
726
 
489
- # Add an await for a message with the same user and channel
727
+ # Add an {Await} for a message with the same user and channel.
728
+ # @see Bot#add_await
490
729
  def await(key, attributes = {}, &block)
491
730
  @bot.add_await(key, Discordrb::Events::MessageEvent, { from: @author.id, in: @channel.id }.merge(attributes), &block)
492
731
  end
493
732
 
733
+ # @return [true, false] whether this message was sent by the current {Bot}.
494
734
  def from_bot?
495
735
  @author.bot?
496
736
  end
@@ -498,11 +738,49 @@ module Discordrb
498
738
 
499
739
  # A server on Discord
500
740
  class Server
501
- attr_reader :region, :name, :owner_id, :id, :members, :channels, :roles, :icon, :afk_timeout, :afk_channel_id
741
+ # @return [String] the region the server is on (e. g. `amsterdam`).
742
+ attr_reader :region
743
+
744
+ # @return [String] this server's name.
745
+ attr_reader :name
746
+
747
+ # @deprecated Use #owner instead, then get the resulting {User}'s {User#id}.
748
+ # @return [Integer] the server owner's user ID.
749
+ attr_reader :owner_id
750
+
751
+ # @return [User] The server owner.
752
+ attr_reader :owner
753
+
754
+ # @return [Integer] the ID used to uniquely identify this server.
755
+ attr_reader :id
756
+
757
+ # @return [Array<User>] an array of all the users on this server.
758
+ attr_reader :members
502
759
 
760
+ # @return [Array<Channel>] an array of all the channels (text and voice) on this server.
761
+ attr_reader :channels
762
+
763
+ # @return [Array<Role>] an array of all the roles created on this server.
764
+ attr_reader :roles
765
+
766
+ # @todo Make this behave like user.avatar where a URL is available as well.
767
+ # @return [String] the hexadecimal ID used to identify this server's icon.
768
+ attr_reader :icon
769
+
770
+ # @return [Integer] the amount of time after which a voice user gets moved into the AFK channel, in seconds.
771
+ attr_reader :afk_timeout
772
+
773
+ # @todo Make this a reader that returns a {Channel}
774
+ # @return [Integer] the channel ID of the AFK channel, or `nil` if none is set.
775
+ attr_reader :afk_channel_id
776
+
777
+ alias_method :resolve_id, :id
778
+
779
+ # @!visibility private
503
780
  def initialize(data, bot)
504
781
  @bot = bot
505
782
  @owner_id = data['owner_id'].to_i
783
+ @owner = bot.user(@owner_id)
506
784
  @id = data['id'].to_i
507
785
  update_data(data)
508
786
 
@@ -518,85 +796,29 @@ module Discordrb
518
796
  Discordrb.id_compare(@id, other)
519
797
  end
520
798
 
521
- def process_roles(roles)
522
- # Create roles
523
- @roles = []
524
- @roles_by_id = {}
525
- roles.each do |element|
526
- role = Role.new(element, @bot, self)
527
- @roles << role
528
- @roles_by_id[role.id] = role
529
- end
530
- end
531
-
532
- def process_members(members)
533
- @members = []
534
- @members_by_id = {}
535
-
536
- return unless members
537
- members.each do |element|
538
- user = User.new(element['user'], @bot)
539
- @members << user
540
- @members_by_id[user.id] = user
541
- user_roles = []
542
- element['roles'].each do |e|
543
- role_id = e.to_i
544
- user_roles << @roles_by_id[role_id]
545
- end
546
- user.update_roles(self, user_roles)
547
- end
548
- end
549
-
550
- def process_presences(presences)
551
- # Update user statuses with presence info
552
- return unless presences
553
- presences.each do |element|
554
- next unless element['user']
555
- user_id = element['user']['id'].to_i
556
- user = @members_by_id[user_id]
557
- if user
558
- user.status = element['status'].to_sym
559
- user.game = element['game'] ? element['game']['name'] : nil
560
- end
561
- end
562
- end
563
-
564
- def process_channels(channels)
565
- @channels = []
566
- @channels_by_id = {}
567
-
568
- return unless channels
569
- channels.each do |element|
570
- channel = Channel.new(element, @bot, self)
571
- @channels << channel
572
- @channels_by_id[channel.id] = channel
573
- end
799
+ # @return [Channel] The default channel on this server (usually called #general)
800
+ def default_channel
801
+ @bot.channel(@id)
574
802
  end
575
803
 
576
- def process_voice_states(voice_states)
577
- return unless voice_states
578
- voice_states.each do |element|
579
- user_id = element['user_id'].to_i
580
- user = @members_by_id[user_id]
581
- next unless user
582
- user.server_mute = element['mute']
583
- user.server_deaf = element['deaf']
584
- user.self_mute = element['self_mute']
585
- user.self_mute = element['self_mute']
586
- channel_id = element['channel_id'].to_i
587
- channel = channel_id ? @channels_by_id[channel_id] : nil
588
- user.move(channel)
589
- end
590
- end
804
+ alias_method :general_channel, :default_channel
591
805
 
806
+ # Gets a role on this server based on its ID.
807
+ # @param id [Integer] The role ID to look for.
592
808
  def role(id)
593
809
  @roles.find { |e| e.id == id }
594
810
  end
595
811
 
812
+ # Adds a role to the role cache
813
+ # @note For internal use only
814
+ # @!visibility private
596
815
  def add_role(role)
597
816
  @roles << role
598
817
  end
599
818
 
819
+ # Removes a role from the role cache
820
+ # @note For internal use only
821
+ # @!visibility private
600
822
  def delete_role(role_id)
601
823
  @roles.reject! { |r| r.id == role_id }
602
824
  @members.each do |user|
@@ -609,19 +831,31 @@ module Discordrb
609
831
  end
610
832
  end
611
833
 
834
+ # Adds a user to the user cache.
835
+ # @note For internal use only
836
+ # @!visibility private
612
837
  def add_user(user)
613
838
  @members << user
614
839
  end
615
840
 
841
+ # Removes a user from the user cache.
842
+ # @note For internal use only
843
+ # @!visibility private
616
844
  def delete_user(user_id)
617
845
  @members.reject! { |member| member.id == user_id }
618
846
  end
619
847
 
848
+ # Creates a channel on this server with the given name.
849
+ # @return [Channel] the created channel.
620
850
  def create_channel(name)
621
851
  response = API.create_channel(@bot.token, @id, name, 'text')
622
852
  Channel.new(JSON.parse(response), @bot)
623
853
  end
624
854
 
855
+ # Creates a role on this server which can then be modified. It will be initialized (on Discord's side)
856
+ # with the regular role defaults the client uses, i. e. name is "new role", permissions are the default,
857
+ # colour is the default etc.
858
+ # @return [Role] the created role.
625
859
  def create_role
626
860
  response = API.create_role(@bot.token, @id)
627
861
  role = Role.new(JSON.parse(response), @bot)
@@ -629,56 +863,94 @@ module Discordrb
629
863
  role
630
864
  end
631
865
 
866
+ # Bans a user from this server.
867
+ # @param user [User] The user to ban.
868
+ # @param message_days [Integer] How many days worth of messages sent by the user should be deleted.
632
869
  def ban(user, message_days = 0)
633
870
  API.ban_user(@bot.token, @id, user.id, message_days)
634
871
  end
635
872
 
873
+ # Unbans a previously banned user from this server.
874
+ # @param user [User] The user to unban.
636
875
  def unban(user)
637
876
  API.unban_user(@bot.token, @id, user.id)
638
877
  end
639
878
 
879
+ # Kicks a user from this server.
880
+ # @param user [User] The user to kick.
640
881
  def kick(user)
641
882
  API.kick_user(@bot.token, @id, user.id)
642
883
  end
643
884
 
885
+ # Forcibly moves a user into a different voice channel. Only works if the bot has the permission needed.
886
+ # @param user [User] The user to move.
887
+ # @param channel [Channel] The voice channel to move into.
888
+ def move(user, channel)
889
+ API.move_user(@bot.token, @id, user.id, channel.id)
890
+ end
891
+
892
+ # Deletes this server. Be aware that this is permanent and impossible to undo, so be careful!
644
893
  def delete
645
894
  API.delete_server(@bot.token, @id)
646
895
  end
647
896
 
897
+ # Leave the server - to Discord, leaving a server and deleting it are the same, so be careful if the bot
898
+ # is the server owner!
648
899
  alias_method :leave, :delete
649
900
 
901
+ # Transfers server ownership to another user.
902
+ # @param user [User] The user who should become the new owner.
903
+ def owner=(user)
904
+ API.transfer_ownership(@bot.token, @id, user.id)
905
+ end
906
+
907
+ # Sets the server's name.
908
+ # @param name [String] The new server name.
650
909
  def name=(name)
651
910
  update_server_data(name: name)
652
911
  end
653
912
 
913
+ # Moves the server to another region. This will cause a voice interruption of at most a second.
914
+ # @param region [String] The new region the server should be in.
654
915
  def region=(region)
655
916
  update_server_data(region: region.to_s)
656
917
  end
657
918
 
919
+ # Sets the server's icon.
920
+ # @todo Make this behave in a similar way to User#avatar=.
921
+ # @param icon [String] The new icon, in base64-encoded JPG format.
658
922
  def icon=(icon)
659
923
  update_server_data(icon: icon)
660
924
  end
661
925
 
926
+ # Sets the server's AFK channel.
927
+ # @param afk_channel [Channel, nil] The new AFK channel, or `nil` if there should be none set.
662
928
  def afk_channel=(afk_channel)
663
- update_server_data(afk_channel_id: afk_channel.id)
929
+ update_server_data(afk_channel_id: afk_channel.resolve_id)
664
930
  end
665
931
 
932
+ # @deprecated Use #afk_channel= with the ID instead.
666
933
  def afk_channel_id=(afk_channel_id)
667
934
  update_server_data(afk_channel_id: afk_channel_id)
668
935
  end
669
936
 
937
+ # Sets the amount of time after which a user gets moved into the AFK channel.
938
+ # @param afk_timeout [Integer] The AFK timeout, in seconds.
670
939
  def afk_timeout=(afk_timeout)
671
940
  update_server_data(afk_timeout: afk_timeout)
672
941
  end
673
942
 
943
+ # Updates the cached data with new data
944
+ # @note For internal use only
945
+ # @!visibility private
674
946
  def update_data(new_data)
675
947
  @name = new_data[:name] || new_data['name'] || @name
676
948
  @region = new_data[:region] || new_data['region'] || @region
677
949
  @icon = new_data[:icon] || new_data['icon'] || @icon
678
950
  @afk_timeout = new_data[:afk_timeout] || new_data['afk_timeout'].to_i || @afk_timeout
679
951
 
680
- afk_channel_id = new_data[:afk_channel_id] || new_data['afk_channel_id'].to_i || @afk_channel.id
681
- @afk_channel = @bot.channel(afk_channel_id) if afk_channel_id != 0 && (!@afk_channel || afk_channel_id != @afk_channel.id)
952
+ @afk_channel_id = new_data[:afk_channel_id] || new_data['afk_channel_id'].to_i || @afk_channel.id
953
+ @afk_channel = @bot.channel(@afk_channel_id) if @afk_channel_id != 0 && (!@afk_channel || @afk_channel_id != @afk_channel.id)
682
954
  end
683
955
 
684
956
  private
@@ -692,12 +964,98 @@ module Discordrb
692
964
  new_data[:afk_timeout] || @afk_timeout)
693
965
  update_data(new_data)
694
966
  end
967
+
968
+ def process_roles(roles)
969
+ # Create roles
970
+ @roles = []
971
+ @roles_by_id = {}
972
+
973
+ return unless roles
974
+ roles.each do |element|
975
+ role = Role.new(element, @bot, self)
976
+ @roles << role
977
+ @roles_by_id[role.id] = role
978
+ end
979
+ end
980
+
981
+ def process_members(members)
982
+ @members = []
983
+ @members_by_id = {}
984
+
985
+ return unless members
986
+ members.each do |element|
987
+ user = User.new(element['user'], @bot)
988
+ @members << user
989
+ @members_by_id[user.id] = user
990
+ user_roles = []
991
+ element['roles'].each do |e|
992
+ role_id = e.to_i
993
+ user_roles << @roles_by_id[role_id]
994
+ end
995
+ user.update_roles(self, user_roles)
996
+ end
997
+ end
998
+
999
+ def process_presences(presences)
1000
+ # Update user statuses with presence info
1001
+ return unless presences
1002
+ presences.each do |element|
1003
+ next unless element['user']
1004
+ user_id = element['user']['id'].to_i
1005
+ user = @members_by_id[user_id]
1006
+ if user
1007
+ user.status = element['status'].to_sym
1008
+ user.game = element['game'] ? element['game']['name'] : nil
1009
+ end
1010
+ end
1011
+ end
1012
+
1013
+ def process_channels(channels)
1014
+ @channels = []
1015
+ @channels_by_id = {}
1016
+
1017
+ return unless channels
1018
+ channels.each do |element|
1019
+ channel = Channel.new(element, @bot, self)
1020
+ @channels << channel
1021
+ @channels_by_id[channel.id] = channel
1022
+ end
1023
+ end
1024
+
1025
+ def process_voice_states(voice_states)
1026
+ return unless voice_states
1027
+ voice_states.each do |element|
1028
+ user_id = element['user_id'].to_i
1029
+ user = @members_by_id[user_id]
1030
+ next unless user
1031
+ user.server_mute = element['mute']
1032
+ user.server_deaf = element['deaf']
1033
+ user.self_mute = element['self_mute']
1034
+ user.self_mute = element['self_mute']
1035
+ channel_id = element['channel_id'].to_i
1036
+ channel = channel_id ? @channels_by_id[channel_id] : nil
1037
+ user.move(channel)
1038
+ end
1039
+ end
695
1040
  end
696
1041
 
697
- # A colour (red, green and blue values). Used for role colours
1042
+ # A colour (red, green and blue values). Used for role colours. If you prefer the American spelling, the alias
1043
+ # {ColorRGB} is also available.
698
1044
  class ColourRGB
699
- attr_reader :red, :green, :blue, :combined
1045
+ # @return [Integer] the red part of this colour (0-255).
1046
+ attr_reader :red
1047
+
1048
+ # @return [Integer] the green part of this colour (0-255).
1049
+ attr_reader :green
1050
+
1051
+ # @return [Integer] the blue part of this colour (0-255).
1052
+ attr_reader :blue
1053
+
1054
+ # @return [Integer] the colour's RGB values combined into one integer.
1055
+ attr_reader :combined
700
1056
 
1057
+ # Make a new colour from the combined value.
1058
+ # @param combined [Integer] The colour's RGB values combined into one integer
701
1059
  def initialize(combined)
702
1060
  @combined = combined
703
1061
  @red = (combined >> 16) & 0xFF
@@ -706,5 +1064,6 @@ module Discordrb
706
1064
  end
707
1065
  end
708
1066
 
1067
+ # Alias for the class {ColourRGB}
709
1068
  ColorRGB = ColourRGB
710
1069
  end