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.
- checksums.yaml +4 -4
- data/.devcontainer/Dockerfile +13 -0
- data/.devcontainer/devcontainer.json +29 -0
- data/.devcontainer/postcreate.sh +4 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
- data/.github/workflows/ci.yml +78 -0
- data/.github/workflows/codeql.yml +65 -0
- data/.github/workflows/deploy.yml +54 -0
- data/.github/workflows/release.yml +45 -0
- data/.markdownlint.json +4 -0
- data/.rubocop.yml +58 -2
- data/CHANGELOG.md +485 -225
- data/LICENSE.txt +1 -1
- data/README.md +38 -26
- data/discordrb-webhooks.gemspec +4 -1
- data/discordrb.gemspec +18 -10
- data/lib/discordrb/api/application.rb +278 -0
- data/lib/discordrb/api/channel.rb +222 -18
- data/lib/discordrb/api/interaction.rb +63 -0
- data/lib/discordrb/api/invite.rb +2 -2
- data/lib/discordrb/api/server.rb +123 -66
- data/lib/discordrb/api/user.rb +20 -5
- data/lib/discordrb/api/webhook.rb +72 -0
- data/lib/discordrb/api.rb +35 -25
- data/lib/discordrb/bot.rb +437 -66
- data/lib/discordrb/cache.rb +41 -22
- data/lib/discordrb/commands/command_bot.rb +13 -21
- data/lib/discordrb/commands/container.rb +1 -1
- data/lib/discordrb/commands/parser.rb +7 -7
- data/lib/discordrb/commands/rate_limiter.rb +1 -1
- data/lib/discordrb/container.rb +178 -3
- data/lib/discordrb/data/activity.rb +1 -1
- data/lib/discordrb/data/application.rb +1 -0
- data/lib/discordrb/data/attachment.rb +38 -3
- data/lib/discordrb/data/audit_logs.rb +3 -3
- data/lib/discordrb/data/avatar_decoration.rb +26 -0
- data/lib/discordrb/data/call.rb +22 -0
- data/lib/discordrb/data/channel.rb +299 -30
- data/lib/discordrb/data/collectibles.rb +45 -0
- data/lib/discordrb/data/component.rb +229 -0
- data/lib/discordrb/data/embed.rb +10 -3
- data/lib/discordrb/data/emoji.rb +20 -1
- data/lib/discordrb/data/integration.rb +45 -3
- data/lib/discordrb/data/interaction.rb +937 -0
- data/lib/discordrb/data/invite.rb +1 -1
- data/lib/discordrb/data/member.rb +236 -44
- data/lib/discordrb/data/message.rb +278 -51
- data/lib/discordrb/data/overwrite.rb +15 -7
- data/lib/discordrb/data/primary_server.rb +60 -0
- data/lib/discordrb/data/profile.rb +2 -7
- data/lib/discordrb/data/reaction.rb +2 -1
- data/lib/discordrb/data/recipient.rb +1 -1
- data/lib/discordrb/data/role.rb +204 -18
- data/lib/discordrb/data/server.rb +194 -118
- data/lib/discordrb/data/server_preview.rb +68 -0
- data/lib/discordrb/data/snapshot.rb +110 -0
- data/lib/discordrb/data/user.rb +132 -12
- data/lib/discordrb/data/voice_region.rb +1 -0
- data/lib/discordrb/data/webhook.rb +99 -9
- data/lib/discordrb/data.rb +9 -0
- data/lib/discordrb/errors.rb +47 -3
- data/lib/discordrb/events/await.rb +1 -1
- data/lib/discordrb/events/channels.rb +38 -1
- data/lib/discordrb/events/generic.rb +2 -0
- data/lib/discordrb/events/guilds.rb +6 -1
- data/lib/discordrb/events/interactions.rb +575 -0
- data/lib/discordrb/events/invites.rb +2 -0
- data/lib/discordrb/events/members.rb +19 -2
- data/lib/discordrb/events/message.rb +42 -8
- data/lib/discordrb/events/presence.rb +23 -14
- data/lib/discordrb/events/raw.rb +1 -0
- data/lib/discordrb/events/reactions.rb +2 -1
- data/lib/discordrb/events/roles.rb +2 -0
- data/lib/discordrb/events/threads.rb +100 -0
- data/lib/discordrb/events/typing.rb +1 -0
- data/lib/discordrb/events/voice_server_update.rb +1 -0
- data/lib/discordrb/events/voice_state_update.rb +1 -0
- data/lib/discordrb/events/webhooks.rb +1 -0
- data/lib/discordrb/gateway.rb +57 -28
- data/lib/discordrb/paginator.rb +3 -3
- data/lib/discordrb/permissions.rb +71 -35
- 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/websocket.rb +0 -10
- data/lib/discordrb.rb +54 -5
- metadata +87 -25
- data/.circleci/config.yml +0 -126
- data/.codeclimate.yml +0 -16
- data/.travis.yml +0 -32
- data/bin/travis_build_docs.sh +0 -17
|
@@ -7,6 +7,7 @@ module Discordrb::Events
|
|
|
7
7
|
class Negated
|
|
8
8
|
attr_reader :object
|
|
9
9
|
|
|
10
|
+
# @!visibility private
|
|
10
11
|
def initialize(object)
|
|
11
12
|
@object = object
|
|
12
13
|
end
|
|
@@ -75,6 +76,7 @@ module Discordrb::Events
|
|
|
75
76
|
|
|
76
77
|
# Generic event handler that can be extended
|
|
77
78
|
class EventHandler
|
|
79
|
+
# @!visibility private
|
|
78
80
|
def initialize(attributes, block)
|
|
79
81
|
@attributes = attributes
|
|
80
82
|
@block = block
|
|
@@ -9,6 +9,7 @@ module Discordrb::Events
|
|
|
9
9
|
# @return [Server] the server in question.
|
|
10
10
|
attr_reader :server
|
|
11
11
|
|
|
12
|
+
# @!visibility private
|
|
12
13
|
def initialize(data, bot)
|
|
13
14
|
@bot = bot
|
|
14
15
|
|
|
@@ -64,7 +65,8 @@ module Discordrb::Events
|
|
|
64
65
|
# @return [Integer] The ID of the server that was left.
|
|
65
66
|
attr_reader :server
|
|
66
67
|
|
|
67
|
-
#
|
|
68
|
+
# @!visibility private
|
|
69
|
+
# @note Override init_server to account for the deleted server
|
|
68
70
|
def init_server(data, _bot)
|
|
69
71
|
@server = data['id'].to_i
|
|
70
72
|
end
|
|
@@ -81,6 +83,7 @@ module Discordrb::Events
|
|
|
81
83
|
# @return [Array<Emoji>] array of emojis.
|
|
82
84
|
attr_reader :emoji
|
|
83
85
|
|
|
86
|
+
# @!visibility private
|
|
84
87
|
def initialize(server, data, bot)
|
|
85
88
|
@bot = bot
|
|
86
89
|
@server = server
|
|
@@ -103,6 +106,7 @@ module Discordrb::Events
|
|
|
103
106
|
# @return [Emoji] the emoji data.
|
|
104
107
|
attr_reader :emoji
|
|
105
108
|
|
|
109
|
+
# @!visibility private
|
|
106
110
|
def initialize(server, emoji, bot)
|
|
107
111
|
@bot = bot
|
|
108
112
|
@emoji = emoji
|
|
@@ -127,6 +131,7 @@ module Discordrb::Events
|
|
|
127
131
|
# @return [Emoji, nil] the updated emoji data.
|
|
128
132
|
attr_reader :emoji
|
|
129
133
|
|
|
134
|
+
# @!visibility private
|
|
130
135
|
def initialize(server, old_emoji, emoji, bot)
|
|
131
136
|
@bot = bot
|
|
132
137
|
@old_emoji = old_emoji
|
|
@@ -0,0 +1,575 @@
|
|
|
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
|
+
# @!visibility private
|
|
33
|
+
def initialize(data, bot)
|
|
34
|
+
@interaction = Discordrb::Interaction.new(data, bot)
|
|
35
|
+
@bot = bot
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @see Interaction#respond
|
|
39
|
+
def respond(...)
|
|
40
|
+
@interaction.respond(...)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @see Interaction#defer
|
|
44
|
+
def defer(...)
|
|
45
|
+
@interaction.defer(...)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @see Interaction#update_message
|
|
49
|
+
def update_message(...)
|
|
50
|
+
@interaction.update_message(...)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @see Interaction#show_modal
|
|
54
|
+
def show_modal(...)
|
|
55
|
+
@interaction.show_modal(...)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @see Interaction#edit_response
|
|
59
|
+
def edit_response(...)
|
|
60
|
+
@interaction.edit_response(...)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @see Interaction#delete_response
|
|
64
|
+
def delete_response
|
|
65
|
+
@interaction.delete_response
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @see Interaction#send_message
|
|
69
|
+
def send_message(...)
|
|
70
|
+
@interaction.send_message(...)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @see Interaction#edit_message
|
|
74
|
+
def edit_message(...)
|
|
75
|
+
@interaction.edit_message(...)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @see Interaction#delete_message
|
|
79
|
+
def delete_message(...)
|
|
80
|
+
@interaction.delete_message(...)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @see Interaction#defer_update
|
|
84
|
+
def defer_update
|
|
85
|
+
@interaction.defer_update
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @see Interaction#get_component
|
|
89
|
+
def get_component(...)
|
|
90
|
+
@interaction.get_component(...)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Event handler for INTERACTION_CREATE events.
|
|
95
|
+
class InteractionCreateEventHandler < EventHandler
|
|
96
|
+
# @!visibility private
|
|
97
|
+
def matches?(event)
|
|
98
|
+
return false unless event.is_a? InteractionCreateEvent
|
|
99
|
+
|
|
100
|
+
[
|
|
101
|
+
matches_all(@attributes[:type], event.type) do |a, e|
|
|
102
|
+
a == case a
|
|
103
|
+
when String, Symbol
|
|
104
|
+
Discordrb::Interactions::TYPES[e.to_sym]
|
|
105
|
+
else
|
|
106
|
+
e
|
|
107
|
+
end
|
|
108
|
+
end,
|
|
109
|
+
|
|
110
|
+
matches_all(@attributes[:server], event.interaction) do |a, e|
|
|
111
|
+
a.resolve_id == e.server_id
|
|
112
|
+
end,
|
|
113
|
+
|
|
114
|
+
matches_all(@attributes[:channel], event.interaction) do |a, e|
|
|
115
|
+
a.resolve_id == e.channel_id
|
|
116
|
+
end,
|
|
117
|
+
|
|
118
|
+
matches_all(@attributes[:user], event.user) do |a, e|
|
|
119
|
+
a.resolve_id == e.id
|
|
120
|
+
end
|
|
121
|
+
].reduce(true, &:&)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Event for ApplicationCommand interactions.
|
|
126
|
+
class ApplicationCommandEvent < InteractionCreateEvent
|
|
127
|
+
# Struct to allow accessing data via [] or methods.
|
|
128
|
+
Resolved = Struct.new('Resolved', :channels, :members, :messages, :roles, :users, :attachments) # rubocop:disable Lint/StructNewOverride
|
|
129
|
+
|
|
130
|
+
# @return [Symbol] The name of the command.
|
|
131
|
+
attr_reader :command_name
|
|
132
|
+
|
|
133
|
+
# @return [Integer] The ID of the command.
|
|
134
|
+
attr_reader :command_id
|
|
135
|
+
|
|
136
|
+
# @return [Symbol, nil] The name of the subcommand group relevant to this event.
|
|
137
|
+
attr_reader :subcommand_group
|
|
138
|
+
|
|
139
|
+
# @return [Symbol, nil] The name of the subcommand relevant to this event.
|
|
140
|
+
attr_reader :subcommand
|
|
141
|
+
|
|
142
|
+
# @return [Resolved]
|
|
143
|
+
attr_reader :resolved
|
|
144
|
+
|
|
145
|
+
# @return [Hash<Symbol, Object>] Arguments provided to the command, mapped as `Name => Value`.
|
|
146
|
+
attr_reader :options
|
|
147
|
+
|
|
148
|
+
# @return [Integer, nil] The target of this command when it is a context command.
|
|
149
|
+
attr_reader :target_id
|
|
150
|
+
|
|
151
|
+
# @!visibility private
|
|
152
|
+
def initialize(data, bot)
|
|
153
|
+
super
|
|
154
|
+
|
|
155
|
+
command_data = data['data']
|
|
156
|
+
|
|
157
|
+
@command_id = command_data['id']
|
|
158
|
+
@command_name = command_data['name'].to_sym
|
|
159
|
+
|
|
160
|
+
@target_id = command_data['target_id']&.to_i
|
|
161
|
+
@resolved = Resolved.new({}, {}, {}, {}, {}, {})
|
|
162
|
+
process_resolved(command_data['resolved']) if command_data['resolved']
|
|
163
|
+
|
|
164
|
+
options = command_data['options'] || []
|
|
165
|
+
|
|
166
|
+
if options.empty?
|
|
167
|
+
@options = {}
|
|
168
|
+
return
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
case options[0]['type']
|
|
172
|
+
when 2
|
|
173
|
+
options = options[0]
|
|
174
|
+
@subcommand_group = options['name'].to_sym
|
|
175
|
+
@subcommand = options['options'][0]['name'].to_sym
|
|
176
|
+
options = options['options'][0]['options']
|
|
177
|
+
when 1
|
|
178
|
+
options = options[0]
|
|
179
|
+
@subcommand = options['name'].to_sym
|
|
180
|
+
options = options['options']
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
@options = transform_options_hash(options || {})
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# @return [Message, User, nil] The target of this command, for context commands.
|
|
187
|
+
def target
|
|
188
|
+
return nil unless @target_id
|
|
189
|
+
|
|
190
|
+
@resolved.find { |data| data.key?(@target_id) }[@target_id]
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
private
|
|
194
|
+
|
|
195
|
+
def process_resolved(resolved_data)
|
|
196
|
+
resolved_data['users']&.each do |id, data|
|
|
197
|
+
@resolved[:users][id.to_i] = @bot.ensure_user(data)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
resolved_data['roles']&.each do |id, data|
|
|
201
|
+
@resolved[:roles][id.to_i] = Discordrb::Role.new(data, @bot)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
resolved_data['channels']&.each do |id, data|
|
|
205
|
+
data['guild_id'] = @interaction.server_id
|
|
206
|
+
@resolved[:channels][id.to_i] = Discordrb::Channel.new(data, @bot)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
resolved_data['members']&.each do |id, data|
|
|
210
|
+
data['user'] = resolved_data['users'][id]
|
|
211
|
+
data['guild_id'] = @interaction.server_id
|
|
212
|
+
@resolved[:members][id.to_i] = Discordrb::Member.new(data, nil, @bot)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
resolved_data['messages']&.each do |id, data|
|
|
216
|
+
@resolved[:messages][id.to_i] = Discordrb::Message.new(data, @bot)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
resolved_data['attachments']&.each do |id, data|
|
|
220
|
+
@resolved[:attachments][id.to_i] = Discordrb::Attachment.new(data, nil, @bot)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def transform_options_hash(hash)
|
|
225
|
+
hash.to_h { |opt| [opt['name'], opt['options'] || opt['value']] }
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Event handler for ApplicationCommandEvents.
|
|
230
|
+
class ApplicationCommandEventHandler < EventHandler
|
|
231
|
+
# @return [Hash]
|
|
232
|
+
attr_reader :subcommands
|
|
233
|
+
|
|
234
|
+
# @!visibility private
|
|
235
|
+
def initialize(attributes, block)
|
|
236
|
+
super
|
|
237
|
+
|
|
238
|
+
@subcommands = {}
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# @param name [Symbol, String]
|
|
242
|
+
# @yieldparam [SubcommandBuilder]
|
|
243
|
+
# @return [ApplicationCommandEventHandler]
|
|
244
|
+
def group(name)
|
|
245
|
+
raise ArgumentError, 'Unable to mix subcommands and groups' if @subcommands.any? { |n, v| n == name && v.is_a?(Proc) }
|
|
246
|
+
|
|
247
|
+
builder = SubcommandBuilder.new(name)
|
|
248
|
+
yield builder
|
|
249
|
+
|
|
250
|
+
@subcommands.merge!(builder.to_h)
|
|
251
|
+
self
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# @param name [String, Symbol]
|
|
255
|
+
# @yieldparam [SubcommandBuilder]
|
|
256
|
+
# @return [ApplicationCommandEventHandler]
|
|
257
|
+
def subcommand(name, &block)
|
|
258
|
+
raise ArgumentError, 'Unable to mix subcommands and groups' if @subcommands.any? { |n, v| n == name && v.is_a?(Hash) }
|
|
259
|
+
|
|
260
|
+
@subcommands[name.to_sym] = block
|
|
261
|
+
|
|
262
|
+
self
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# @!visibility private
|
|
266
|
+
# @param event [Event]
|
|
267
|
+
def call(event)
|
|
268
|
+
return unless matches?(event)
|
|
269
|
+
|
|
270
|
+
if event.subcommand_group
|
|
271
|
+
unless (cmd = @subcommands.dig(event.subcommand_group, event.subcommand))
|
|
272
|
+
Discordrb::LOGGER.debug("Received an event for an unhandled subcommand `#{event.command_name} #{event.subcommand_group} #{event.subcommand}'")
|
|
273
|
+
return
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
cmd.call(event)
|
|
277
|
+
elsif event.subcommand
|
|
278
|
+
unless (cmd = @subcommands[event.subcommand])
|
|
279
|
+
Discordrb::LOGGER.debug("Received an event for an unhandled subcommand `#{event.command_name} #{event.subcommand}'")
|
|
280
|
+
return
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
cmd.call(event)
|
|
284
|
+
else
|
|
285
|
+
@block.call(event)
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# @!visibility private
|
|
290
|
+
def matches?(event)
|
|
291
|
+
return false unless event.is_a? ApplicationCommandEvent
|
|
292
|
+
|
|
293
|
+
[
|
|
294
|
+
matches_all(@attributes[:name], event.command_name) do |a, e|
|
|
295
|
+
a.to_sym == e.to_sym
|
|
296
|
+
end
|
|
297
|
+
].reduce(true, &:&)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Builder for adding subcommands to an ApplicationCommandHandler
|
|
302
|
+
class SubcommandBuilder
|
|
303
|
+
# @!visibility private
|
|
304
|
+
# @param group [String, Symbol, nil]
|
|
305
|
+
def initialize(group = nil)
|
|
306
|
+
@group = group&.to_sym
|
|
307
|
+
@subcommands = {}
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# @param name [Symbol, String]
|
|
311
|
+
# @yieldparam [ApplicationCommandEvent]
|
|
312
|
+
def subcommand(name, &block)
|
|
313
|
+
@subcommands[name.to_sym] = block
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# @!visibility private
|
|
317
|
+
def to_h
|
|
318
|
+
@group ? { @group => @subcommands } : @subcommands
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# An event for when a user interacts with a component.
|
|
323
|
+
class ComponentEvent < InteractionCreateEvent
|
|
324
|
+
# @return [String] User provided data for this button.
|
|
325
|
+
attr_reader :custom_id
|
|
326
|
+
|
|
327
|
+
# @return [Interactions::Message, nil] The message the button originates from.
|
|
328
|
+
attr_reader :message
|
|
329
|
+
|
|
330
|
+
# @!visibility private
|
|
331
|
+
def initialize(data, bot)
|
|
332
|
+
super
|
|
333
|
+
|
|
334
|
+
@message = Discordrb::Interactions::Message.new(data['message'], bot, @interaction) if data['message']
|
|
335
|
+
@custom_id = data['data']['custom_id']
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Generic handler for component events.
|
|
340
|
+
class ComponentEventHandler < InteractionCreateEventHandler
|
|
341
|
+
def matches?(event)
|
|
342
|
+
return false unless super
|
|
343
|
+
return false unless event.is_a? ComponentEvent
|
|
344
|
+
|
|
345
|
+
[
|
|
346
|
+
matches_all(@attributes[:custom_id], event.custom_id) do |a, e|
|
|
347
|
+
# Match regexp and strings
|
|
348
|
+
case a
|
|
349
|
+
when Regexp
|
|
350
|
+
a.match?(e)
|
|
351
|
+
else
|
|
352
|
+
a == e
|
|
353
|
+
end
|
|
354
|
+
end,
|
|
355
|
+
matches_all(@attributes[:message], event.message) do |a, e|
|
|
356
|
+
case a
|
|
357
|
+
when String, Integer
|
|
358
|
+
a.resolve_id == e.id
|
|
359
|
+
else
|
|
360
|
+
a.id == e.id
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
].reduce(&:&)
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# An event for when a user interacts with a button component.
|
|
368
|
+
class ButtonEvent < ComponentEvent
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Event handler for a Button interaction event.
|
|
372
|
+
class ButtonEventHandler < ComponentEventHandler
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# Event for when a user interacts with a select string component.
|
|
376
|
+
class StringSelectEvent < ComponentEvent
|
|
377
|
+
# @return [Array<String>] Selected values.
|
|
378
|
+
attr_reader :values
|
|
379
|
+
|
|
380
|
+
# @!visibility private
|
|
381
|
+
def initialize(data, bot)
|
|
382
|
+
super
|
|
383
|
+
|
|
384
|
+
@values = data['data']['values']
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# Event handler for a select string component.
|
|
389
|
+
class StringSelectEventHandler < ComponentEventHandler
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
# An event for when a user submits a modal.
|
|
393
|
+
class ModalSubmitEvent < ComponentEvent
|
|
394
|
+
# @return [Array<TextInputComponent>]
|
|
395
|
+
attr_reader :components
|
|
396
|
+
|
|
397
|
+
# Get the value of an input passed to the modal.
|
|
398
|
+
# @param custom_id [String] The custom ID of the component to look for.
|
|
399
|
+
# @return [String, nil]
|
|
400
|
+
def value(custom_id)
|
|
401
|
+
get_component(custom_id)&.value
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# Event handler for a modal submission.
|
|
406
|
+
class ModalSubmitEventHandler < ComponentEventHandler
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# Event for when a user interacts with a select user component.
|
|
410
|
+
class UserSelectEvent < ComponentEvent
|
|
411
|
+
# @return [Array<User>] Selected values.
|
|
412
|
+
attr_reader :values
|
|
413
|
+
|
|
414
|
+
# @!visibility private
|
|
415
|
+
def initialize(data, bot)
|
|
416
|
+
super
|
|
417
|
+
|
|
418
|
+
@values = data['data']['values'].map { |e| bot.user(e) }
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# Event handler for a select user component.
|
|
423
|
+
class UserSelectEventHandler < ComponentEventHandler
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
# Event for when a user interacts with a select role component.
|
|
427
|
+
class RoleSelectEvent < ComponentEvent
|
|
428
|
+
# @return [Array<Role>] Selected values.
|
|
429
|
+
attr_reader :values
|
|
430
|
+
|
|
431
|
+
# @!visibility private
|
|
432
|
+
def initialize(data, bot)
|
|
433
|
+
super
|
|
434
|
+
|
|
435
|
+
@values = data['data']['values'].map { |e| bot.server(data['guild_id']).role(e) }
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
# Event handler for a select role component.
|
|
440
|
+
class RoleSelectEventHandler < ComponentEventHandler
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# Event for when a user interacts with a select mentionable component.
|
|
444
|
+
class MentionableSelectEvent < ComponentEvent
|
|
445
|
+
# @return [Hash<Symbol => Array<User>, Symbol => Array<Role>>] Selected values.
|
|
446
|
+
attr_reader :values
|
|
447
|
+
|
|
448
|
+
# @!visibility private
|
|
449
|
+
def initialize(data, bot)
|
|
450
|
+
super
|
|
451
|
+
|
|
452
|
+
users = data['data']['resolved']['users'].keys.map { |e| bot.user(e) }
|
|
453
|
+
roles = data['data']['resolved']['roles'] ? data['data']['resolved']['roles'].keys.map { |e| bot.server(data['guild_id']).role(e) } : []
|
|
454
|
+
@values = { users: users, roles: roles }
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
# Event handler for a select mentionable component.
|
|
459
|
+
class MentionableSelectEventHandler < ComponentEventHandler
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
# Event for when a user interacts with a select channel component.
|
|
463
|
+
class ChannelSelectEvent < ComponentEvent
|
|
464
|
+
# @return [Array<Channel>] Selected values.
|
|
465
|
+
attr_reader :values
|
|
466
|
+
|
|
467
|
+
# @!visibility private
|
|
468
|
+
def initialize(data, bot)
|
|
469
|
+
super
|
|
470
|
+
|
|
471
|
+
@values = data['data']['values'].map { |e| bot.channel(e, bot.server(data['guild_id'])) }
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
# Event handler for a select channel component.
|
|
476
|
+
class ChannelSelectEventHandler < ComponentEventHandler
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# Event handler for an autocomplete option choices.
|
|
480
|
+
class AutocompleteEventHandler < InteractionCreateEventHandler
|
|
481
|
+
def matches?(event)
|
|
482
|
+
return false unless super
|
|
483
|
+
return false unless event.is_a?(AutocompleteEvent)
|
|
484
|
+
|
|
485
|
+
[
|
|
486
|
+
matches_all(@attributes[:name], event.focused) { |a, e| a&.to_s == e },
|
|
487
|
+
matches_all(@attributes[:command_id], event.command_id) { |a, e| a&.to_i == e },
|
|
488
|
+
matches_all(@attributes[:subcommand], event.subcommand) { |a, e| a&.to_sym == e },
|
|
489
|
+
matches_all(@attributes[:command_name], event.command_name) { |a, e| a&.to_sym == e },
|
|
490
|
+
matches_all(@attributes[:subcommand_group], event.subcommand_group) { |a, e| a&.to_sym == e },
|
|
491
|
+
matches_all(@attributes[:server], event.server_id) { |a, e| a&.resolve_id == e }
|
|
492
|
+
].reduce(&:&)
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
# An event for an autocomplete option choice.
|
|
497
|
+
class AutocompleteEvent < ApplicationCommandEvent
|
|
498
|
+
# @return [String] Name of the currently focused option.
|
|
499
|
+
attr_reader :focused
|
|
500
|
+
|
|
501
|
+
# @return [Hash] An empty hash that can be used to return choices by adding K/V pairs.
|
|
502
|
+
attr_reader :choices
|
|
503
|
+
|
|
504
|
+
# @!visibility private
|
|
505
|
+
def initialize(data, bot)
|
|
506
|
+
super
|
|
507
|
+
|
|
508
|
+
@choices = {}
|
|
509
|
+
|
|
510
|
+
options = data['data']['options']
|
|
511
|
+
|
|
512
|
+
options = case options[0]['type']
|
|
513
|
+
when 1
|
|
514
|
+
options[0]['options']
|
|
515
|
+
when 2
|
|
516
|
+
options[0]['options'][0]['options']
|
|
517
|
+
else
|
|
518
|
+
options
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
@focused = options.find { |opt| opt.key?('focused') }['name']
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
# Respond to this interaction with autocomplete choices.
|
|
525
|
+
# @param choices [Array<Hash>, Hash, nil] Autocomplete choices to return.
|
|
526
|
+
def respond(choices:)
|
|
527
|
+
@interaction.show_autocomplete_choices(choices || [])
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
# An event for whenever an application command's permissions are updated.
|
|
532
|
+
class ApplicationCommandPermissionsUpdateEvent < Event
|
|
533
|
+
# @return [Integer] the ID of the server where the command permissions were updated.
|
|
534
|
+
attr_reader :server_id
|
|
535
|
+
|
|
536
|
+
# @return [Integer, nil] the ID of the application command that was updated.
|
|
537
|
+
attr_reader :command_id
|
|
538
|
+
|
|
539
|
+
# @return [Array<ApplicationCommand::Permission>] the permissions that were updated.
|
|
540
|
+
attr_reader :permissions
|
|
541
|
+
|
|
542
|
+
# @return [Integer] the ID of the application whose commands were updated.
|
|
543
|
+
attr_reader :application_id
|
|
544
|
+
|
|
545
|
+
# @!visibility private
|
|
546
|
+
def initialize(data, bot)
|
|
547
|
+
@bot = bot
|
|
548
|
+
@server_id = data['guild_id'].to_i
|
|
549
|
+
@application_id = data['application_id'].to_i
|
|
550
|
+
@command_id = data['id'].to_i if data['id'].to_i != @application_id
|
|
551
|
+
@permissions = data['permissions'].map do |permission|
|
|
552
|
+
Discordrb::ApplicationCommand::Permission.new(permission, data, bot)
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
# @return [Server] the server where the command's permissions were updated.
|
|
557
|
+
def server
|
|
558
|
+
@bot.server(@server_id)
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
# Event handler for the APPLICATION_COMMAND_PERMISSIONS_UPDATE event.
|
|
563
|
+
class ApplicationCommandPermissionsUpdateEventHandler < EventHandler
|
|
564
|
+
# @!visibility private
|
|
565
|
+
def matches?(event)
|
|
566
|
+
return false unless event.is_a?(ApplicationCommandPermissionsUpdateEvent)
|
|
567
|
+
|
|
568
|
+
[
|
|
569
|
+
matches_all(@attributes[:server], event.server_id) { |a, e| a.resolve_id == e },
|
|
570
|
+
matches_all(@attributes[:command_id], event.command_id) { |a, e| a.resolve_id == e },
|
|
571
|
+
matches_all(@attributes[:application_id], event.application_id) { |a, e| a.resolve_id == e }
|
|
572
|
+
].reduce(&:&)
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
end
|
|
@@ -34,6 +34,7 @@ module Discordrb::Events
|
|
|
34
34
|
|
|
35
35
|
alias temporary? temporary
|
|
36
36
|
|
|
37
|
+
# @!visibility private
|
|
37
38
|
def initialize(data, invite, bot)
|
|
38
39
|
@bot = bot
|
|
39
40
|
@invite = invite
|
|
@@ -53,6 +54,7 @@ module Discordrb::Events
|
|
|
53
54
|
# @return [String] The code of the deleted invite.
|
|
54
55
|
attr_reader :code
|
|
55
56
|
|
|
57
|
+
# @!visibility private
|
|
56
58
|
def initialize(data, bot)
|
|
57
59
|
@bot = bot
|
|
58
60
|
@channel = bot.channel(data['channel_id'])
|
|
@@ -16,6 +16,7 @@ module Discordrb::Events
|
|
|
16
16
|
# @return [Server] the server on which the event happened.
|
|
17
17
|
attr_reader :server
|
|
18
18
|
|
|
19
|
+
# @!visibility private
|
|
19
20
|
def initialize(data, bot)
|
|
20
21
|
@bot = bot
|
|
21
22
|
|
|
@@ -28,11 +29,13 @@ module Discordrb::Events
|
|
|
28
29
|
|
|
29
30
|
private
|
|
30
31
|
|
|
32
|
+
# @!visibility private
|
|
31
33
|
def init_user(data, _)
|
|
32
34
|
user_id = data['user']['id'].to_i
|
|
33
35
|
@user = @server.member(user_id)
|
|
34
36
|
end
|
|
35
37
|
|
|
38
|
+
# @!visibility private
|
|
36
39
|
def init_roles(data, _)
|
|
37
40
|
@roles = [@server.role(@server.id)]
|
|
38
41
|
return unless data['roles']
|
|
@@ -71,7 +74,20 @@ module Discordrb::Events
|
|
|
71
74
|
|
|
72
75
|
# Member is updated (roles added or deleted)
|
|
73
76
|
# @see Discordrb::EventContainer#member_update
|
|
74
|
-
class ServerMemberUpdateEvent < ServerMemberEvent
|
|
77
|
+
class ServerMemberUpdateEvent < ServerMemberEvent
|
|
78
|
+
# @!visibility private
|
|
79
|
+
# @note Override init_user so we don't make requests all the time on large servers
|
|
80
|
+
def init_user(data, _)
|
|
81
|
+
@user_id = data['user']['id']
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @return [Member] the member in question.
|
|
85
|
+
def user
|
|
86
|
+
@server&.member(@user_id)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
alias_method :member, :user
|
|
90
|
+
end
|
|
75
91
|
|
|
76
92
|
# Event handler for {ServerMemberUpdateEvent}
|
|
77
93
|
class ServerMemberUpdateEventHandler < ServerMemberEventHandler; end
|
|
@@ -79,7 +95,8 @@ module Discordrb::Events
|
|
|
79
95
|
# Member leaves
|
|
80
96
|
# @see Discordrb::EventContainer#member_leave
|
|
81
97
|
class ServerMemberDeleteEvent < ServerMemberEvent
|
|
82
|
-
#
|
|
98
|
+
# @!visibility private
|
|
99
|
+
# @note Override init_user to account for the deleted user on the server
|
|
83
100
|
def init_user(data, bot)
|
|
84
101
|
@user = Discordrb::User.new(data['user'], bot)
|
|
85
102
|
end
|