discordrb 3.4.3 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +13 -0
  3. data/.devcontainer/devcontainer.json +29 -0
  4. data/.devcontainer/postcreate.sh +4 -0
  5. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
  6. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
  7. data/.github/workflows/ci.yml +78 -0
  8. data/.github/workflows/codeql.yml +65 -0
  9. data/.github/workflows/deploy.yml +54 -0
  10. data/.github/workflows/release.yml +45 -0
  11. data/.markdownlint.json +4 -0
  12. data/.rubocop.yml +58 -2
  13. data/CHANGELOG.md +485 -225
  14. data/LICENSE.txt +1 -1
  15. data/README.md +38 -26
  16. data/discordrb-webhooks.gemspec +4 -1
  17. data/discordrb.gemspec +18 -10
  18. data/lib/discordrb/api/application.rb +278 -0
  19. data/lib/discordrb/api/channel.rb +222 -18
  20. data/lib/discordrb/api/interaction.rb +63 -0
  21. data/lib/discordrb/api/invite.rb +2 -2
  22. data/lib/discordrb/api/server.rb +123 -66
  23. data/lib/discordrb/api/user.rb +20 -5
  24. data/lib/discordrb/api/webhook.rb +72 -0
  25. data/lib/discordrb/api.rb +35 -25
  26. data/lib/discordrb/bot.rb +437 -66
  27. data/lib/discordrb/cache.rb +41 -22
  28. data/lib/discordrb/commands/command_bot.rb +13 -21
  29. data/lib/discordrb/commands/container.rb +1 -1
  30. data/lib/discordrb/commands/parser.rb +7 -7
  31. data/lib/discordrb/commands/rate_limiter.rb +1 -1
  32. data/lib/discordrb/container.rb +178 -3
  33. data/lib/discordrb/data/activity.rb +1 -1
  34. data/lib/discordrb/data/application.rb +1 -0
  35. data/lib/discordrb/data/attachment.rb +38 -3
  36. data/lib/discordrb/data/audit_logs.rb +3 -3
  37. data/lib/discordrb/data/avatar_decoration.rb +26 -0
  38. data/lib/discordrb/data/call.rb +22 -0
  39. data/lib/discordrb/data/channel.rb +299 -30
  40. data/lib/discordrb/data/collectibles.rb +45 -0
  41. data/lib/discordrb/data/component.rb +229 -0
  42. data/lib/discordrb/data/embed.rb +10 -3
  43. data/lib/discordrb/data/emoji.rb +20 -1
  44. data/lib/discordrb/data/integration.rb +45 -3
  45. data/lib/discordrb/data/interaction.rb +937 -0
  46. data/lib/discordrb/data/invite.rb +1 -1
  47. data/lib/discordrb/data/member.rb +236 -44
  48. data/lib/discordrb/data/message.rb +278 -51
  49. data/lib/discordrb/data/overwrite.rb +15 -7
  50. data/lib/discordrb/data/primary_server.rb +60 -0
  51. data/lib/discordrb/data/profile.rb +2 -7
  52. data/lib/discordrb/data/reaction.rb +2 -1
  53. data/lib/discordrb/data/recipient.rb +1 -1
  54. data/lib/discordrb/data/role.rb +204 -18
  55. data/lib/discordrb/data/server.rb +194 -118
  56. data/lib/discordrb/data/server_preview.rb +68 -0
  57. data/lib/discordrb/data/snapshot.rb +110 -0
  58. data/lib/discordrb/data/user.rb +132 -12
  59. data/lib/discordrb/data/voice_region.rb +1 -0
  60. data/lib/discordrb/data/webhook.rb +99 -9
  61. data/lib/discordrb/data.rb +9 -0
  62. data/lib/discordrb/errors.rb +47 -3
  63. data/lib/discordrb/events/await.rb +1 -1
  64. data/lib/discordrb/events/channels.rb +38 -1
  65. data/lib/discordrb/events/generic.rb +2 -0
  66. data/lib/discordrb/events/guilds.rb +6 -1
  67. data/lib/discordrb/events/interactions.rb +575 -0
  68. data/lib/discordrb/events/invites.rb +2 -0
  69. data/lib/discordrb/events/members.rb +19 -2
  70. data/lib/discordrb/events/message.rb +42 -8
  71. data/lib/discordrb/events/presence.rb +23 -14
  72. data/lib/discordrb/events/raw.rb +1 -0
  73. data/lib/discordrb/events/reactions.rb +2 -1
  74. data/lib/discordrb/events/roles.rb +2 -0
  75. data/lib/discordrb/events/threads.rb +100 -0
  76. data/lib/discordrb/events/typing.rb +1 -0
  77. data/lib/discordrb/events/voice_server_update.rb +1 -0
  78. data/lib/discordrb/events/voice_state_update.rb +1 -0
  79. data/lib/discordrb/events/webhooks.rb +1 -0
  80. data/lib/discordrb/gateway.rb +57 -28
  81. data/lib/discordrb/paginator.rb +3 -3
  82. data/lib/discordrb/permissions.rb +71 -35
  83. data/lib/discordrb/version.rb +1 -1
  84. data/lib/discordrb/voice/encoder.rb +2 -2
  85. data/lib/discordrb/voice/network.rb +18 -7
  86. data/lib/discordrb/voice/sodium.rb +3 -1
  87. data/lib/discordrb/voice/voice_bot.rb +3 -3
  88. data/lib/discordrb/webhooks.rb +2 -0
  89. data/lib/discordrb/websocket.rb +0 -10
  90. data/lib/discordrb.rb +54 -5
  91. metadata +87 -25
  92. data/.circleci/config.yml +0 -126
  93. data/.codeclimate.yml +0 -16
  94. data/.travis.yml +0 -32
  95. data/bin/travis_build_docs.sh +0 -17
@@ -100,7 +100,7 @@ module Discordrb
100
100
  end
101
101
 
102
102
  @uses = data['uses']
103
- @inviter = data['inviter'] ? (@bot.user(data['inviter']['id'].to_i) || User.new(data['inviter'], bot)) : nil
103
+ @inviter = data['inviter'] ? bot.ensure_user(data['inviter']) : nil
104
104
  @temporary = data['temporary']
105
105
  @revoked = data['revoked']
106
106
  @online_member_count = data['approximate_presence_count']
@@ -3,6 +3,19 @@
3
3
  module Discordrb
4
4
  # Mixin for the attributes members and private members should have
5
5
  module MemberAttributes
6
+ # Map of server member flags
7
+ MEMBER_FLAGS = {
8
+ rejoined: 1 << 0,
9
+ completed_onboarding: 1 << 1,
10
+ bypassed_verification: 1 << 2,
11
+ started_onboarding: 1 << 3,
12
+ guest: 1 << 4,
13
+ started_home_actions: 1 << 5,
14
+ completed_home_actions: 1 << 6,
15
+ automod_quarantined_username: 1 << 7,
16
+ dm_settings_upsell_acknowledged: 1 << 9
17
+ }.freeze
18
+
6
19
  # @return [Time] when this member joined the server.
7
20
  attr_reader :joined_at
8
21
 
@@ -18,6 +31,48 @@ module Discordrb
18
31
 
19
32
  # @return [Server] the server this member is on.
20
33
  attr_reader :server
34
+
35
+ # @return [Time] When the user's timeout will expire.
36
+ attr_reader :communication_disabled_until
37
+ alias_method :timeout, :communication_disabled_until
38
+
39
+ # @return [Integer] the flags set on this member.
40
+ attr_reader :flags
41
+
42
+ # @return [true, false] whether the member has not yet passed the server's membership screening requirements.
43
+ attr_reader :pending
44
+ alias_method :pending?, :pending
45
+
46
+ # @return [String, nil] the ID of this user's current avatar, can be used to generate a server avatar URL.
47
+ # @see #server_avatar_url
48
+ attr_reader :server_avatar_id
49
+
50
+ # @return [String, nil] the ID of this user's current server banner, can be used to generate a banner URL.
51
+ # @see #server_banner_url
52
+ attr_reader :server_banner_id
53
+
54
+ # @return [AvatarDecoration, nil] the user's current server avatar decoration, or nil for no server avatar decoration.
55
+ attr_reader :server_avatar_decoration
56
+
57
+ # Utility method to get a member's server avatar URL.
58
+ # @param format [String, nil] If `nil`, the URL will default to `webp` for static avatars, and will detect if the member has a `gif` avatar. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this.
59
+ # @return [String, nil] the URL to the avatar image, or nil if the member doesn't have one.
60
+ def server_avatar_url(format = nil)
61
+ API::Server.avatar_url(@server_id, @user.id, @server_avatar_id, format) if @server_avatar_id
62
+ end
63
+
64
+ # Utility method to get a member's server banner URL.
65
+ # @param format [String, nil] If `nil`, the URL will default to `webp` for static banners, and will detect if the member has a `gif` banner. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this.
66
+ # @return [String, nil] the URL to the banner image, or nil if the member doesn't have one.
67
+ def server_banner_url(format = nil)
68
+ API::Server.banner_url(@server_id, @user.id, @server_banner_id, format) if @server_banner_id
69
+ end
70
+
71
+ MEMBER_FLAGS.each do |name, value|
72
+ define_method("#{name}?") do
73
+ @flags.anybits?(value)
74
+ end
75
+ end
21
76
  end
22
77
 
23
78
  # A member is a user on a server. It differs from regular users in that it has roles, voice statuses and things like
@@ -60,19 +115,46 @@ module Discordrb
60
115
  @bot = bot
61
116
 
62
117
  @user = bot.ensure_user(data['user'])
63
- super @user # Initialize the delegate class
64
-
65
- # Somehow, Discord doesn't send the server ID in the standard member format...
66
- raise ArgumentError, 'Cannot create a member without any information about the server!' if server.nil? && data['guild_id'].nil?
118
+ super(@user) # Initialize the delegate class
67
119
 
68
- @server = server || bot.server(data['guild_id'].to_i)
120
+ @server = server
121
+ @server_id = server&.id || data['guild_id'].to_i
69
122
 
70
- # Initialize the roles by getting the roles from the server one-by-one
71
- update_roles(data['roles'])
123
+ @role_ids = data['roles']&.map(&:to_i) || []
72
124
 
73
125
  @nick = data['nick']
74
126
  @joined_at = data['joined_at'] ? Time.parse(data['joined_at']) : nil
75
127
  @boosting_since = data['premium_since'] ? Time.parse(data['premium_since']) : nil
128
+ timeout_until = data['communication_disabled_until']
129
+ @communication_disabled_until = timeout_until ? Time.parse(timeout_until) : nil
130
+ @permissions = Permissions.new(data['permissions']) if data['permissions']
131
+ @server_avatar_id = data['avatar']
132
+ @server_banner_id = data['banner']
133
+ @flags = data['flags'] || 0
134
+ @pending = data.key?('pending') ? data['pending'] : false
135
+ @server_avatar_decoration = process_avatar_decoration(data['avatar_decoration_data'])
136
+ end
137
+
138
+ # @return [Server] the server this member is on.
139
+ # @raise [Discordrb::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
140
+ # authorized with the `bot` scope.
141
+ def server
142
+ return @server if @server
143
+
144
+ @server = @bot.server(@server_id)
145
+ raise Discordrb::Errors::NoPermission, 'The bot does not have access to this server' unless @server
146
+
147
+ @server
148
+ end
149
+
150
+ # @return [Array<Role>] the roles this member has.
151
+ # @raise [Discordrb::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
152
+ # authorized with the `bot` scope.
153
+ def roles
154
+ return @roles if @roles
155
+
156
+ update_roles(@role_ids)
157
+ @roles
76
158
  end
77
159
 
78
160
  # @return [true, false] if this user is a Nitro Booster of this server.
@@ -82,14 +164,14 @@ module Discordrb
82
164
 
83
165
  # @return [true, false] whether this member is the server owner.
84
166
  def owner?
85
- @server.owner == self
167
+ server.owner == self
86
168
  end
87
169
 
88
170
  # @param role [Role, String, Integer] the role to check or its ID.
89
171
  # @return [true, false] whether this member has the specified role.
90
172
  def role?(role)
91
173
  role = role.resolve_id
92
- @roles.any? { |e| e.id == role }
174
+ roles.any?(role)
93
175
  end
94
176
 
95
177
  # @see Member#set_roles
@@ -97,12 +179,30 @@ module Discordrb
97
179
  set_roles(role)
98
180
  end
99
181
 
182
+ # Check if the current user has communication disabled.
183
+ # @return [true, false]
184
+ def communication_disabled?
185
+ !@communication_disabled_until.nil? && @communication_disabled_until > Time.now
186
+ end
187
+
188
+ alias_method :timeout?, :communication_disabled?
189
+
190
+ # Set a user's timeout duration, or remove it by setting the timeout to `nil`.
191
+ # @param timeout_until [Time, nil] When the timeout will end.
192
+ def communication_disabled_until=(timeout_until)
193
+ raise ArgumentError, 'A time out cannot exceed 28 days' if timeout_until && timeout_until > (Time.now + 2_419_200)
194
+
195
+ update_member_data(communication_disabled_until: timeout_until&.iso8601)
196
+ end
197
+
198
+ alias_method :timeout=, :communication_disabled_until=
199
+
100
200
  # Bulk sets a member's roles.
101
201
  # @param role [Role, Array<Role>] The role(s) to set.
102
202
  # @param reason [String] The reason the user's roles are being changed.
103
203
  def set_roles(role, reason = nil)
104
204
  role_ids = role_id_array(role)
105
- API::Server.update_member(@bot.token, @server.id, @user.id, roles: role_ids, reason: reason)
205
+ update_member_data(roles: role_ids, reason: reason)
106
206
  end
107
207
 
108
208
  # Adds and removes roles from a member.
@@ -116,10 +216,10 @@ module Discordrb
116
216
  def modify_roles(add, remove, reason = nil)
117
217
  add_role_ids = role_id_array(add)
118
218
  remove_role_ids = role_id_array(remove)
119
- old_role_ids = @roles.map(&:id)
219
+ old_role_ids = resolve_role_ids
120
220
  new_role_ids = (old_role_ids - remove_role_ids + add_role_ids).uniq
121
221
 
122
- API::Server.update_member(@bot.token, @server.id, @user.id, roles: new_role_ids, reason: reason)
222
+ update_member_data(roles: new_role_ids, reason: reason)
123
223
  end
124
224
 
125
225
  # Adds one or more roles to this member.
@@ -128,12 +228,12 @@ module Discordrb
128
228
  def add_role(role, reason = nil)
129
229
  role_ids = role_id_array(role)
130
230
 
131
- if role_ids.count == 1
132
- API::Server.add_member_role(@bot.token, @server.id, @user.id, role_ids[0], reason)
231
+ if role_ids.count.one?
232
+ API::Server.add_member_role(@bot.token, @server_id, @user.id, role_ids[0], reason)
133
233
  else
134
- old_role_ids = @roles.map(&:id)
234
+ old_role_ids = resolve_role_ids
135
235
  new_role_ids = (old_role_ids + role_ids).uniq
136
- API::Server.update_member(@bot.token, @server.id, @user.id, roles: new_role_ids, reason: reason)
236
+ update_member_data(roles: new_role_ids, reason: reason)
137
237
  end
138
238
  end
139
239
 
@@ -143,23 +243,23 @@ module Discordrb
143
243
  def remove_role(role, reason = nil)
144
244
  role_ids = role_id_array(role)
145
245
 
146
- if role_ids.count == 1
147
- API::Server.remove_member_role(@bot.token, @server.id, @user.id, role_ids[0], reason)
246
+ if role_ids.count.one?
247
+ API::Server.remove_member_role(@bot.token, @server_id, @user.id, role_ids[0], reason)
148
248
  else
149
- old_role_ids = @roles.map(&:id)
249
+ old_role_ids = resolve_role_ids
150
250
  new_role_ids = old_role_ids.reject { |i| role_ids.include?(i) }
151
- API::Server.update_member(@bot.token, @server.id, @user.id, roles: new_role_ids, reason: reason)
251
+ update_member_data(roles: new_role_ids, reason: reason)
152
252
  end
153
253
  end
154
254
 
155
255
  # @return [Role] the highest role this member has.
156
256
  def highest_role
157
- @roles.max_by(&:position)
257
+ roles.max_by(&:position)
158
258
  end
159
259
 
160
260
  # @return [Role, nil] the role this member is being hoisted with.
161
261
  def hoist_role
162
- hoisted_roles = @roles.select(&:hoist)
262
+ hoisted_roles = roles.select(&:hoist)
163
263
  return nil if hoisted_roles.empty?
164
264
 
165
265
  hoisted_roles.max_by(&:position)
@@ -167,11 +267,12 @@ module Discordrb
167
267
 
168
268
  # @return [Role, nil] the role this member is basing their colour on.
169
269
  def colour_role
170
- coloured_roles = @roles.select { |v| v.colour.combined.nonzero? }
270
+ coloured_roles = roles.select { |v| v.colour.combined.nonzero? }
171
271
  return nil if coloured_roles.empty?
172
272
 
173
273
  coloured_roles.max_by(&:position)
174
274
  end
275
+
175
276
  alias_method :color_role, :colour_role
176
277
 
177
278
  # @return [ColourRGB, nil] the colour this member has.
@@ -180,26 +281,51 @@ module Discordrb
180
281
 
181
282
  colour_role.color
182
283
  end
284
+
183
285
  alias_method :color, :colour
184
286
 
185
287
  # Server deafens this member.
186
- def server_deafen
187
- API::Server.update_member(@bot.token, @server.id, @user.id, deaf: true)
288
+ # @param reason [String, nil] The reason for defeaning this member.
289
+ def server_deafen(reason: nil)
290
+ update_member_data(deaf: true, reason: reason)
188
291
  end
189
292
 
190
293
  # Server undeafens this member.
191
- def server_undeafen
192
- API::Server.update_member(@bot.token, @server.id, @user.id, deaf: false)
294
+ # @param reason [String, nil] The reason for un-defeaning this member.
295
+ def server_undeafen(reason: nil)
296
+ update_member_data(deaf: false, reason: reason)
193
297
  end
194
298
 
195
299
  # Server mutes this member.
196
- def server_mute
197
- API::Server.update_member(@bot.token, @server.id, @user.id, mute: true)
300
+ # @param reason [String, nil] The reason for muting this member.
301
+ def server_mute(reason: nil)
302
+ update_member_data(mute: true, reason: reason)
198
303
  end
199
304
 
200
305
  # Server unmutes this member.
201
- def server_unmute
202
- API::Server.update_member(@bot.token, @server.id, @user.id, mute: false)
306
+ # @param reason [String, nil] The reason for un-muting this member.
307
+ def server_unmute(reason: nil)
308
+ update_member_data(mute: false, reason: reason)
309
+ end
310
+
311
+ # Bans this member from the server.
312
+ # @param message_days [Integer] How many days worth of messages sent by the member should be deleted. This parameter is deprecated and will be removed in 4.0.
313
+ # @param message_seconds [Integer] How many seconds worth of messages sent by the member should be deleted.
314
+ # @param reason [String] The reason this member is being banned.
315
+ def ban(message_days = 0, message_seconds: nil, reason: nil)
316
+ server.ban(@user, message_days, message_seconds: message_seconds, reason: reason)
317
+ end
318
+
319
+ # Unbans this member from the server.
320
+ # @param reason [String] The reason this member is being unbanned.
321
+ def unban(reason = nil)
322
+ server.unban(@user, reason)
323
+ end
324
+
325
+ # Kicks this member from the server.
326
+ # @param reason [String] The reason this member is being kicked.
327
+ def kick(reason = nil)
328
+ server.kick(@user, reason)
203
329
  end
204
330
 
205
331
  # @see Member#set_nick
@@ -214,32 +340,52 @@ module Discordrb
214
340
  # @param nick [String, nil] The string to set the nickname to, or nil if it should be reset.
215
341
  # @param reason [String] The reason the user's nickname is being changed.
216
342
  def set_nick(nick, reason = nil)
217
- # Discord uses the empty string to signify 'no nickname' so we convert nil into that
218
- nick ||= ''
219
-
220
343
  if @user.current_bot?
221
- API::User.change_own_nickname(@bot.token, @server.id, nick, reason)
344
+ update_current_member_data(nick: nick, reason: reason)
222
345
  else
223
- API::Server.update_member(@bot.token, @server.id, @user.id, nick: nick, reason: nil)
346
+ update_member_data(nick: nick, reason: reason)
224
347
  end
225
348
  end
226
349
 
227
350
  alias_method :set_nickname, :set_nick
228
351
 
229
- # @return [String] the name the user displays as (nickname if they have one, username otherwise)
352
+ # @return [String] the name the user displays as (nickname if they have one, global_name if they have one, username otherwise)
230
353
  def display_name
231
- nickname || username
354
+ nickname || global_name || username
355
+ end
356
+
357
+ # @param format [String, nil] If `nil`, the URL will default to `webp` for static avatars, and will detect if the member has a `gif` avatar. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this.
358
+ # @return [String, nil] the avatar that the user has displayed (server avatar if they have one, user avatar if they have one, nil otherwise)
359
+ def display_avatar_url(format = nil)
360
+ server_avatar_url(format) || avatar_url(format)
361
+ end
362
+
363
+ # @param format [String, nil] If `nil`, the URL will default to `webp` for static banners, and will detect if the member has a `gif` banner. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this.
364
+ # @return [String, nil] the banner that the user has displayed (server banner if they have one, user banner if they have one, nil otherwise)
365
+ def display_banner_url(format = nil)
366
+ server_banner_url(format) || banner_url(format)
367
+ end
368
+
369
+ # @return [AvatarDecoration, nil] the avatar decoration that the user displays (server avatar decoration if they have one, user avatar decoration if they have one, nil otherwise)
370
+ def display_avatar_decoration
371
+ server_avatar_decoration || avatar_decoration
372
+ end
373
+
374
+ # Set the flags for this member.
375
+ # @param flags [Integer, nil] The new bitwise value of flags for this member, or nil.
376
+ def flags=(flags)
377
+ update_member_data(flags: flags)
232
378
  end
233
379
 
234
380
  # Update this member's roles
235
381
  # @note For internal use only.
236
382
  # @!visibility private
237
383
  def update_roles(role_ids)
238
- @roles = [@server.role(@server.id)]
384
+ @roles = [server.role(@server_id)]
239
385
  role_ids.each do |id|
240
386
  # It is possible for members to have roles that do not exist
241
- # on the server any longer. See https://github.com/shardlab/discordrb/issues/371
242
- role = @server.role(id)
387
+ # on the server any longer. See https://github.com/discordrb/discordrb/issues/371
388
+ role = server.role(id)
243
389
  @roles << role if role
244
390
  end
245
391
  end
@@ -258,23 +404,52 @@ module Discordrb
258
404
  @boosting_since = time
259
405
  end
260
406
 
407
+ # @!visibility private
408
+ def update_communication_disabled_until(time)
409
+ time = time ? Time.parse(time) : nil
410
+ @communication_disabled_until = time
411
+ end
412
+
261
413
  # Update this member
262
414
  # @note For internal use only.
263
415
  # @!visibility private
264
416
  def update_data(data)
265
417
  update_roles(data['roles']) if data['roles']
266
- update_nick(data['nick']) if data.key?('nick')
418
+ @nick = data['nick'] if data.key?('nick')
267
419
  @mute = data['mute'] if data.key?('mute')
268
420
  @deaf = data['deaf'] if data.key?('deaf')
421
+ @server_avatar_id = data['avatar'] if data.key?('avatar')
422
+ @server_banner_id = data['banner'] if data.key?('banner')
423
+ @flags = data['flags'] if data.key?('flags')
424
+ @pending = data['pending'] if data.key?('pending')
269
425
 
270
426
  @joined_at = Time.parse(data['joined_at']) if data['joined_at']
427
+
428
+ if data.key?('communication_disabled_until')
429
+ timeout_until = data['communication_disabled_until']
430
+ @communication_disabled_until = timeout_until ? Time.parse(timeout_until) : nil
431
+ end
432
+
433
+ if data.key('premium_since')
434
+ @boosting_since = data['premium_since'] ? Time.parse(data['premium_since']) : nil
435
+ end
436
+
437
+ if (user = data['user'])
438
+ @user.update_global_name(user['global_name']) if user['global_name']
439
+ @user.avatar_id = user['avatar'] if user.key('avatar')
440
+ @user.update_avatar_decoration(user['avatar_decoration_data']) if user.key?('avatar_decoration_data')
441
+ @user.update_collectibles(user['collectibles']) if user.key?('collectibles')
442
+ @user.update_primary_server(user['primary_guild']) if user.key?('primary_guild')
443
+ end
444
+
445
+ @server_avatar_decoration = process_avatar_decoration(data['avatar_decoration_data']) if data.key?('avatar_decoration_data')
271
446
  end
272
447
 
273
448
  include PermissionCalculator
274
449
 
275
450
  # Overwriting inspect for debug purposes
276
451
  def inspect
277
- "<Member user=#{@user.inspect} server=#{@server.inspect} joined_at=#{@joined_at} roles=#{@roles.inspect} voice_channel=#{@voice_channel.inspect} mute=#{@mute} deaf=#{@deaf} self_mute=#{@self_mute} self_deaf=#{@self_deaf}>"
452
+ "<Member user=#{@user.inspect} server=#{@server&.inspect || @server_id} joined_at=#{@joined_at} roles=#{@roles&.inspect || @role_ids} voice_channel=#{voice_channel.inspect} mute=#{mute} deaf=#{deaf} self_mute=#{self_mute} self_deaf=#{self_deaf}>"
278
453
  end
279
454
 
280
455
  private
@@ -290,8 +465,25 @@ module Discordrb
290
465
 
291
466
  # Utility method to get data out of this member's voice state
292
467
  def voice_state_attribute(name)
293
- voice_state = @server.voice_states[@user.id]
468
+ voice_state = server.voice_states[@user.id]
294
469
  voice_state&.send name
295
470
  end
471
+
472
+ # @!visibility private
473
+ def resolve_role_ids
474
+ @roles ? @roles.collect(&:id) : @role_ids
475
+ end
476
+
477
+ # @!visibility private
478
+ def update_member_data(new_data)
479
+ update_data(JSON.parse(API::Server.update_member(@bot.token, @server_id, @user.id, **new_data)))
480
+ end
481
+
482
+ # @!visibility private
483
+ def update_current_member_data(new_data)
484
+ update_data(JSON.parse(API::Server.update_current_member(@bot.token, @server_id,
485
+ new_data.key?(:nick) ? new_data[:nick] : :undef,
486
+ new_data[:reason])))
487
+ end
296
488
  end
297
489
  end