discordrb 3.4.3 → 3.5.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +44 -18
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
- data/.github/workflows/codeql.yml +65 -0
- data/.markdownlint.json +4 -0
- data/.rubocop.yml +8 -2
- data/CHANGELOG.md +390 -225
- data/LICENSE.txt +1 -1
- data/README.md +37 -25
- data/discordrb-webhooks.gemspec +4 -1
- data/discordrb.gemspec +9 -6
- data/lib/discordrb/api/application.rb +202 -0
- data/lib/discordrb/api/channel.rb +177 -11
- data/lib/discordrb/api/interaction.rb +54 -0
- data/lib/discordrb/api/invite.rb +2 -2
- data/lib/discordrb/api/server.rb +40 -19
- data/lib/discordrb/api/user.rb +8 -3
- data/lib/discordrb/api/webhook.rb +57 -0
- data/lib/discordrb/api.rb +19 -5
- data/lib/discordrb/bot.rb +317 -32
- data/lib/discordrb/cache.rb +27 -22
- data/lib/discordrb/commands/command_bot.rb +6 -4
- data/lib/discordrb/commands/container.rb +1 -1
- data/lib/discordrb/commands/parser.rb +2 -2
- data/lib/discordrb/commands/rate_limiter.rb +1 -1
- data/lib/discordrb/container.rb +132 -3
- data/lib/discordrb/data/attachment.rb +15 -0
- data/lib/discordrb/data/audit_logs.rb +3 -3
- data/lib/discordrb/data/channel.rb +167 -23
- data/lib/discordrb/data/component.rb +229 -0
- data/lib/discordrb/data/integration.rb +42 -3
- data/lib/discordrb/data/interaction.rb +800 -0
- data/lib/discordrb/data/invite.rb +1 -1
- data/lib/discordrb/data/member.rb +108 -33
- data/lib/discordrb/data/message.rb +99 -19
- data/lib/discordrb/data/overwrite.rb +13 -7
- data/lib/discordrb/data/role.rb +58 -1
- data/lib/discordrb/data/server.rb +82 -80
- data/lib/discordrb/data/user.rb +69 -9
- data/lib/discordrb/data/webhook.rb +97 -4
- data/lib/discordrb/data.rb +3 -0
- data/lib/discordrb/errors.rb +44 -3
- data/lib/discordrb/events/channels.rb +1 -1
- data/lib/discordrb/events/interactions.rb +482 -0
- data/lib/discordrb/events/message.rb +9 -6
- data/lib/discordrb/events/presence.rb +21 -14
- data/lib/discordrb/events/reactions.rb +0 -1
- data/lib/discordrb/events/threads.rb +96 -0
- data/lib/discordrb/gateway.rb +30 -17
- data/lib/discordrb/permissions.rb +59 -34
- data/lib/discordrb/version.rb +1 -1
- data/lib/discordrb/voice/encoder.rb +2 -2
- data/lib/discordrb/voice/network.rb +18 -7
- data/lib/discordrb/voice/sodium.rb +3 -1
- data/lib/discordrb/voice/voice_bot.rb +3 -3
- data/lib/discordrb/webhooks.rb +2 -0
- data/lib/discordrb.rb +37 -4
- metadata +48 -14
- data/.codeclimate.yml +0 -16
- data/.travis.yml +0 -32
- data/bin/travis_build_docs.sh +0 -17
@@ -0,0 +1,482 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'discordrb/events/generic'
|
4
|
+
require 'discordrb/data'
|
5
|
+
|
6
|
+
module Discordrb::Events
|
7
|
+
# Generic subclass for interaction events
|
8
|
+
class InteractionCreateEvent < Event
|
9
|
+
# @return [Interaction] The interaction for this event.
|
10
|
+
attr_reader :interaction
|
11
|
+
|
12
|
+
# @!attribute [r] type
|
13
|
+
# @return [Integer]
|
14
|
+
# @see Interaction#type
|
15
|
+
# @!attribute [r] server
|
16
|
+
# @return [Server, nil]
|
17
|
+
# @see Interaction#server
|
18
|
+
# @!attribute [r] server_id
|
19
|
+
# @return [Integer]
|
20
|
+
# @see Interaction#server_id
|
21
|
+
# @!attribute [r] channel
|
22
|
+
# @return [Channel]
|
23
|
+
# @see Interaction#channel
|
24
|
+
# @!attribute [r] channel_id
|
25
|
+
# @return [Integer]
|
26
|
+
# @see Interaction#channel_id
|
27
|
+
# @!attribute [r] user
|
28
|
+
# @return [User]
|
29
|
+
# @see Interaction#user
|
30
|
+
delegate :type, :server, :server_id, :channel, :channel_id, :user, to: :interaction
|
31
|
+
|
32
|
+
def initialize(data, bot)
|
33
|
+
@interaction = Discordrb::Interaction.new(data, bot)
|
34
|
+
@bot = bot
|
35
|
+
end
|
36
|
+
|
37
|
+
# (see Interaction#respond)
|
38
|
+
def respond(content: nil, tts: nil, embeds: nil, allowed_mentions: nil, flags: 0, ephemeral: nil, wait: false, components: nil, &block)
|
39
|
+
@interaction.respond(
|
40
|
+
content: content, tts: tts, embeds: embeds, allowed_mentions: allowed_mentions,
|
41
|
+
flags: flags, ephemeral: ephemeral, wait: wait, components: components, &block
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
# (see Interaction#defer)
|
46
|
+
def defer(flags: 0, ephemeral: true)
|
47
|
+
@interaction.defer(flags: flags, ephemeral: ephemeral)
|
48
|
+
end
|
49
|
+
|
50
|
+
# (see Interaction#update_message)
|
51
|
+
def update_message(content: nil, tts: nil, embeds: nil, allowed_mentions: nil, flags: 0, ephemeral: nil, wait: false, components: nil, &block)
|
52
|
+
@interaction.update_message(
|
53
|
+
content: content, tts: tts, embeds: embeds, allowed_mentions: allowed_mentions,
|
54
|
+
flags: flags, ephemeral: ephemeral, wait: wait, components: components, &block
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
# (see Interaction#show_modal)
|
59
|
+
def show_modal(title:, custom_id:, components: nil, &block)
|
60
|
+
@interaction.show_modal(title: title, custom_id: custom_id, components: components, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
# (see Interaction#edit_response)
|
64
|
+
def edit_response(content: nil, embeds: nil, allowed_mentions: nil, components: nil, &block)
|
65
|
+
@interaction.edit_response(content: content, embeds: embeds, allowed_mentions: allowed_mentions, components: components, &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
# (see Interaction#delete_response)
|
69
|
+
def delete_response
|
70
|
+
@interaction.delete_response
|
71
|
+
end
|
72
|
+
|
73
|
+
# (see Interaction#send_message)
|
74
|
+
def send_message(content: nil, embeds: nil, tts: false, allowed_mentions: nil, flags: 0, ephemeral: nil, components: nil, &block)
|
75
|
+
@interaction.send_message(content: content, embeds: embeds, tts: tts, allowed_mentions: allowed_mentions, flags: flags, ephemeral: ephemeral, components: components, &block)
|
76
|
+
end
|
77
|
+
|
78
|
+
# (see Interaction#edit_message)
|
79
|
+
def edit_message(message, content: nil, embeds: nil, allowed_mentions: nil, &block)
|
80
|
+
@interaction.edit_message(message, content: content, embeds: embeds, allowed_mentions: allowed_mentions, &block)
|
81
|
+
end
|
82
|
+
|
83
|
+
# (see Interaction#delete_message)
|
84
|
+
def delete_message(message)
|
85
|
+
@interaction.delete_message(message)
|
86
|
+
end
|
87
|
+
|
88
|
+
# (see Interaction#defer_update)
|
89
|
+
def defer_update
|
90
|
+
@interaction.defer_update
|
91
|
+
end
|
92
|
+
|
93
|
+
# (see Interaction#get_component)
|
94
|
+
def get_component(custom_id)
|
95
|
+
@interaction.get_component(custom_id)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Event handler for INTERACTION_CREATE events.
|
100
|
+
class InteractionCreateEventHandler < EventHandler
|
101
|
+
# @!visibility private
|
102
|
+
def matches?(event)
|
103
|
+
return false unless event.is_a? InteractionCreateEvent
|
104
|
+
|
105
|
+
[
|
106
|
+
matches_all(@attributes[:type], event.type) do |a, e|
|
107
|
+
a == case a
|
108
|
+
when String, Symbol
|
109
|
+
Discordrb::Interactions::TYPES[e.to_sym]
|
110
|
+
else
|
111
|
+
e
|
112
|
+
end
|
113
|
+
end,
|
114
|
+
|
115
|
+
matches_all(@attributes[:server], event.interaction) do |a, e|
|
116
|
+
a.resolve_id == e.server_id
|
117
|
+
end,
|
118
|
+
|
119
|
+
matches_all(@attributes[:channel], event.interaction) do |a, e|
|
120
|
+
a.resolve_id == e.channel_id
|
121
|
+
end,
|
122
|
+
|
123
|
+
matches_all(@attributes[:user], event.user) do |a, e|
|
124
|
+
a.resolve_id == e.id
|
125
|
+
end
|
126
|
+
].reduce(true, &:&)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Event for ApplicationCommand interactions.
|
131
|
+
class ApplicationCommandEvent < InteractionCreateEvent
|
132
|
+
# Struct to allow accessing data via [] or methods.
|
133
|
+
Resolved = Struct.new('Resolved', :channels, :members, :messages, :roles, :users, :attachments) # rubocop:disable Lint/StructNewOverride
|
134
|
+
|
135
|
+
# @return [String] The name of the command.
|
136
|
+
attr_reader :command_name
|
137
|
+
|
138
|
+
# @return [Integer] The ID of the command.
|
139
|
+
attr_reader :command_id
|
140
|
+
|
141
|
+
# @return [String, nil] The name of the subcommand group relevant to this event.
|
142
|
+
attr_reader :subcommand_group
|
143
|
+
|
144
|
+
# @return [String, nil] The name of the subcommand relevant to this event.
|
145
|
+
attr_reader :subcommand
|
146
|
+
|
147
|
+
# @return [Resolved]
|
148
|
+
attr_reader :resolved
|
149
|
+
|
150
|
+
# @return [Hash<Symbol, Object>] Arguments provided to the command, mapped as `Name => Value`.
|
151
|
+
attr_reader :options
|
152
|
+
|
153
|
+
# @return [Integer, nil] The target of this command when it is a context command.
|
154
|
+
attr_reader :target_id
|
155
|
+
|
156
|
+
def initialize(data, bot)
|
157
|
+
super
|
158
|
+
|
159
|
+
command_data = data['data']
|
160
|
+
|
161
|
+
@command_id = command_data['id']
|
162
|
+
@command_name = command_data['name'].to_sym
|
163
|
+
|
164
|
+
@target_id = command_data['target_id']&.to_i
|
165
|
+
@resolved = Resolved.new({}, {}, {}, {}, {}, {})
|
166
|
+
process_resolved(command_data['resolved']) if command_data['resolved']
|
167
|
+
|
168
|
+
options = command_data['options'] || []
|
169
|
+
|
170
|
+
if options.empty?
|
171
|
+
@options = {}
|
172
|
+
return
|
173
|
+
end
|
174
|
+
|
175
|
+
case options[0]['type']
|
176
|
+
when 2
|
177
|
+
options = options[0]
|
178
|
+
@subcommand_group = options['name'].to_sym
|
179
|
+
@subcommand = options['options'][0]['name'].to_sym
|
180
|
+
options = options['options'][0]['options']
|
181
|
+
when 1
|
182
|
+
options = options[0]
|
183
|
+
@subcommand = options['name'].to_sym
|
184
|
+
options = options['options']
|
185
|
+
end
|
186
|
+
|
187
|
+
@options = transform_options_hash(options || {})
|
188
|
+
end
|
189
|
+
|
190
|
+
# @return [Message, User, nil] The target of this command, for context commands.
|
191
|
+
def target
|
192
|
+
return nil unless @target_id
|
193
|
+
|
194
|
+
@resolved.find { |data| data.key?(@target_id) }[@target_id]
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def process_resolved(resolved_data)
|
200
|
+
resolved_data['users']&.each do |id, data|
|
201
|
+
@resolved[:users][id.to_i] = @bot.ensure_user(data)
|
202
|
+
end
|
203
|
+
|
204
|
+
resolved_data['roles']&.each do |id, data|
|
205
|
+
@resolved[:roles][id.to_i] = Discordrb::Role.new(data, @bot)
|
206
|
+
end
|
207
|
+
|
208
|
+
resolved_data['channels']&.each do |id, data|
|
209
|
+
data['guild_id'] = @interaction.server_id
|
210
|
+
@resolved[:channels][id.to_i] = Discordrb::Channel.new(data, @bot)
|
211
|
+
end
|
212
|
+
|
213
|
+
resolved_data['members']&.each do |id, data|
|
214
|
+
data['user'] = resolved_data['users'][id]
|
215
|
+
data['guild_id'] = @interaction.server_id
|
216
|
+
@resolved[:members][id.to_i] = Discordrb::Member.new(data, nil, @bot)
|
217
|
+
end
|
218
|
+
|
219
|
+
resolved_data['messages']&.each do |id, data|
|
220
|
+
@resolved[:messages][id.to_i] = Discordrb::Message.new(data, @bot)
|
221
|
+
end
|
222
|
+
|
223
|
+
resolved_data['attachments']&.each do |id, data|
|
224
|
+
@resolved[:attachments][id.to_i] = Discordrb::Attachment.new(data, nil, @bot)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def transform_options_hash(hash)
|
229
|
+
hash.to_h { |opt| [opt['name'], opt['options'] || opt['value']] }
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Event handler for ApplicationCommandEvents.
|
234
|
+
class ApplicationCommandEventHandler < EventHandler
|
235
|
+
# @return [Hash]
|
236
|
+
attr_reader :subcommands
|
237
|
+
|
238
|
+
# @!visibility private
|
239
|
+
def initialize(attributes, block)
|
240
|
+
super
|
241
|
+
|
242
|
+
@subcommands = {}
|
243
|
+
end
|
244
|
+
|
245
|
+
# @param name [Symbol, String]
|
246
|
+
# @yieldparam [SubcommandBuilder]
|
247
|
+
# @return [ApplicationCommandEventHandler]
|
248
|
+
def group(name)
|
249
|
+
raise ArgumentError, 'Unable to mix subcommands and groups' if @subcommands.any? { |_, v| v.is_a? Proc }
|
250
|
+
|
251
|
+
builder = SubcommandBuilder.new(name)
|
252
|
+
yield builder
|
253
|
+
|
254
|
+
@subcommands.merge!(builder.to_h)
|
255
|
+
self
|
256
|
+
end
|
257
|
+
|
258
|
+
# @param name [String, Symbol]
|
259
|
+
# @yieldparam [SubcommandBuilder]
|
260
|
+
# @return [ApplicationCommandEventHandler]
|
261
|
+
def subcommand(name, &block)
|
262
|
+
raise ArgumentError, 'Unable to mix subcommands and groups' if @subcommands.any? { |_, v| v.is_a? Hash }
|
263
|
+
|
264
|
+
@subcommands[name.to_sym] = block
|
265
|
+
|
266
|
+
self
|
267
|
+
end
|
268
|
+
|
269
|
+
# @!visibility private
|
270
|
+
# @param event [Event]
|
271
|
+
def call(event)
|
272
|
+
return unless matches?(event)
|
273
|
+
|
274
|
+
if event.subcommand_group
|
275
|
+
unless (cmd = @subcommands.dig(event.subcommand_group, event.subcommand))
|
276
|
+
Discordrb::LOGGER.debug("Received an event for an unhandled subcommand `#{event.command_name} #{event.subcommand_group} #{event.subcommand}'")
|
277
|
+
return
|
278
|
+
end
|
279
|
+
|
280
|
+
cmd.call(event)
|
281
|
+
elsif event.subcommand
|
282
|
+
unless (cmd = @subcommands[event.subcommand])
|
283
|
+
Discordrb::LOGGER.debug("Received an event for an unhandled subcommand `#{event.command_name} #{event.subcommand}'")
|
284
|
+
return
|
285
|
+
end
|
286
|
+
|
287
|
+
cmd.call(event)
|
288
|
+
else
|
289
|
+
@block.call(event)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# @!visibility private
|
294
|
+
def matches?(event)
|
295
|
+
return false unless event.is_a? ApplicationCommandEvent
|
296
|
+
|
297
|
+
[
|
298
|
+
matches_all(@attributes[:name], event.command_name) do |a, e|
|
299
|
+
a.to_sym == e.to_sym
|
300
|
+
end
|
301
|
+
].reduce(true, &:&)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
# Builder for adding subcommands to an ApplicationCommandHandler
|
306
|
+
class SubcommandBuilder
|
307
|
+
# @!visibility private
|
308
|
+
# @param group [String, Symbol, nil]
|
309
|
+
def initialize(group = nil)
|
310
|
+
@group = group&.to_sym
|
311
|
+
@subcommands = {}
|
312
|
+
end
|
313
|
+
|
314
|
+
# @param name [Symbol, String]
|
315
|
+
# @yieldparam [ApplicationCommandEvent]
|
316
|
+
def subcommand(name, &block)
|
317
|
+
@subcommands[name.to_sym] = block
|
318
|
+
end
|
319
|
+
|
320
|
+
# @!visibility private
|
321
|
+
def to_h
|
322
|
+
@group ? { @group => @subcommands } : @subcommands
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
# An event for when a user interacts with a component.
|
327
|
+
class ComponentEvent < InteractionCreateEvent
|
328
|
+
# @return [String] User provided data for this button.
|
329
|
+
attr_reader :custom_id
|
330
|
+
|
331
|
+
# @return [Interactions::Message, nil] The message the button originates from.
|
332
|
+
attr_reader :message
|
333
|
+
|
334
|
+
# @!visibility private
|
335
|
+
def initialize(data, bot)
|
336
|
+
super
|
337
|
+
|
338
|
+
@message = Discordrb::Interactions::Message.new(data['message'], bot, @interaction) if data['message']
|
339
|
+
@custom_id = data['data']['custom_id']
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
# Generic handler for component events.
|
344
|
+
class ComponentEventHandler < InteractionCreateEventHandler
|
345
|
+
def matches?(event)
|
346
|
+
return false unless super
|
347
|
+
return false unless event.is_a? ComponentEvent
|
348
|
+
|
349
|
+
[
|
350
|
+
matches_all(@attributes[:custom_id], event.custom_id) do |a, e|
|
351
|
+
# Match regexp and strings
|
352
|
+
case a
|
353
|
+
when Regexp
|
354
|
+
a.match?(e)
|
355
|
+
else
|
356
|
+
a == e
|
357
|
+
end
|
358
|
+
end,
|
359
|
+
matches_all(@attributes[:message], event.message) do |a, e|
|
360
|
+
case a
|
361
|
+
when String, Integer
|
362
|
+
a.resolve_id == e.id
|
363
|
+
else
|
364
|
+
a.id == e.id
|
365
|
+
end
|
366
|
+
end
|
367
|
+
].reduce(&:&)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
# An event for when a user interacts with a button component.
|
372
|
+
class ButtonEvent < ComponentEvent
|
373
|
+
end
|
374
|
+
|
375
|
+
# Event handler for a Button interaction event.
|
376
|
+
class ButtonEventHandler < ComponentEventHandler
|
377
|
+
end
|
378
|
+
|
379
|
+
# Event for when a user interacts with a select string component.
|
380
|
+
class StringSelectEvent < ComponentEvent
|
381
|
+
# @return [Array<String>] Selected values.
|
382
|
+
attr_reader :values
|
383
|
+
|
384
|
+
# @!visibility private
|
385
|
+
def initialize(data, bot)
|
386
|
+
super
|
387
|
+
|
388
|
+
@values = data['data']['values']
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# Event handler for a select string component.
|
393
|
+
class StringSelectEventHandler < ComponentEventHandler
|
394
|
+
end
|
395
|
+
|
396
|
+
# An event for when a user submits a modal.
|
397
|
+
class ModalSubmitEvent < ComponentEvent
|
398
|
+
# @return [Array<TextInputComponent>]
|
399
|
+
attr_reader :components
|
400
|
+
|
401
|
+
# Get the value of an input passed to the modal.
|
402
|
+
# @param custom_id [String] The custom ID of the component to look for.
|
403
|
+
# @return [String, nil]
|
404
|
+
def value(custom_id)
|
405
|
+
get_component(custom_id)&.value
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
# Event handler for a modal submission.
|
410
|
+
class ModalSubmitEventHandler < ComponentEventHandler
|
411
|
+
end
|
412
|
+
|
413
|
+
# Event for when a user interacts with a select user component.
|
414
|
+
class UserSelectEvent < ComponentEvent
|
415
|
+
# @return [Array<User>] Selected values.
|
416
|
+
attr_reader :values
|
417
|
+
|
418
|
+
# @!visibility private
|
419
|
+
def initialize(data, bot)
|
420
|
+
super
|
421
|
+
|
422
|
+
@values = data['data']['values'].map { |e| bot.user(e) }
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
# Event handler for a select user component.
|
427
|
+
class UserSelectEventHandler < ComponentEventHandler
|
428
|
+
end
|
429
|
+
|
430
|
+
# Event for when a user interacts with a select role component.
|
431
|
+
class RoleSelectEvent < ComponentEvent
|
432
|
+
# @return [Array<Role>] Selected values.
|
433
|
+
attr_reader :values
|
434
|
+
|
435
|
+
# @!visibility private
|
436
|
+
def initialize(data, bot)
|
437
|
+
super
|
438
|
+
|
439
|
+
@values = data['data']['values'].map { |e| bot.server(data['guild_id']).role(e) }
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
# Event handler for a select role component.
|
444
|
+
class RoleSelectEventHandler < ComponentEventHandler
|
445
|
+
end
|
446
|
+
|
447
|
+
# Event for when a user interacts with a select mentionable component.
|
448
|
+
class MentionableSelectEvent < ComponentEvent
|
449
|
+
# @return [Hash<Symbol => Array<User>, Symbol => Array<Role>>] Selected values.
|
450
|
+
attr_reader :values
|
451
|
+
|
452
|
+
# @!visibility private
|
453
|
+
def initialize(data, bot)
|
454
|
+
super
|
455
|
+
|
456
|
+
users = data['data']['resolved']['users'].keys.map { |e| bot.user(e) }
|
457
|
+
roles = data['data']['resolved']['roles'] ? data['data']['resolved']['roles'].keys.map { |e| bot.server(data['guild_id']).role(e) } : []
|
458
|
+
@values = { users: users, roles: roles }
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
# Event handler for a select mentionable component.
|
463
|
+
class MentionableSelectEventHandler < ComponentEventHandler
|
464
|
+
end
|
465
|
+
|
466
|
+
# Event for when a user interacts with a select channel component.
|
467
|
+
class ChannelSelectEvent < ComponentEvent
|
468
|
+
# @return [Array<Channel>] Selected values.
|
469
|
+
attr_reader :values
|
470
|
+
|
471
|
+
# @!visibility private
|
472
|
+
def initialize(data, bot)
|
473
|
+
super
|
474
|
+
|
475
|
+
@values = data['data']['values'].map { |e| bot.channel(e, bot.server(data['guild_id'])) }
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# Event handler for a select channel component.
|
480
|
+
class ChannelSelectEventHandler < ComponentEventHandler
|
481
|
+
end
|
482
|
+
end
|
@@ -17,9 +17,10 @@ module Discordrb::Events
|
|
17
17
|
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
18
18
|
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
19
19
|
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
20
|
+
# @param components [View, Array<Hash>, nil] A collection of components to attach to the message.
|
20
21
|
# @return [Discordrb::Message] the message that was sent
|
21
|
-
def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil)
|
22
|
-
channel.send_message(content, tts, embed, attachments, allowed_mentions, message_reference)
|
22
|
+
def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
|
23
|
+
channel.send_message(content, tts, embed, attachments, allowed_mentions, message_reference, components)
|
23
24
|
end
|
24
25
|
|
25
26
|
# The same as {#send_message}, but yields a {Webhooks::Embed} for easy building of embedded content inside a block.
|
@@ -30,11 +31,12 @@ module Discordrb::Events
|
|
30
31
|
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
31
32
|
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
32
33
|
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
34
|
+
# @param components [View, Array<Hash>, nil] A collection of components to attach to the message.
|
33
35
|
# @yield [embed] Yields the embed to allow for easy building inside a block.
|
34
36
|
# @yieldparam embed [Discordrb::Webhooks::Embed] The embed from the parameters, or a new one.
|
35
37
|
# @return [Message] The resulting message.
|
36
|
-
def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, &block)
|
37
|
-
channel.send_embed(message, embed, attachments, tts, allowed_mentions, message_reference, &block)
|
38
|
+
def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, components = nil, &block)
|
39
|
+
channel.send_embed(message, embed, attachments, tts, allowed_mentions, message_reference, components, &block)
|
38
40
|
end
|
39
41
|
|
40
42
|
# Sends a temporary message to the channel this message was sent in, right now.
|
@@ -44,8 +46,9 @@ module Discordrb::Events
|
|
44
46
|
# @param embed [Hash, Discordrb::Webhooks::Embed, nil] The rich embed to append to this message.
|
45
47
|
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
46
48
|
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
47
|
-
|
48
|
-
|
49
|
+
# @param components [View, Array<Hash>, nil] A collection of components to attach to the message.
|
50
|
+
def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, components = nil)
|
51
|
+
channel.send_temporary_message(content, timeout, tts, embed, attachments, allowed_mentions, components)
|
49
52
|
end
|
50
53
|
|
51
54
|
# Adds a string to be sent after the event has finished execution. Avoids problems with rate limiting because only
|
@@ -65,28 +65,35 @@ module Discordrb::Events
|
|
65
65
|
# @return [User] the user whose status got updated.
|
66
66
|
attr_reader :user
|
67
67
|
|
68
|
-
# @return [
|
69
|
-
attr_reader :
|
68
|
+
# @return [Discordrb::Activity] The new activity
|
69
|
+
attr_reader :activity
|
70
70
|
|
71
|
-
#
|
72
|
-
|
71
|
+
# @!attribute [r] url
|
72
|
+
# @return [String] the URL to the stream
|
73
73
|
|
74
|
-
#
|
75
|
-
|
74
|
+
# @!attribute [r] details
|
75
|
+
# @return [String] what the player is currently doing (ex. game being streamed)
|
76
76
|
|
77
|
-
#
|
78
|
-
|
77
|
+
# @!attribute [r] type
|
78
|
+
# @return [Integer] the type of play. See {Discordrb::Activity}
|
79
|
+
delegate :url, :details, :type, to: :activity
|
79
80
|
|
80
|
-
|
81
|
+
# @return [Hash<Symbol, Symbol>] the current online status (`:online`, `:idle` or `:dnd`) of the user
|
82
|
+
# on various device types (`:desktop`, `:mobile`, or `:web`). The value will be `nil` if the user is offline or invisible.
|
83
|
+
attr_reader :client_status
|
84
|
+
|
85
|
+
def initialize(data, activity, bot)
|
81
86
|
@bot = bot
|
87
|
+
@activity = activity
|
82
88
|
|
83
89
|
@server = bot.server(data['guild_id'].to_i)
|
84
90
|
@user = bot.user(data['user']['id'].to_i)
|
85
|
-
@
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
91
|
+
@client_status = @user.client_status
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [String] the name of the new game the user is playing.
|
95
|
+
def game
|
96
|
+
@activity.name
|
90
97
|
end
|
91
98
|
end
|
92
99
|
|
@@ -137,7 +137,6 @@ module Discordrb::Events
|
|
137
137
|
# Check for the proper event type
|
138
138
|
return false unless event.is_a? ReactionRemoveAllEvent
|
139
139
|
|
140
|
-
# No attributes yet as there is no property available on the event that doesn't involve doing a resolution request
|
141
140
|
[
|
142
141
|
matches_all(@attributes[:message], event.message_id) do |a, e|
|
143
142
|
a == e
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Discordrb::Events
|
4
|
+
# Raised when a thread is created
|
5
|
+
class ThreadCreateEvent < Event
|
6
|
+
# @return [Channel] the thread in question.
|
7
|
+
attr_reader :thread
|
8
|
+
|
9
|
+
delegate :name, :server, :owner, :parent_channel, :thread_metadata, to: :thread
|
10
|
+
|
11
|
+
def initialize(data, bot)
|
12
|
+
@bot = bot
|
13
|
+
@thread = data.is_a?(Discordrb::Channel) ? data : bot.channel(data['id'].to_i)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Event handler for ChannelCreateEvent
|
18
|
+
class ThreadCreateEventHandler < EventHandler
|
19
|
+
def matches?(event)
|
20
|
+
# Check for the proper event type
|
21
|
+
return false unless event.is_a? ThreadCreateEvent
|
22
|
+
|
23
|
+
[
|
24
|
+
matches_all(@attributes[:name], event.name) do |a, e|
|
25
|
+
a == if a.is_a? String
|
26
|
+
e.to_s
|
27
|
+
else
|
28
|
+
e
|
29
|
+
end
|
30
|
+
end,
|
31
|
+
matches_all(@attributes[:server], event.server) do |a, e|
|
32
|
+
a.resolve_id == e.resolve_id
|
33
|
+
end,
|
34
|
+
matches_all(@attributes[:invitable], event.thread.invitable) do |a, e|
|
35
|
+
a == e
|
36
|
+
end,
|
37
|
+
matches_all(@attributes[:owner], event.thread.owner) do |a, e|
|
38
|
+
a.resolve_id == e.resolve_id
|
39
|
+
end,
|
40
|
+
matches_all(@attributes[:channel], event.thread.parent) do |a, e|
|
41
|
+
a.resolve_id == e.resolve_id
|
42
|
+
end
|
43
|
+
].reduce(true, &:&)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Raised when a thread is updated (e.g. name changes)
|
48
|
+
class ThreadUpdateEvent < ThreadCreateEvent; end
|
49
|
+
|
50
|
+
# Event handler for ThreadUpdateEvent
|
51
|
+
class ThreadUpdateEventHandler < ThreadCreateEventHandler
|
52
|
+
def matches?(event)
|
53
|
+
# Check for the proper event type
|
54
|
+
return false unless event.is_a? ThreadUpdateEvent
|
55
|
+
|
56
|
+
super
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Raised when members are added or removed from a thread.
|
61
|
+
class ThreadMembersUpdateEvent < Event
|
62
|
+
# @return [Channel]
|
63
|
+
attr_reader :thread
|
64
|
+
|
65
|
+
# @return [Array<Member, User>]
|
66
|
+
attr_reader :added_members
|
67
|
+
|
68
|
+
# @return [Array<Integer>]
|
69
|
+
attr_reader :removed_member_ids
|
70
|
+
|
71
|
+
# @return [Integer]
|
72
|
+
attr_reader :member_count
|
73
|
+
|
74
|
+
delegate :name, :server, :owner, :parent_channel, :thread_metadata, to: :thread
|
75
|
+
|
76
|
+
def initialize(data, bot)
|
77
|
+
@bot = bot
|
78
|
+
@thread = data.is_a?(Discordrb::Channel) ? data : bot.channel(data['id'].to_i)
|
79
|
+
@added_members = data['added_members']&.map do |member|
|
80
|
+
data['guild_id'] ? bot.member(data['guild_id'], member['user_id']) : bot.user(member['user_id'])
|
81
|
+
end || []
|
82
|
+
@removed_member_ids = data['removed_member_ids']&.map(&:resolve_id) || []
|
83
|
+
@member_count = data['member_count']
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Event handler for ThreadMembersUpdateEvent
|
88
|
+
class ThreadMembersUpdateEventHandler < ThreadCreateEventHandler
|
89
|
+
def matches?(event)
|
90
|
+
# Check for the proper event type
|
91
|
+
return false unless event.is_a? ThreadMembersUpdateEvent
|
92
|
+
|
93
|
+
super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|