discordrb 3.6.1 → 3.7.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.
@@ -13,7 +13,8 @@ module Discordrb
13
13
  started_home_actions: 1 << 5,
14
14
  completed_home_actions: 1 << 6,
15
15
  automod_quarantined_username: 1 << 7,
16
- dm_settings_upsell_acknowledged: 1 << 9
16
+ dm_settings_upsell_acknowledged: 1 << 9,
17
+ automod_quarantined_server_tag: 1 << 10
17
18
  }.freeze
18
19
 
19
20
  # @return [Time] when this member joined the server.
@@ -228,7 +229,7 @@ module Discordrb
228
229
  def add_role(role, reason = nil)
229
230
  role_ids = role_id_array(role)
230
231
 
231
- if role_ids.count.one?
232
+ if role_ids.one?
232
233
  API::Server.add_member_role(@bot.token, @server_id, @user.id, role_ids[0], reason)
233
234
  else
234
235
  old_role_ids = resolve_role_ids
@@ -243,7 +244,7 @@ module Discordrb
243
244
  def remove_role(role, reason = nil)
244
245
  role_ids = role_id_array(role)
245
246
 
246
- if role_ids.count.one?
247
+ if role_ids.one?
247
248
  API::Server.remove_member_role(@bot.token, @server_id, @user.id, role_ids[0], reason)
248
249
  else
249
250
  old_role_ids = resolve_role_ids
@@ -284,6 +285,12 @@ module Discordrb
284
285
 
285
286
  alias_method :color, :colour
286
287
 
288
+ # Get the member's roles sorted by their order in the hierarchy.
289
+ # @return [Array<Role>] the roles the member has, ordered by hierarchy.
290
+ def sort_roles
291
+ roles.sort_by { |role| [role.position, role.id] }
292
+ end
293
+
287
294
  # Server deafens this member.
288
295
  # @param reason [String, nil] The reason for defeaning this member.
289
296
  def server_deafen(reason: nil)
@@ -377,6 +384,30 @@ module Discordrb
377
384
  update_member_data(flags: flags)
378
385
  end
379
386
 
387
+ # Set the server banner for the current bot.
388
+ # @param banner [File, nil] A file like object that responds to read, or `nil`.
389
+ def server_banner=(banner)
390
+ raise 'Can only set a banner for the current bot' unless current_bot?
391
+
392
+ update_current_member_data(banner: banner.respond_to?(:read) ? Discordrb.encode64(banner) : banner)
393
+ end
394
+
395
+ # Set the server avatar for the current bot.
396
+ # @param avatar [File, nil] A file like object that responds to read, or `nil`.
397
+ def server_avatar=(avatar)
398
+ raise 'Can only set an avatar for the current bot' unless current_bot?
399
+
400
+ update_current_member_data(avatar: avatar.respond_to?(:read) ? Discordrb.encode64(avatar) : avatar)
401
+ end
402
+
403
+ # Set the server bio for the current bot.
404
+ # @param bio [String, nil] The new server bio for the bot, or nil.
405
+ def server_bio=(bio)
406
+ raise 'Can only set a bio for the current bot' unless current_bot?
407
+
408
+ update_current_member_data(bio: bio)
409
+ end
410
+
380
411
  # Update this member's roles
381
412
  # @note For internal use only.
382
413
  # @!visibility private
@@ -430,7 +461,7 @@ module Discordrb
430
461
  @communication_disabled_until = timeout_until ? Time.parse(timeout_until) : nil
431
462
  end
432
463
 
433
- if data.key('premium_since')
464
+ if data.key?('premium_since')
434
465
  @boosting_since = data['premium_since'] ? Time.parse(data['premium_since']) : nil
435
466
  end
436
467
 
@@ -483,7 +514,10 @@ module Discordrb
483
514
  def update_current_member_data(new_data)
484
515
  update_data(JSON.parse(API::Server.update_current_member(@bot.token, @server_id,
485
516
  new_data.key?(:nick) ? new_data[:nick] : :undef,
486
- new_data[:reason])))
517
+ new_data[:reason],
518
+ new_data.key?(:bio) ? new_data[:bio] : :undef,
519
+ new_data.key?(:banner) ? new_data[:banner] : :undef,
520
+ new_data.key?(:avatar) ? new_data[:avatar] : :undef)))
487
521
  end
488
522
  end
489
523
  end
@@ -92,9 +92,6 @@ module Discordrb
92
92
  # @return [Array<User>] the users that were mentioned in this message.
93
93
  attr_reader :mentions
94
94
 
95
- # @return [Array<Role>] the roles that were mentioned in this message.
96
- attr_reader :role_mentions
97
-
98
95
  # @return [Array<Attachment>] the files attached to this message.
99
96
  attr_reader :attachments
100
97
 
@@ -127,9 +124,6 @@ module Discordrb
127
124
  # @return [Integer] what the type of the message is
128
125
  attr_reader :type
129
126
 
130
- # @return [Server, nil] the server in which this message was sent.
131
- attr_reader :server
132
-
133
127
  # @return [Integer, nil] the webhook ID that sent this message, or `nil` if it wasn't sent through a webhook.
134
128
  attr_reader :webhook_id
135
129
 
@@ -151,9 +145,16 @@ module Discordrb
151
145
  # @return [Array<Snapshot>] the message snapshots included in this message.
152
146
  attr_reader :snapshots
153
147
 
148
+ # @return [RoleSubscriptionData, nil] the role subscription purchase or renewal that prompted this message.
149
+ attr_reader :role_subscription
150
+
151
+ # @return [Integer] a generally increasing integer that can be used to determine this message's position in a thread.
152
+ attr_reader :position
153
+
154
154
  # @!visibility private
155
155
  def initialize(data, bot)
156
156
  @bot = bot
157
+ @id = data['id'].to_i
157
158
  @content = data['content']
158
159
  @channel = bot.channel(data['channel_id'].to_i)
159
160
  @pinned = data['pinned']
@@ -161,14 +162,11 @@ module Discordrb
161
162
  @tts = data['tts']
162
163
  @nonce = data['nonce']
163
164
  @mention_everyone = data['mention_everyone']
165
+ @webhook_id = data['webhook_id']&.to_i
164
166
 
165
167
  @referenced_message = Message.new(data['referenced_message'], bot) if data['referenced_message']
166
168
  @message_reference = data['message_reference']
167
169
 
168
- @server = @channel.server
169
-
170
- @webhook_id = data['webhook_id']&.to_i
171
-
172
170
  if data['author']
173
171
  if @webhook_id
174
172
  # This is a webhook user! It would be pointless to try to resolve a member here, so we just create
@@ -188,7 +186,6 @@ module Discordrb
188
186
  @timestamp = Time.parse(data['timestamp']) if data['timestamp']
189
187
  @edited_timestamp = data['edited_timestamp'].nil? ? nil : Time.parse(data['edited_timestamp'])
190
188
  @edited = !@edited_timestamp.nil?
191
- @id = data['id'].to_i
192
189
 
193
190
  @emoji = []
194
191
 
@@ -204,14 +201,7 @@ module Discordrb
204
201
  @mentions << bot.ensure_user(element)
205
202
  end
206
203
 
207
- @role_mentions = []
208
-
209
- # Role mentions can only happen on public servers so make sure we only parse them there
210
- if @channel.text?
211
- data['mention_roles']&.each do |element|
212
- @role_mentions << @channel.server.role(element.to_i)
213
- end
214
- end
204
+ @mention_roles = data['mention_roles']&.map(&:to_i) || []
215
205
 
216
206
  @attachments = []
217
207
  @attachments = data['attachments'].map { |e| Attachment.new(e, self, @bot) } if data['attachments']
@@ -224,13 +214,17 @@ module Discordrb
224
214
 
225
215
  @flags = data['flags'] || 0
226
216
 
227
- @thread = data['thread'] ? @bot.ensure_channel(data['thread'], @server) : nil
217
+ @thread = data['thread'] ? @bot.ensure_channel(data['thread']) : nil
228
218
 
229
219
  @pinned_at = data['pinned_at'] ? Time.parse(data['pinned_at']) : nil
230
220
 
231
221
  @call = data['call'] ? Call.new(data['call'], @bot) : nil
232
222
 
233
223
  @snapshots = data['message_snapshots']&.map { |snapshot| Snapshot.new(snapshot['message'], @bot) } || []
224
+
225
+ @role_subscription = RoleSubscriptionData.new(data['role_subscription_data'], self, @bot) if data['role_subscription_data']
226
+
227
+ @position = data['position'] || 0
234
228
  end
235
229
 
236
230
  # @return [Member, User] the user that sent this message. (Will be a {Member} most of the time, it should only be a
@@ -238,7 +232,7 @@ module Discordrb
238
232
  def author
239
233
  return @author if @author
240
234
 
241
- if @channel.server
235
+ unless @channel.private?
242
236
  @author = @channel.server.member(@author_id)
243
237
  Discordrb::LOGGER.debug("Member with ID #{@author_id} not cached (possibly left the server).") if @author.nil?
244
238
  end
@@ -249,6 +243,25 @@ module Discordrb
249
243
  alias_method :user, :author
250
244
  alias_method :writer, :author
251
245
 
246
+ # @return [Server, nil] the server this message was sent in. If this message was sent in a PM channel, it will be nil.
247
+ # @raise [Discordrb::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
248
+ # authorized with the `bot` scope.
249
+ def server
250
+ return if @channel.private?
251
+
252
+ @server ||= @channel.server
253
+ end
254
+
255
+ # Get the roles that were mentioned in this message.
256
+ # @return [Array<Role>] the roles that were mentioned in this message.
257
+ # @raise [Discordrb::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
258
+ # authorized with the `bot` scope.
259
+ def role_mentions
260
+ return [] if @channel.private? || @mention_roles.empty?
261
+
262
+ @role_mentions ||= @mention_roles.map { |id| server.role(id) }
263
+ end
264
+
252
265
  # Replies to this message with the specified content.
253
266
  # @deprecated Please use {#respond}.
254
267
  # @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
@@ -297,12 +310,14 @@ module Discordrb
297
310
  end
298
311
 
299
312
  # Deletes this message.
313
+ # @return [nil]
300
314
  def delete(reason = nil)
301
315
  API::Channel.delete_message(@bot.token, @channel.id, @id, reason)
302
316
  nil
303
317
  end
304
318
 
305
319
  # Pins this message
320
+ # @return [nil]
306
321
  def pin(reason = nil)
307
322
  API::Channel.pin_message(@bot.token, @channel.id, @id, reason)
308
323
  @pinned = true
@@ -310,6 +325,7 @@ module Discordrb
310
325
  end
311
326
 
312
327
  # Unpins this message
328
+ # @return [nil]
313
329
  def unpin(reason = nil)
314
330
  API::Channel.unpin_message(@bot.token, @channel.id, @id, reason)
315
331
  @pinned = false
@@ -317,6 +333,7 @@ module Discordrb
317
333
  end
318
334
 
319
335
  # Crossposts a message in a news channel.
336
+ # @return [Message] the updated message object.
320
337
  def crosspost
321
338
  response = API::Channel.crosspost_message(@bot.token, @channel.id, @id)
322
339
  Message.new(JSON.parse(response), @bot)
@@ -405,6 +422,7 @@ module Discordrb
405
422
 
406
423
  # Reacts to a message.
407
424
  # @param reaction [String, #to_reaction] the unicode emoji or {Emoji}
425
+ # @return [nil]
408
426
  def create_reaction(reaction)
409
427
  reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
410
428
  API::Channel.create_reaction(@bot.token, @channel.id, @id, reaction)
@@ -416,15 +434,17 @@ module Discordrb
416
434
  # Returns the list of users who reacted with a certain reaction.
417
435
  # @param reaction [String, #to_reaction] the unicode emoji or {Emoji}
418
436
  # @param limit [Integer] the limit of how many users to retrieve. `nil` will return all users
437
+ # @param type [Integer, Symbol] the type of reaction to get. See {Reaction::TYPES}
419
438
  # @example Get all the users that reacted with a thumbs up.
420
439
  # thumbs_up_reactions = message.reacted_with("\u{1F44D}")
421
440
  # @return [Array<User>] the users who used this reaction
422
- def reacted_with(reaction, limit: 100)
441
+ def reacted_with(reaction, limit: 100, type: :normal)
423
442
  reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
424
443
  reaction = reaction.to_s if reaction.respond_to?(:to_s)
444
+ type = Reaction::TYPES[type] || type
425
445
 
426
446
  get_reactions = proc do |fetch_limit, after_id = nil|
427
- resp = API::Channel.get_reactions(@bot.token, @channel.id, @id, reaction, nil, after_id, fetch_limit)
447
+ resp = API::Channel.get_reactions(@bot.token, @channel.id, @id, reaction, nil, after_id, fetch_limit, type)
428
448
  JSON.parse(resp).map { |d| User.new(d, @bot) }
429
449
  end
430
450
 
@@ -473,6 +493,13 @@ module Discordrb
473
493
  API::Channel.delete_all_reactions(@bot.token, @channel.id, @id)
474
494
  end
475
495
 
496
+ # Removes all reactions for a single emoji.
497
+ # @param reaction [String, #to_reaction] the reaction to remove.
498
+ def delete_all_reactions_for_emoji(reaction)
499
+ reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
500
+ API::Channel.delete_all_emoji_reactions(@bot.token, @channel.id, @id, reaction.to_s)
501
+ end
502
+
476
503
  # The inspect method is overwritten to give more useful output
477
504
  def inspect
478
505
  "<Message content=\"#{@content}\" id=#{@id} timestamp=#{@timestamp} author=#{@author} channel=#{@channel}>"
@@ -480,7 +507,7 @@ module Discordrb
480
507
 
481
508
  # @return [String] a URL that a user can use to navigate to this message in the client
482
509
  def link
483
- "https://discord.com/channels/#{@server&.id || '@me'}/#{@channel.id}/#{@id}"
510
+ "https://discord.com/channels/#{server&.id || '@me'}/#{@channel.id}/#{@id}"
484
511
  end
485
512
 
486
513
  alias_method :jump_link, :link
@@ -65,9 +65,8 @@ module Discordrb
65
65
 
66
66
  # Comparison by attributes [:id, :type, :allow, :deny]
67
67
  def ==(other)
68
- # rubocop:disable Lint/Void
69
- false unless other.is_a? Discordrb::Overwrite
70
- # rubocop:enable Lint/Void
68
+ return false unless other.is_a?(Discordrb::Overwrite)
69
+
71
70
  id == other.id &&
72
71
  type == other.type &&
73
72
  allow == other.allow &&
@@ -52,7 +52,7 @@ module Discordrb
52
52
  def ==(other)
53
53
  return false unless other.is_a?(PrimaryServer)
54
54
 
55
- Discordrb.id_compare(other.server_id, @server_id)
55
+ Discordrb.id_compare?(other.server_id, @server_id)
56
56
  end
57
57
 
58
58
  alias_method :eql?, :==
@@ -19,8 +19,8 @@ module Discordrb
19
19
  alias_method :name=, :username=
20
20
 
21
21
  # Changes the bot's avatar.
22
- # @param avatar [String, #read] A JPG file to be used as the avatar, either
23
- # something readable (e.g. File Object) or as a data URL.
22
+ # @param avatar [String, File, #read, nil] A file to be used as the avatar, either
23
+ # something readable (e.g. File Object) or a data URI.
24
24
  def avatar=(avatar)
25
25
  if avatar.respond_to?(:read)
26
26
  update_profile_data(avatar: Discordrb.encode64(avatar))
@@ -29,38 +29,24 @@ module Discordrb
29
29
  end
30
30
  end
31
31
 
32
+ # Changes the bot's banner.
33
+ # @param banner [String, File, #read, nil] A file to be used as the banner, either
34
+ # something readable (e.g. File Object) or a data URI.
35
+ def banner=(banner)
36
+ if banner.respond_to?(:read)
37
+ update_profile_data(banner: Discordrb.encode64(banner))
38
+ else
39
+ update_profile_data(banner: banner)
40
+ end
41
+ end
42
+
32
43
  # Updates the cached profile data with the new one.
33
44
  # @note For internal use only.
34
45
  # @!visibility private
35
46
  def update_data(new_data)
36
- @username = new_data[:username] || @username
37
- @avatar_id = new_data[:avatar_id] || @avatar_id
38
- end
39
-
40
- # Sets the user status setting to Online.
41
- # @note Only usable on User accounts.
42
- def online
43
- update_profile_status_setting('online')
44
- end
45
-
46
- # Sets the user status setting to Idle.
47
- # @note Only usable on User accounts.
48
- def idle
49
- update_profile_status_setting('idle')
50
- end
51
-
52
- # Sets the user status setting to Do Not Disturb.
53
- # @note Only usable on User accounts.
54
- def dnd
55
- update_profile_status_setting('dnd')
56
- end
57
-
58
- alias_method(:busy, :dnd)
59
-
60
- # Sets the user status setting to Invisible.
61
- # @note Only usable on User accounts.
62
- def invisible
63
- update_profile_status_setting('invisible')
47
+ @username = new_data['username']
48
+ @avatar_id = new_data['avatar']
49
+ @banner_id = new_data['banner']
64
50
  end
65
51
 
66
52
  # The inspect method is overwritten to give more useful output
@@ -70,17 +56,12 @@ module Discordrb
70
56
 
71
57
  private
72
58
 
73
- # Internal handler for updating the user's status setting
74
- def update_profile_status_setting(status)
75
- API::User.change_status_setting(@bot.token, status)
76
- end
77
-
59
+ # @!visibility private
78
60
  def update_profile_data(new_data)
79
- API::User.update_profile(@bot.token,
80
- nil, nil,
81
- new_data[:username] || @username,
82
- new_data.key?(:avatar) ? new_data[:avatar] : @avatar_id)
83
- update_data(new_data)
61
+ update_data(JSON.parse(API::User.update_current_user(@bot.token,
62
+ new_data[:username] || :undef,
63
+ new_data.key?(:avatar) ? new_data[:avatar] : :undef,
64
+ new_data.key?(:banner) ? new_data[:banner] : :undef)))
84
65
  end
85
66
  end
86
67
  end
@@ -3,7 +3,13 @@
3
3
  module Discordrb
4
4
  # A reaction to a message.
5
5
  class Reaction
6
- # @return [Integer] the amount of users who have reacted with this reaction
6
+ # Map of reaction types.
7
+ TYPES = {
8
+ normal: 0,
9
+ burst: 1
10
+ }.freeze
11
+
12
+ # @return [Integer] the total amount of users who have reacted with this reaction (including burst reactions)
7
13
  attr_reader :count
8
14
 
9
15
  # @return [true, false] whether the current bot or user used this reaction
@@ -16,12 +22,30 @@ module Discordrb
16
22
  # @return [String] the name or unicode representation of the emoji
17
23
  attr_reader :name
18
24
 
25
+ # @return [true, false] whether the current bot or user used this reaction as a burst reaction
26
+ attr_reader :me_burst
27
+ alias_method :me_burst?, :me_burst
28
+
29
+ # @return [Array<ColourRGB>] an array of colors used for animations in burst reactions
30
+ attr_reader :burst_colours
31
+ alias_method :burst_colors, :burst_colours
32
+
33
+ # @return [Integer] the total amount of users who have reacted with this reaction as a burst reaction
34
+ attr_reader :burst_count
35
+
36
+ # @return [Integer] the total amount of users who have reacted with this reaction as a normal reaction
37
+ attr_reader :normal_count
38
+
19
39
  # @!visibility private
20
40
  def initialize(data)
21
41
  @count = data['count']
22
42
  @me = data['me']
23
43
  @id = data['emoji']['id']&.to_i
24
44
  @name = data['emoji']['name']
45
+ @me_burst = data['me_burst']
46
+ @burst_colours = data['burst_colors'].map { |b| ColourRGB.new(b.delete('#')) }
47
+ @burst_count = data['count_details']['burst']
48
+ @normal_count = data['count_details']['normal']
25
49
  end
26
50
 
27
51
  # Converts this Reaction into a string that can be sent back to Discord in other reaction endpoints.
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discordrb
4
+ # Metadata about a purchase or renewal for a role subscription.
5
+ class RoleSubscriptionData
6
+ # @return [String] the name of the tier the user is subscribed to.
7
+ attr_reader :tier_name
8
+
9
+ # @return [Integer] the ID of the SKU and listing the user is subscribed to.
10
+ attr_reader :listing_id
11
+
12
+ # @return [true, false] whether the subscription notification is for a renewal.
13
+ attr_reader :renewal
14
+ alias_method :renewal?, :renewal
15
+
16
+ # @return [Integer] the total number of months the user has been subscribed for.
17
+ attr_reader :total_months_subscribed
18
+
19
+ # @!visibility private
20
+ def initialize(data, message, bot)
21
+ @bot = bot
22
+ @message = message
23
+ @renewal = data['is_renewal']
24
+ @tier_name = data['tier_name']
25
+ @listing_id = data['role_subscription_listing_id']&.to_i
26
+ @total_months_subscribed = data['total_months_subscribed']
27
+ end
28
+
29
+ # Check if this role subscription is a new purchase.
30
+ # @return [true, false] if this role subscription is a new purchase.
31
+ def new?
32
+ @renewal == false
33
+ end
34
+
35
+ # Get the role associated with the notification for this subscription.
36
+ # @return [Role, nil] the role that's associated with this subscription.
37
+ def role
38
+ @message.server.roles.find { |role| role.tags&.subscription_listing_id == @listing_id }
39
+ end
40
+ end
41
+ end
@@ -68,6 +68,8 @@ module Discordrb
68
68
  @members = {}
69
69
  @voice_states = {}
70
70
  @emoji = {}
71
+ @channels = []
72
+ @channels_by_id = {}
71
73
 
72
74
  update_data(data)
73
75
 
@@ -328,8 +330,8 @@ module Discordrb
328
330
  # @return [String, nil] the widget URL to the server that displays the amount of online members in a
329
331
  # stylish way. `nil` if the widget is not enabled.
330
332
  def widget_url
331
- update_data if @embed_enabled.nil?
332
- return unless @embed_enabled
333
+ update_data if @widget_enabled.nil?
334
+ return unless @widget_enabled
333
335
 
334
336
  API.widget_url(@id)
335
337
  end
@@ -343,8 +345,8 @@ module Discordrb
343
345
  # @return [String, nil] the widget banner URL to the server that displays the amount of online members,
344
346
  # server icon and server name in a stylish way. `nil` if the widget is not enabled.
345
347
  def widget_banner_url(style)
346
- update_data if @embed_enabled.nil?
347
- return unless @embed_enabled
348
+ update_data if @widget_enabled.nil?
349
+ return unless @widget_enabled
348
350
 
349
351
  API.widget_url(@id, style)
350
352
  end
@@ -46,3 +46,4 @@ require 'discordrb/data/primary_server'
46
46
  require 'discordrb/data/server_preview'
47
47
  require 'discordrb/data/call'
48
48
  require 'discordrb/data/snapshot'
49
+ require 'discordrb/data/role_subscription'
@@ -27,7 +27,13 @@ module Discordrb::Events
27
27
  # @!attribute [r] user
28
28
  # @return [User]
29
29
  # @see Interaction#user
30
- delegate :type, :server, :server_id, :channel, :channel_id, :user, to: :interaction
30
+ # @!attribute [r] user_locale
31
+ # @return [String]
32
+ # @see Interaction#user_locale
33
+ # @!attribute [r] context
34
+ # @return [Integer]
35
+ # @see Interaction#context
36
+ delegate :type, :server, :server_id, :channel, :channel_id, :user, :user_locale, :context, to: :interaction
31
37
 
32
38
  # @!visibility private
33
39
  def initialize(data, bot)
@@ -287,11 +287,40 @@ module Discordrb::Events
287
287
  end
288
288
  end
289
289
 
290
- # @see Discordrb::EventContainer#mention
291
- class MentionEvent < MessageEvent; end
290
+ # Event raised when the current bot is mentioned in a message.
291
+ class MentionEvent < MessageEvent
292
+ # @return [true, false] whether this mention event was raised
293
+ # due to a mention of the bot's auto-generated server role.
294
+ attr_reader :role_mention
295
+ alias_method :role_mention?, :role_mention
296
+
297
+ # @!visibility private
298
+ def initialize(message, bot, role_mention)
299
+ super(message, bot)
300
+
301
+ @role_mention = role_mention
302
+ end
303
+ end
292
304
 
293
305
  # Event handler for {MentionEvent}
294
- class MentionEventHandler < MessageEventHandler; end
306
+ class MentionEventHandler < MessageEventHandler
307
+ # @!visibility private
308
+ def matches?(event)
309
+ return false unless super
310
+ return false unless event.is_a?(MentionEvent)
311
+
312
+ [
313
+ matches_all(@attributes[:role_mention], event.role_mention) do |a, e|
314
+ case a
315
+ when TrueClass
316
+ e == true
317
+ when FalseClass
318
+ e == false
319
+ end
320
+ end
321
+ ].reduce(true, &:&)
322
+ end
323
+ end
295
324
 
296
325
  # @see Discordrb::EventContainer#pm
297
326
  class PrivateMessageEvent < MessageEvent; end
@@ -14,6 +14,17 @@ module Discordrb::Events
14
14
  # @!visibility private
15
15
  attr_reader :message_id
16
16
 
17
+ # @return [true, false] whether the reaction is a burst reaction.
18
+ attr_reader :burst
19
+ alias_method :burst?, :burst
20
+
21
+ # @return [Integer] the type of the reaction. 0 for normal, 1 for burst.
22
+ attr_reader :type
23
+
24
+ # @return [Array<ColourRGB>] an array of colors used for animations in burst reactions.
25
+ attr_reader :burst_colours
26
+ alias_method :burst_colors, :burst_colours
27
+
17
28
  # @!visibility private
18
29
  def initialize(data, bot)
19
30
  @bot = bot
@@ -22,6 +33,9 @@ module Discordrb::Events
22
33
  @user_id = data['user_id'].to_i
23
34
  @message_id = data['message_id'].to_i
24
35
  @channel_id = data['channel_id'].to_i
36
+ @burst = data['burst']
37
+ @type = data['type']
38
+ @burst_colours = data['burst_colors']&.map { |b| Discordrb::ColourRGB.new(b.delete('#')) } || []
25
39
  end
26
40
 
27
41
  # @return [User, Member] the user that reacted to this message, or member if a server exists.
@@ -90,6 +104,14 @@ module Discordrb::Events
90
104
  else
91
105
  a == e
92
106
  end
107
+ end,
108
+ matches_all(@attributes[:type], event.type) do |a, e|
109
+ case a
110
+ when Integer
111
+ a == e
112
+ when Symbol, String
113
+ Discordrb::Reaction::TYPES[a.to_sym] == e
114
+ end
93
115
  end
94
116
  ].reduce(true, &:&)
95
117
  end
@@ -157,4 +179,40 @@ module Discordrb::Events
157
179
  ].reduce(true, &:&)
158
180
  end
159
181
  end
182
+
183
+ # Event raised when all instances of a single reaction are removed from a message.
184
+ class ReactionRemoveEmojiEvent < ReactionRemoveAllEvent
185
+ # @return [Emoji] the emoji that was removed.
186
+ attr_reader :emoji
187
+
188
+ # @!visibility private
189
+ def initialize(data, bot)
190
+ super
191
+
192
+ @emoji = Discordrb::Emoji.new(data['emoji'], bot)
193
+ end
194
+ end
195
+
196
+ # Event handler for {ReactionRemoveEmojiEvent}.
197
+ class ReactionRemoveEmojiEventHandler < ReactionRemoveAllEventHandler
198
+ # @!visibility private
199
+ def matches?(event)
200
+ # Check for the proper event type.
201
+ return false unless super
202
+ return false unless event.is_a?(ReactionRemoveEmojiEvent)
203
+
204
+ [
205
+ matches_all(@attributes[:emoji], event.emoji) do |a, e|
206
+ case a
207
+ when Integer
208
+ e.id == a
209
+ when String
210
+ e.name == a || e.name == a.delete(':') || e.id == a.resolve_id
211
+ else
212
+ e == a
213
+ end
214
+ end
215
+ ].reduce(true, &:&)
216
+ end
217
+ end
160
218
  end