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
|
@@ -5,17 +5,80 @@ module Discordrb
|
|
|
5
5
|
class Message
|
|
6
6
|
include IDObject
|
|
7
7
|
|
|
8
|
+
# Map of message flags.
|
|
9
|
+
FLAGS = {
|
|
10
|
+
crossposted: 1 << 0,
|
|
11
|
+
crosspost: 1 << 1,
|
|
12
|
+
suppress_embeds: 1 << 2,
|
|
13
|
+
source_message_deleted: 1 << 3,
|
|
14
|
+
urgent: 1 << 4,
|
|
15
|
+
thread: 1 << 5,
|
|
16
|
+
ephemeral: 1 << 6,
|
|
17
|
+
loading: 1 << 7,
|
|
18
|
+
failed_to_mention_roles: 1 << 8,
|
|
19
|
+
suppress_notifications: 1 << 12,
|
|
20
|
+
voice_message: 1 << 13,
|
|
21
|
+
snapshot: 1 << 14,
|
|
22
|
+
uikit_components: 1 << 15
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
# Map of message types.
|
|
26
|
+
TYPES = {
|
|
27
|
+
default: 0,
|
|
28
|
+
recipient_add: 1,
|
|
29
|
+
recipient_remove: 2,
|
|
30
|
+
call: 3,
|
|
31
|
+
channel_name_change: 4,
|
|
32
|
+
channel_icon_change: 5,
|
|
33
|
+
channel_pinned_message: 6,
|
|
34
|
+
server_member_join: 7,
|
|
35
|
+
server_boost: 8,
|
|
36
|
+
server_boost_tier_one: 9,
|
|
37
|
+
server_boost_tier_two: 10,
|
|
38
|
+
server_boost_tier_three: 11,
|
|
39
|
+
channel_follow_add: 12,
|
|
40
|
+
server_discovery_disqualified: 14,
|
|
41
|
+
server_discovery_requalified: 15,
|
|
42
|
+
server_discovery_grace_period_initial_warning: 16,
|
|
43
|
+
server_discovery_grace_period_final_warning: 17,
|
|
44
|
+
thread_created: 18,
|
|
45
|
+
reply: 19,
|
|
46
|
+
chat_input_command: 20,
|
|
47
|
+
thread_starter_message: 21,
|
|
48
|
+
server_invite_reminder: 22,
|
|
49
|
+
context_menu_command: 23,
|
|
50
|
+
automod_action: 24,
|
|
51
|
+
role_subscription_purchase: 25,
|
|
52
|
+
interaction_premium_upsell: 26,
|
|
53
|
+
stage_start: 27,
|
|
54
|
+
stage_end: 28,
|
|
55
|
+
stage_speaker: 29,
|
|
56
|
+
stage_raise_hand: 30,
|
|
57
|
+
stage_topic: 31,
|
|
58
|
+
server_application_premium_subscription: 32,
|
|
59
|
+
server_incident_alert_mode_enabled: 36,
|
|
60
|
+
server_incident_alert_mode_disabled: 37,
|
|
61
|
+
server_incident_report_raid: 38,
|
|
62
|
+
server_incident_report_false_alarm: 39,
|
|
63
|
+
purchase_notification: 44,
|
|
64
|
+
poll_result: 46,
|
|
65
|
+
changelog: 47,
|
|
66
|
+
server_join_request_accepted: 52,
|
|
67
|
+
server_join_request_rejected: 53,
|
|
68
|
+
server_join_request_withdrawn: 54,
|
|
69
|
+
report_to_mod_deleted_message: 58,
|
|
70
|
+
report_to_mod_timeout_user: 59,
|
|
71
|
+
report_to_mod_kick_user: 60,
|
|
72
|
+
report_to_mod_ban_user: 61,
|
|
73
|
+
report_to_mod_closed_report: 62,
|
|
74
|
+
server_emoji_added: 63
|
|
75
|
+
}.freeze
|
|
76
|
+
|
|
8
77
|
# @return [String] the content of this message.
|
|
9
78
|
attr_reader :content
|
|
10
79
|
alias_method :text, :content
|
|
11
80
|
alias_method :to_s, :content
|
|
12
81
|
|
|
13
|
-
# @return [Member, User] the user that sent this message. (Will be a {Member} most of the time, it should only be a
|
|
14
|
-
# {User} for old messages when the author has left the server since then)
|
|
15
|
-
attr_reader :author
|
|
16
|
-
alias_method :user, :author
|
|
17
|
-
alias_method :writer, :author
|
|
18
|
-
|
|
19
82
|
# @return [Channel] the channel in which this message was sent.
|
|
20
83
|
attr_reader :channel
|
|
21
84
|
|
|
@@ -61,14 +124,32 @@ module Discordrb
|
|
|
61
124
|
attr_reader :pinned
|
|
62
125
|
alias_method :pinned?, :pinned
|
|
63
126
|
|
|
127
|
+
# @return [Integer] what the type of the message is
|
|
128
|
+
attr_reader :type
|
|
129
|
+
|
|
64
130
|
# @return [Server, nil] the server in which this message was sent.
|
|
65
131
|
attr_reader :server
|
|
66
132
|
|
|
67
133
|
# @return [Integer, nil] the webhook ID that sent this message, or `nil` if it wasn't sent through a webhook.
|
|
68
134
|
attr_reader :webhook_id
|
|
69
135
|
|
|
70
|
-
#
|
|
71
|
-
|
|
136
|
+
# @return [Array<Component>] Interaction components for this message.
|
|
137
|
+
attr_reader :components
|
|
138
|
+
|
|
139
|
+
# @return [Integer] flags set on the message.
|
|
140
|
+
attr_reader :flags
|
|
141
|
+
|
|
142
|
+
# @return [Channel, nil] The thread that was started from this message, or nil.
|
|
143
|
+
attr_reader :thread
|
|
144
|
+
|
|
145
|
+
# @return [Time, nil] the time at when this message was pinned. Only present on messages fetched via {Channel#pins}.
|
|
146
|
+
attr_reader :pinned_at
|
|
147
|
+
|
|
148
|
+
# @return [Call, nil] the call in a private channel that prompted this message.
|
|
149
|
+
attr_reader :call
|
|
150
|
+
|
|
151
|
+
# @return [Array<Snapshot>] the message snapshots included in this message.
|
|
152
|
+
attr_reader :snapshots
|
|
72
153
|
|
|
73
154
|
# @!visibility private
|
|
74
155
|
def initialize(data, bot)
|
|
@@ -76,6 +157,7 @@ module Discordrb
|
|
|
76
157
|
@content = data['content']
|
|
77
158
|
@channel = bot.channel(data['channel_id'].to_i)
|
|
78
159
|
@pinned = data['pinned']
|
|
160
|
+
@type = data['type']
|
|
79
161
|
@tts = data['tts']
|
|
80
162
|
@nonce = data['nonce']
|
|
81
163
|
@mention_everyone = data['mention_everyone']
|
|
@@ -85,36 +167,23 @@ module Discordrb
|
|
|
85
167
|
|
|
86
168
|
@server = @channel.server
|
|
87
169
|
|
|
88
|
-
@
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
member = if data['member']
|
|
106
|
-
member_data = data['author'].merge(data['member'])
|
|
107
|
-
Member.new(member_data, bot)
|
|
108
|
-
else
|
|
109
|
-
@bot.ensure_user(data['author'])
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
member
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
@webhook_id = data['webhook_id'].to_i if data['webhook_id']
|
|
170
|
+
@webhook_id = data['webhook_id']&.to_i
|
|
171
|
+
|
|
172
|
+
if data['author']
|
|
173
|
+
if @webhook_id
|
|
174
|
+
# This is a webhook user! It would be pointless to try to resolve a member here, so we just create
|
|
175
|
+
# a User and return that instead.
|
|
176
|
+
Discordrb::LOGGER.debug("Webhook user: #{data['author']['id']}")
|
|
177
|
+
@author = User.new(data['author'].merge({ '_webhook' => true }), @bot)
|
|
178
|
+
elsif @channel.private?
|
|
179
|
+
|
|
180
|
+
# Turn the message user into a recipient - we can't use the channel recipient
|
|
181
|
+
# directly because the bot may also send messages to the channel
|
|
182
|
+
@author = Recipient.new(bot.user(data['author']['id'].to_i), @channel, bot)
|
|
183
|
+
else
|
|
184
|
+
@author_id = data['author']['id'].to_i
|
|
185
|
+
end
|
|
186
|
+
end
|
|
118
187
|
|
|
119
188
|
@timestamp = Time.parse(data['timestamp']) if data['timestamp']
|
|
120
189
|
@edited_timestamp = data['edited_timestamp'].nil? ? nil : Time.parse(data['edited_timestamp'])
|
|
@@ -149,43 +218,81 @@ module Discordrb
|
|
|
149
218
|
|
|
150
219
|
@embeds = []
|
|
151
220
|
@embeds = data['embeds'].map { |e| Embed.new(e, self) } if data['embeds']
|
|
221
|
+
|
|
222
|
+
@components = []
|
|
223
|
+
@components = data['components'].map { |component_data| Components.from_data(component_data, @bot) } if data['components']
|
|
224
|
+
|
|
225
|
+
@flags = data['flags'] || 0
|
|
226
|
+
|
|
227
|
+
@thread = data['thread'] ? @bot.ensure_channel(data['thread'], @server) : nil
|
|
228
|
+
|
|
229
|
+
@pinned_at = data['pinned_at'] ? Time.parse(data['pinned_at']) : nil
|
|
230
|
+
|
|
231
|
+
@call = data['call'] ? Call.new(data['call'], @bot) : nil
|
|
232
|
+
|
|
233
|
+
@snapshots = data['message_snapshots']&.map { |snapshot| Snapshot.new(snapshot['message'], @bot) } || []
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# @return [Member, User] the user that sent this message. (Will be a {Member} most of the time, it should only be a
|
|
237
|
+
# {User} for old messages when the author has left the server since then)
|
|
238
|
+
def author
|
|
239
|
+
return @author if @author
|
|
240
|
+
|
|
241
|
+
if @channel.server
|
|
242
|
+
@author = @channel.server.member(@author_id)
|
|
243
|
+
Discordrb::LOGGER.debug("Member with ID #{@author_id} not cached (possibly left the server).") if @author.nil?
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
@author ||= @bot.user(@author_id)
|
|
152
247
|
end
|
|
153
248
|
|
|
249
|
+
alias_method :user, :author
|
|
250
|
+
alias_method :writer, :author
|
|
251
|
+
|
|
154
252
|
# Replies to this message with the specified content.
|
|
155
253
|
# @deprecated Please use {#respond}.
|
|
254
|
+
# @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
|
|
255
|
+
# @return (see #respond)
|
|
156
256
|
# @see Channel#send_message
|
|
157
257
|
def reply(content)
|
|
158
258
|
@channel.send_message(content)
|
|
159
259
|
end
|
|
160
260
|
|
|
161
|
-
#
|
|
261
|
+
# Responds to this message as an inline reply.
|
|
162
262
|
# @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
|
|
163
263
|
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
|
164
264
|
# @param embed [Hash, Discordrb::Webhooks::Embed, nil] The rich embed to append to this message.
|
|
165
265
|
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
|
166
266
|
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
|
167
267
|
# @param mention_user [true, false] Whether the user that is being replied to should be pinged by the reply.
|
|
168
|
-
# @
|
|
169
|
-
|
|
268
|
+
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
|
269
|
+
# @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2) and SUPPRESS_NOTIFICATIONS (1 << 12) can be set.
|
|
270
|
+
# @return (see #respond)
|
|
271
|
+
def reply!(content, tts: false, embed: nil, attachments: nil, allowed_mentions: {}, mention_user: false, components: nil, flags: 0)
|
|
170
272
|
allowed_mentions = { parse: [] } if allowed_mentions == false
|
|
171
273
|
allowed_mentions = allowed_mentions.to_hash.transform_keys(&:to_sym)
|
|
172
274
|
allowed_mentions[:replied_user] = mention_user
|
|
173
275
|
|
|
174
|
-
respond(content, tts, embed, attachments, allowed_mentions, self)
|
|
276
|
+
respond(content, tts, embed, attachments, allowed_mentions, self, components, flags)
|
|
175
277
|
end
|
|
176
278
|
|
|
177
279
|
# (see Channel#send_message)
|
|
178
|
-
def respond(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil)
|
|
179
|
-
@channel.send_message(content, tts, embed, attachments, allowed_mentions, message_reference)
|
|
280
|
+
def respond(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0)
|
|
281
|
+
@channel.send_message(content, tts, embed, attachments, allowed_mentions, message_reference, components, flags)
|
|
180
282
|
end
|
|
181
283
|
|
|
182
284
|
# Edits this message to have the specified content instead.
|
|
183
285
|
# You can only edit your own messages.
|
|
184
286
|
# @param new_content [String] the new content the message should have.
|
|
185
|
-
# @param
|
|
287
|
+
# @param new_embeds [Hash, Discordrb::Webhooks::Embed, Array<Hash>, Array<Discordrb::Webhooks::Embed>, nil] The new embeds the message should have. If `nil` the message will be changed to have no embeds.
|
|
288
|
+
# @param new_components [View, Array<Hash>] The new components the message should have. If `nil` the message will be changed to have no components.
|
|
289
|
+
# @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2) can be edited.
|
|
186
290
|
# @return [Message] the resulting message.
|
|
187
|
-
def edit(new_content,
|
|
188
|
-
|
|
291
|
+
def edit(new_content, new_embeds = nil, new_components = nil, flags = 0)
|
|
292
|
+
new_embeds = (new_embeds.instance_of?(Array) ? new_embeds.map(&:to_hash) : [new_embeds&.to_hash]).compact
|
|
293
|
+
new_components = new_components.to_a
|
|
294
|
+
|
|
295
|
+
response = API::Channel.edit_message(@bot.token, @channel.id, @id, new_content, [], new_embeds, new_components, flags)
|
|
189
296
|
Message.new(JSON.parse(response), @bot)
|
|
190
297
|
end
|
|
191
298
|
|
|
@@ -209,6 +316,12 @@ module Discordrb
|
|
|
209
316
|
nil
|
|
210
317
|
end
|
|
211
318
|
|
|
319
|
+
# Crossposts a message in a news channel.
|
|
320
|
+
def crosspost
|
|
321
|
+
response = API::Channel.crosspost_message(@bot.token, @channel.id, @id)
|
|
322
|
+
Message.new(JSON.parse(response), @bot)
|
|
323
|
+
end
|
|
324
|
+
|
|
212
325
|
# Add an {Await} for a message with the same user and channel.
|
|
213
326
|
# @see Bot#add_await
|
|
214
327
|
# @deprecated Will be changed to blocking behavior in v4.0. Use {#await!} instead.
|
|
@@ -222,6 +335,19 @@ module Discordrb
|
|
|
222
335
|
@bot.add_await!(Discordrb::Events::MessageEvent, { from: @author.id, in: @channel.id }.merge(attributes), &block)
|
|
223
336
|
end
|
|
224
337
|
|
|
338
|
+
# Add an {Await} for a reaction to be added on this message.
|
|
339
|
+
# @see Bot#add_await
|
|
340
|
+
# @deprecated Will be changed to blocking behavior in v4.0. Use {#await_reaction!} instead.
|
|
341
|
+
def await_reaction(key, attributes = {}, &block)
|
|
342
|
+
@bot.add_await(key, Discordrb::Events::ReactionAddEvent, { message: @id }.merge(attributes), &block)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# Add a blocking {Await} for a reaction to be added on this message.
|
|
346
|
+
# @see Bot#add_await!
|
|
347
|
+
def await_reaction!(attributes = {}, &block)
|
|
348
|
+
@bot.add_await!(Discordrb::Events::ReactionAddEvent, { message: @id }.merge(attributes), &block)
|
|
349
|
+
end
|
|
350
|
+
|
|
225
351
|
# @return [true, false] whether this message was sent by the current {Bot}.
|
|
226
352
|
def from_bot?
|
|
227
353
|
@author&.current_bot?
|
|
@@ -258,6 +384,25 @@ module Discordrb
|
|
|
258
384
|
@reactions.select(&:me)
|
|
259
385
|
end
|
|
260
386
|
|
|
387
|
+
# Removes embeds from the message
|
|
388
|
+
# @return [Message] the resulting message.
|
|
389
|
+
def suppress_embeds
|
|
390
|
+
flags = @flags | (1 << 2)
|
|
391
|
+
response = API::Channel.edit_message(@bot.token, @channel.id, @id, :undef, :undef, :undef, :undef, flags)
|
|
392
|
+
Message.new(JSON.parse(response), @bot)
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Check if this message mentions a specific user or role.
|
|
396
|
+
# @param target [Role, User, Member, Integer, String] The mention to match against.
|
|
397
|
+
# @return [true, false] whether or not this message mentions the target.
|
|
398
|
+
def mentions?(target)
|
|
399
|
+
mentions = (@mentions + role_mentions)
|
|
400
|
+
|
|
401
|
+
mentions << server if @mention_everyone
|
|
402
|
+
|
|
403
|
+
mentions.any?(target.resolve_id)
|
|
404
|
+
end
|
|
405
|
+
|
|
261
406
|
# Reacts to a message.
|
|
262
407
|
# @param reaction [String, #to_reaction] the unicode emoji or {Emoji}
|
|
263
408
|
def create_reaction(reaction)
|
|
@@ -276,14 +421,38 @@ module Discordrb
|
|
|
276
421
|
# @return [Array<User>] the users who used this reaction
|
|
277
422
|
def reacted_with(reaction, limit: 100)
|
|
278
423
|
reaction = reaction.to_reaction if reaction.respond_to?(:to_reaction)
|
|
424
|
+
reaction = reaction.to_s if reaction.respond_to?(:to_s)
|
|
425
|
+
|
|
426
|
+
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)
|
|
428
|
+
JSON.parse(resp).map { |d| User.new(d, @bot) }
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
# Can be done without pagination
|
|
432
|
+
return get_reactions.call(limit) if limit && limit <= 100
|
|
433
|
+
|
|
279
434
|
paginator = Paginator.new(limit, :down) do |last_page|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
435
|
+
if last_page && last_page.count < 100
|
|
436
|
+
[]
|
|
437
|
+
else
|
|
438
|
+
get_reactions.call(100, last_page&.last&.id)
|
|
439
|
+
end
|
|
283
440
|
end
|
|
441
|
+
|
|
284
442
|
paginator.to_a
|
|
285
443
|
end
|
|
286
444
|
|
|
445
|
+
# Returns a hash of all reactions to a message as keys and the users that reacted to it as values.
|
|
446
|
+
# @param limit [Integer] the limit of how many users to retrieve per distinct reaction emoji. `nil` will return all users
|
|
447
|
+
# @example Get all the users that reacted to a message for a giveaway.
|
|
448
|
+
# giveaway_participants = message.all_reaction_users
|
|
449
|
+
# @return [Hash<String => Array<User>>] A hash mapping the string representation of a
|
|
450
|
+
# reaction to an array of users.
|
|
451
|
+
def all_reaction_users(limit: 100)
|
|
452
|
+
all_reactions = @reactions.map { |r| { r.to_s => reacted_with(r, limit: limit) } }
|
|
453
|
+
all_reactions.reduce({}, :merge)
|
|
454
|
+
end
|
|
455
|
+
|
|
287
456
|
# Deletes a reaction made by a user on this message.
|
|
288
457
|
# @param user [User, String, Integer] the user or user ID who used this reaction
|
|
289
458
|
# @param reaction [String, #to_reaction] the reaction to remove
|
|
@@ -328,7 +497,65 @@ module Discordrb
|
|
|
328
497
|
return nil unless @message_reference
|
|
329
498
|
|
|
330
499
|
referenced_channel = @bot.channel(@message_reference['channel_id'])
|
|
331
|
-
@referenced_message = referenced_channel
|
|
500
|
+
@referenced_message = referenced_channel&.message(@message_reference['message_id'])
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
# @return [Array<Components::Button>]
|
|
504
|
+
def buttons
|
|
505
|
+
results = @components.collect do |component|
|
|
506
|
+
case component
|
|
507
|
+
when Components::Button
|
|
508
|
+
component
|
|
509
|
+
when Components::ActionRow
|
|
510
|
+
component.buttons
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
results.flatten.compact
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
# to_message -> self or message
|
|
518
|
+
# @return [Discordrb::Message]
|
|
519
|
+
def to_message
|
|
520
|
+
self
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
alias_method :message, :to_message
|
|
524
|
+
|
|
525
|
+
FLAGS.each do |name, value|
|
|
526
|
+
define_method("#{name}?") do
|
|
527
|
+
@flags.anybits?(value)
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
TYPES.each do |name, value|
|
|
532
|
+
define_method("#{name}?") do
|
|
533
|
+
@type == value
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
# Convert this message to a hash that can be used to reference this message in a forward or a reply.
|
|
538
|
+
# @param type [Integer, Symbol] The reference type to set. Can either be one of `:reply` or `:forward`.
|
|
539
|
+
# @param must_exist [true, false] Whether to raise an error if this message was deleted when sending it.
|
|
540
|
+
# @return [Hash] the message as a hash representation that can be used in a forwarded message or a reply.
|
|
541
|
+
def to_reference(type: :reply, must_exist: true)
|
|
542
|
+
type = (type == :reply ? 0 : 1) if type.is_a?(Symbol)
|
|
543
|
+
|
|
544
|
+
{ type: type, message_id: @id, channel_id: @channel.id, fail_if_not_exists: must_exist }
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
# Forward this message to another channel.
|
|
548
|
+
# @param channel [Integer, String, Channel] The target channel to forward this message to.
|
|
549
|
+
# @param must_exist [true, false] Whether to raise an error if this message was deleted when sending it.
|
|
550
|
+
# @param timeout [Float, nil] The amount of time in seconds after which the message sent will be deleted.
|
|
551
|
+
# @param flags [Integer, Symbol, Array<Integer, Symbol>] The message flags to set on the forwarded message.
|
|
552
|
+
# @param nonce [String, Integer, nil] The 25 character optional nonce that should be used when forwarding this message.
|
|
553
|
+
# @param enforce_nonce [true, false] Whether the provided nonce should be enforced and used for message de-duplication.
|
|
554
|
+
# @return [Message, nil] the message that was created from forwarding this one, or `nil` if this is a temporary message.
|
|
555
|
+
def forward(channel, must_exist: true, timeout: nil, flags: 0, nonce: nil, enforce_nonce: false)
|
|
556
|
+
reference = to_reference(type: :forward, must_exist: must_exist)
|
|
557
|
+
|
|
558
|
+
@bot.channel(channel).send_message!(reference: reference, timeout: timeout, flags: flags, nonce: nonce, enforce_nonce: enforce_nonce)
|
|
332
559
|
end
|
|
333
560
|
end
|
|
334
561
|
end
|
|
@@ -4,6 +4,12 @@ module Discordrb
|
|
|
4
4
|
# A permissions overwrite, when applied to channels describes additional
|
|
5
5
|
# permissions a member needs to perform certain actions in context.
|
|
6
6
|
class Overwrite
|
|
7
|
+
# Types of overwrites mapped to their API value.
|
|
8
|
+
TYPES = {
|
|
9
|
+
role: 0,
|
|
10
|
+
member: 1
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
7
13
|
# @return [Integer] ID of the thing associated with this overwrite type
|
|
8
14
|
attr_accessor :id
|
|
9
15
|
|
|
@@ -32,14 +38,14 @@ module Discordrb
|
|
|
32
38
|
# @example Create an overwrite by ID and permissions bits
|
|
33
39
|
# Overwrite.new(120571255635181568, type: 'member', allow: 1024, deny: 0)
|
|
34
40
|
# @param object [Integer, #id] the ID or object this overwrite is for
|
|
35
|
-
# @param type [String] the type of object this overwrite is for (only required if object is an Integer)
|
|
36
|
-
# @param allow [Integer, Permissions] allowed permissions for this overwrite, by bits or a Permissions object
|
|
37
|
-
# @param deny [Integer, Permissions] denied permissions for this overwrite, by bits or a Permissions object
|
|
41
|
+
# @param type [String, Symbol, Integer] the type of object this overwrite is for (only required if object is an Integer)
|
|
42
|
+
# @param allow [String, Integer, Permissions] allowed permissions for this overwrite, by bits or a Permissions object
|
|
43
|
+
# @param deny [String, Integer, Permissions] denied permissions for this overwrite, by bits or a Permissions object
|
|
38
44
|
# @raise [ArgumentError] if type is not :member or :role
|
|
39
45
|
def initialize(object = nil, type: nil, allow: 0, deny: 0)
|
|
40
46
|
if type
|
|
41
|
-
type = type.to_sym
|
|
42
|
-
raise ArgumentError, 'Overwrite type must be :member or :role' unless
|
|
47
|
+
type = TYPES.value?(type) ? TYPES.key(type) : type.to_sym
|
|
48
|
+
raise ArgumentError, 'Overwrite type must be :member or :role' unless type
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
@id = object.respond_to?(:id) ? object.id : object
|
|
@@ -59,7 +65,9 @@ module Discordrb
|
|
|
59
65
|
|
|
60
66
|
# Comparison by attributes [:id, :type, :allow, :deny]
|
|
61
67
|
def ==(other)
|
|
68
|
+
# rubocop:disable Lint/Void
|
|
62
69
|
false unless other.is_a? Discordrb::Overwrite
|
|
70
|
+
# rubocop:enable Lint/Void
|
|
63
71
|
id == other.id &&
|
|
64
72
|
type == other.type &&
|
|
65
73
|
allow == other.allow &&
|
|
@@ -71,7 +79,7 @@ module Discordrb
|
|
|
71
79
|
def self.from_hash(data)
|
|
72
80
|
new(
|
|
73
81
|
data['id'].to_i,
|
|
74
|
-
type: data['type'],
|
|
82
|
+
type: TYPES.key(data['type']),
|
|
75
83
|
allow: Permissions.new(data['allow']),
|
|
76
84
|
deny: Permissions.new(data['deny'])
|
|
77
85
|
)
|
|
@@ -93,7 +101,7 @@ module Discordrb
|
|
|
93
101
|
def to_hash
|
|
94
102
|
{
|
|
95
103
|
id: id,
|
|
96
|
-
type: type,
|
|
104
|
+
type: TYPES[type],
|
|
97
105
|
allow: allow.bits,
|
|
98
106
|
deny: deny.bits
|
|
99
107
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Discordrb
|
|
4
|
+
# A server tag that a user has chosen to display on their profile.
|
|
5
|
+
class PrimaryServer
|
|
6
|
+
# @return [Integer] the ID of the server this primary server is for.
|
|
7
|
+
attr_reader :server_id
|
|
8
|
+
|
|
9
|
+
# @return [Boolean] if the user is displaying the primary server's tag.
|
|
10
|
+
attr_reader :enabled
|
|
11
|
+
alias_method :enabled?, :enabled
|
|
12
|
+
|
|
13
|
+
# @return [String] the text of the primary server's tag. Limited to four characters.
|
|
14
|
+
attr_reader :name
|
|
15
|
+
alias_method :text, :name
|
|
16
|
+
|
|
17
|
+
# @return [String] the ID of the server tag's badge. can be used to generate a badge URL.
|
|
18
|
+
# @see #badge_url
|
|
19
|
+
attr_reader :badge_id
|
|
20
|
+
|
|
21
|
+
# @!visibility private
|
|
22
|
+
def initialize(data, bot)
|
|
23
|
+
@bot = bot
|
|
24
|
+
@server_id = data['identity_guild_id']&.to_i
|
|
25
|
+
@enabled = data['identity_enabled']
|
|
26
|
+
@name = data['tag']
|
|
27
|
+
@badge_id = data['badge']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Get the server associated with this primary server.
|
|
31
|
+
# @return [Server] the server associated with this primary server.
|
|
32
|
+
# @raise [Discordrb::Errors::NoPermission] this can happen when the bot is not in the associated server.
|
|
33
|
+
def server
|
|
34
|
+
@bot.server(@server_id)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Get the server preview associated with this primary server.
|
|
38
|
+
# @return [ServerPreview, nil] the server preview associated with this primary server, or `nil` if it can't be accessed.
|
|
39
|
+
def server_preview
|
|
40
|
+
@bot.server_preview(@server_id)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Utility method to get a server tag's badge URL.
|
|
44
|
+
# @param format [String] the URL will default to `webp`. You can otherwise specify one of `jpg` or `png` to override this.
|
|
45
|
+
# @return [String] the URL to the server tag's badge image.
|
|
46
|
+
def badge_url(format = 'webp')
|
|
47
|
+
API.server_tag_badge_url(@server_id, @badge_id, format)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Comparison based off of server ID.
|
|
51
|
+
# @return [true, false] if the other object is equal to this primary server.
|
|
52
|
+
def ==(other)
|
|
53
|
+
return false unless other.is_a?(PrimaryServer)
|
|
54
|
+
|
|
55
|
+
Discordrb.id_compare(other.server_id, @server_id)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
alias_method :eql?, :==
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -22,13 +22,8 @@ module Discordrb
|
|
|
22
22
|
# @param avatar [String, #read] A JPG file to be used as the avatar, either
|
|
23
23
|
# something readable (e.g. File Object) or as a data URL.
|
|
24
24
|
def avatar=(avatar)
|
|
25
|
-
if avatar.respond_to?
|
|
26
|
-
|
|
27
|
-
avatar.binmode if avatar.respond_to?(:binmode)
|
|
28
|
-
|
|
29
|
-
avatar_string = 'data:image/jpg;base64,'
|
|
30
|
-
avatar_string += Base64.strict_encode64(avatar.read)
|
|
31
|
-
update_profile_data(avatar: avatar_string)
|
|
25
|
+
if avatar.respond_to?(:read)
|
|
26
|
+
update_profile_data(avatar: Discordrb.encode64(avatar))
|
|
32
27
|
else
|
|
33
28
|
update_profile_data(avatar: avatar)
|
|
34
29
|
end
|
|
@@ -16,10 +16,11 @@ module Discordrb
|
|
|
16
16
|
# @return [String] the name or unicode representation of the emoji
|
|
17
17
|
attr_reader :name
|
|
18
18
|
|
|
19
|
+
# @!visibility private
|
|
19
20
|
def initialize(data)
|
|
20
21
|
@count = data['count']
|
|
21
22
|
@me = data['me']
|
|
22
|
-
@id = data['emoji']['id']
|
|
23
|
+
@id = data['emoji']['id']&.to_i
|
|
23
24
|
@name = data['emoji']['name']
|
|
24
25
|
end
|
|
25
26
|
|