discordrb 3.3.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +152 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
- data/.github/pull_request_template.md +37 -0
- data/.github/workflows/codeql.yml +65 -0
- data/.markdownlint.json +4 -0
- data/.rubocop.yml +39 -36
- data/CHANGELOG.md +874 -552
- data/Gemfile +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +80 -86
- data/Rakefile +2 -0
- data/bin/console +1 -0
- data/discordrb-webhooks.gemspec +9 -6
- data/discordrb.gemspec +21 -18
- data/lib/discordrb/allowed_mentions.rb +36 -0
- data/lib/discordrb/api/application.rb +202 -0
- data/lib/discordrb/api/channel.rb +236 -47
- data/lib/discordrb/api/interaction.rb +54 -0
- data/lib/discordrb/api/invite.rb +5 -5
- data/lib/discordrb/api/server.rb +94 -66
- data/lib/discordrb/api/user.rb +17 -11
- data/lib/discordrb/api/webhook.rb +63 -6
- data/lib/discordrb/api.rb +55 -16
- data/lib/discordrb/await.rb +0 -1
- data/lib/discordrb/bot.rb +480 -93
- data/lib/discordrb/cache.rb +31 -24
- data/lib/discordrb/colour_rgb.rb +43 -0
- data/lib/discordrb/commands/command_bot.rb +35 -12
- data/lib/discordrb/commands/container.rb +21 -24
- data/lib/discordrb/commands/parser.rb +20 -20
- data/lib/discordrb/commands/rate_limiter.rb +4 -3
- data/lib/discordrb/container.rb +209 -20
- data/lib/discordrb/data/activity.rb +271 -0
- data/lib/discordrb/data/application.rb +50 -0
- data/lib/discordrb/data/attachment.rb +71 -0
- data/lib/discordrb/data/audit_logs.rb +345 -0
- data/lib/discordrb/data/channel.rb +993 -0
- data/lib/discordrb/data/component.rb +229 -0
- data/lib/discordrb/data/embed.rb +251 -0
- data/lib/discordrb/data/emoji.rb +82 -0
- data/lib/discordrb/data/integration.rb +122 -0
- data/lib/discordrb/data/interaction.rb +800 -0
- data/lib/discordrb/data/invite.rb +137 -0
- data/lib/discordrb/data/member.rb +372 -0
- data/lib/discordrb/data/message.rb +414 -0
- data/lib/discordrb/data/overwrite.rb +108 -0
- data/lib/discordrb/data/profile.rb +91 -0
- data/lib/discordrb/data/reaction.rb +33 -0
- data/lib/discordrb/data/recipient.rb +34 -0
- data/lib/discordrb/data/role.rb +248 -0
- data/lib/discordrb/data/server.rb +1004 -0
- data/lib/discordrb/data/user.rb +264 -0
- data/lib/discordrb/data/voice_region.rb +45 -0
- data/lib/discordrb/data/voice_state.rb +41 -0
- data/lib/discordrb/data/webhook.rb +238 -0
- data/lib/discordrb/data.rb +28 -4180
- data/lib/discordrb/errors.rb +46 -4
- data/lib/discordrb/events/bans.rb +7 -5
- data/lib/discordrb/events/channels.rb +3 -1
- data/lib/discordrb/events/guilds.rb +16 -9
- data/lib/discordrb/events/interactions.rb +482 -0
- data/lib/discordrb/events/invites.rb +125 -0
- data/lib/discordrb/events/members.rb +6 -2
- data/lib/discordrb/events/message.rb +72 -27
- data/lib/discordrb/events/presence.rb +35 -18
- data/lib/discordrb/events/raw.rb +1 -3
- data/lib/discordrb/events/reactions.rb +49 -4
- data/lib/discordrb/events/threads.rb +96 -0
- data/lib/discordrb/events/typing.rb +6 -4
- data/lib/discordrb/events/voice_server_update.rb +47 -0
- data/lib/discordrb/events/voice_state_update.rb +15 -10
- data/lib/discordrb/events/webhooks.rb +9 -6
- data/lib/discordrb/gateway.rb +99 -71
- data/lib/discordrb/id_object.rb +39 -0
- data/lib/discordrb/light/integrations.rb +1 -1
- data/lib/discordrb/light/light_bot.rb +1 -1
- data/lib/discordrb/logger.rb +4 -4
- data/lib/discordrb/paginator.rb +57 -0
- data/lib/discordrb/permissions.rb +159 -39
- data/lib/discordrb/version.rb +1 -1
- data/lib/discordrb/voice/encoder.rb +16 -7
- data/lib/discordrb/voice/network.rb +99 -47
- data/lib/discordrb/voice/sodium.rb +98 -0
- data/lib/discordrb/voice/voice_bot.rb +33 -25
- data/lib/discordrb/webhooks.rb +2 -0
- data/lib/discordrb.rb +107 -1
- metadata +126 -54
- data/.codeclimate.yml +0 -16
- data/.travis.yml +0 -33
- data/bin/travis_build_docs.sh +0 -17
- /data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +0 -0
@@ -0,0 +1,993 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'discordrb/webhooks/view'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
module Discordrb
|
7
|
+
# A Discord channel, including data like the topic
|
8
|
+
class Channel
|
9
|
+
include IDObject
|
10
|
+
|
11
|
+
# Map of channel types
|
12
|
+
TYPES = {
|
13
|
+
text: 0,
|
14
|
+
dm: 1,
|
15
|
+
voice: 2,
|
16
|
+
group: 3,
|
17
|
+
category: 4,
|
18
|
+
news: 5,
|
19
|
+
store: 6,
|
20
|
+
news_thread: 10,
|
21
|
+
public_thread: 11,
|
22
|
+
private_thread: 12,
|
23
|
+
stage_voice: 13,
|
24
|
+
directory: 14,
|
25
|
+
forum: 15
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
# @return [String] this channel's name.
|
29
|
+
attr_reader :name
|
30
|
+
|
31
|
+
# @return [Integer, nil] the ID of the parent channel, if this channel is inside a category. If this channel is a
|
32
|
+
# thread, this is the text channel it is a child to.
|
33
|
+
attr_reader :parent_id
|
34
|
+
|
35
|
+
# @return [Integer] the type of this channel
|
36
|
+
# @see TYPES
|
37
|
+
attr_reader :type
|
38
|
+
|
39
|
+
# @return [Integer, nil] the ID of the owner of the group channel or nil if this is not a group channel. If this
|
40
|
+
# channel is a thread, this is the member that started the thread.
|
41
|
+
attr_reader :owner_id
|
42
|
+
|
43
|
+
# @return [Array<Recipient>, nil] the array of recipients of the private messages, or nil if this is not a Private channel
|
44
|
+
attr_reader :recipients
|
45
|
+
|
46
|
+
# @return [String] the channel's topic
|
47
|
+
attr_reader :topic
|
48
|
+
|
49
|
+
# @return [Integer] the bitrate (in bps) of the channel
|
50
|
+
attr_reader :bitrate
|
51
|
+
|
52
|
+
# @return [Integer] the amount of users that can be in the channel. `0` means it is unlimited.
|
53
|
+
attr_reader :user_limit
|
54
|
+
alias_method :limit, :user_limit
|
55
|
+
|
56
|
+
# @return [Integer] the channel's position on the channel list
|
57
|
+
attr_reader :position
|
58
|
+
|
59
|
+
# @return [true, false] if this channel is marked as nsfw
|
60
|
+
attr_reader :nsfw
|
61
|
+
alias_method :nsfw?, :nsfw
|
62
|
+
|
63
|
+
# @return [Integer] the amount of time (in seconds) users need to wait to send in between messages.
|
64
|
+
attr_reader :rate_limit_per_user
|
65
|
+
alias_method :slowmode_rate, :rate_limit_per_user
|
66
|
+
|
67
|
+
# @return [Integer, nil] An approximate count of messages sent in a thread. Stops counting at 50.
|
68
|
+
attr_reader :message_count
|
69
|
+
|
70
|
+
# @return [Integer, nil] An approximate count of members in a thread. Stops counting at 50.
|
71
|
+
attr_reader :member_count
|
72
|
+
|
73
|
+
# @return [true, false, nil] Whether or not this thread is archived.
|
74
|
+
attr_reader :archived
|
75
|
+
|
76
|
+
# @return [Integer, nil] How long after the last message before a thread is automatically archived.
|
77
|
+
attr_reader :auto_archive_duration
|
78
|
+
|
79
|
+
# @return [Time, nil] The timestamp of when this threads status last changed.
|
80
|
+
attr_reader :archive_timestamp
|
81
|
+
|
82
|
+
# @return [true, false, nil] Whether this thread is locked or not.
|
83
|
+
attr_reader :locked
|
84
|
+
alias_method :locked?, :locked
|
85
|
+
|
86
|
+
# @return [Time, nil] When the current user joined this thread.
|
87
|
+
attr_reader :join_timestamp
|
88
|
+
|
89
|
+
# @return [Integer, nil] Member flags for this thread, used for notifications.
|
90
|
+
attr_reader :member_flags
|
91
|
+
|
92
|
+
# @return [true, false] For private threads, determines whether non-moderators can add other non-moderators to
|
93
|
+
# a thread.
|
94
|
+
attr_reader :invitable
|
95
|
+
|
96
|
+
# @return [true, false] whether or not this channel is a PM or group channel.
|
97
|
+
def private?
|
98
|
+
pm? || group?
|
99
|
+
end
|
100
|
+
|
101
|
+
# @return [String] a string that will mention the channel as a clickable link on Discord.
|
102
|
+
def mention
|
103
|
+
"<##{@id}>"
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Recipient, nil] the recipient of the private messages, or nil if this is not a PM channel
|
107
|
+
def recipient
|
108
|
+
@recipients.first if pm?
|
109
|
+
end
|
110
|
+
|
111
|
+
# @!visibility private
|
112
|
+
def initialize(data, bot, server = nil)
|
113
|
+
@bot = bot
|
114
|
+
# data is sometimes a Hash and other times an array of Hashes, you only want the last one if it's an array
|
115
|
+
data = data[-1] if data.is_a?(Array)
|
116
|
+
|
117
|
+
@id = data['id'].to_i
|
118
|
+
@type = data['type'] || 0
|
119
|
+
@topic = data['topic']
|
120
|
+
@bitrate = data['bitrate']
|
121
|
+
@user_limit = data['user_limit']
|
122
|
+
@position = data['position']
|
123
|
+
@parent_id = data['parent_id'].to_i if data['parent_id']
|
124
|
+
|
125
|
+
if private?
|
126
|
+
@recipients = []
|
127
|
+
data['recipients']&.each do |recipient|
|
128
|
+
recipient_user = bot.ensure_user(recipient)
|
129
|
+
@recipients << Recipient.new(recipient_user, self, bot)
|
130
|
+
end
|
131
|
+
if pm?
|
132
|
+
@name = @recipients.first.username
|
133
|
+
else
|
134
|
+
@name = data['name']
|
135
|
+
@owner_id = data['owner_id']
|
136
|
+
end
|
137
|
+
else
|
138
|
+
@name = data['name']
|
139
|
+
@server_id = server&.id || data['guild_id'].to_i
|
140
|
+
@server = server
|
141
|
+
end
|
142
|
+
|
143
|
+
@nsfw = data['nsfw'] || false
|
144
|
+
@rate_limit_per_user = data['rate_limit_per_user'] || 0
|
145
|
+
@message_count = data['message_count']
|
146
|
+
@member_count = data['member_count']
|
147
|
+
|
148
|
+
if (metadata = data['thread_metadata'])
|
149
|
+
@archived = metadata['archived']
|
150
|
+
@auto_archive_duration = metadata['auto_archive_duration']
|
151
|
+
@archive_timestamp = Time.iso8601(metadata['archive_timestamp'])
|
152
|
+
@locked = metadata['locked']
|
153
|
+
@invitable = metadata['invitable']
|
154
|
+
end
|
155
|
+
|
156
|
+
if (member = data['member'])
|
157
|
+
@member_join = Time.iso8601(member['join_timestamp'])
|
158
|
+
@member_flags = member['flags']
|
159
|
+
end
|
160
|
+
|
161
|
+
process_permission_overwrites(data['permission_overwrites'])
|
162
|
+
end
|
163
|
+
|
164
|
+
# @return [Server, nil] the server this channel is on. If this channel is a PM channel, it will be nil.
|
165
|
+
# @raise [Discordrb::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
|
166
|
+
# authorized with the `bot` scope.
|
167
|
+
def server
|
168
|
+
return @server if @server
|
169
|
+
return nil if private?
|
170
|
+
|
171
|
+
@server = @bot.server(@server_id)
|
172
|
+
raise Discordrb::Errors::NoPermission, 'The bot does not have access to this server' unless @server
|
173
|
+
|
174
|
+
@server
|
175
|
+
end
|
176
|
+
|
177
|
+
# @return [true, false] whether or not this channel is a text channel
|
178
|
+
def text?
|
179
|
+
@type.zero?
|
180
|
+
end
|
181
|
+
|
182
|
+
# @return [true, false] whether or not this channel is a PM channel.
|
183
|
+
def pm?
|
184
|
+
@type == 1
|
185
|
+
end
|
186
|
+
|
187
|
+
# @return [true, false] whether or not this channel is a voice channel.
|
188
|
+
def voice?
|
189
|
+
@type == 2
|
190
|
+
end
|
191
|
+
|
192
|
+
# @return [true, false] whether or not this channel is a group channel.
|
193
|
+
def group?
|
194
|
+
@type == 3
|
195
|
+
end
|
196
|
+
|
197
|
+
# @return [true, false] whether or not this channel is a category channel.
|
198
|
+
def category?
|
199
|
+
@type == 4
|
200
|
+
end
|
201
|
+
|
202
|
+
# @return [true, false] whether or not this channel is a news channel.
|
203
|
+
def news?
|
204
|
+
@type == 5
|
205
|
+
end
|
206
|
+
|
207
|
+
# @return [true, false] whether or not this channel is a store channel.
|
208
|
+
def store?
|
209
|
+
@type == 6
|
210
|
+
end
|
211
|
+
|
212
|
+
# @return [true, false] whether or not this channel is a news thread.
|
213
|
+
def news_thread?
|
214
|
+
@type == 10
|
215
|
+
end
|
216
|
+
|
217
|
+
# @return [true, false] whether or not this channel is a public thread.
|
218
|
+
def public_thread?
|
219
|
+
@type == 11
|
220
|
+
end
|
221
|
+
|
222
|
+
# @return [true, false] whether or not this channel is a private thread.
|
223
|
+
def private_thread?
|
224
|
+
@type == 12
|
225
|
+
end
|
226
|
+
|
227
|
+
# @return [true, false] whether or not this channel is a thread.
|
228
|
+
def thread?
|
229
|
+
news_thread? || public_thread? || private_thread?
|
230
|
+
end
|
231
|
+
|
232
|
+
# @return [Channel, nil] the category channel, if this channel is in a category
|
233
|
+
def category
|
234
|
+
@bot.channel(@parent_id) if @parent_id
|
235
|
+
end
|
236
|
+
|
237
|
+
alias_method :parent, :category
|
238
|
+
|
239
|
+
# Sets this channels parent category
|
240
|
+
# @param channel [Channel, String, Integer] the target category channel, or its ID
|
241
|
+
# @raise [ArgumentError] if the target channel isn't a category
|
242
|
+
def category=(channel)
|
243
|
+
channel = @bot.channel(channel)
|
244
|
+
raise ArgumentError, 'Cannot set parent category to a channel that isn\'t a category' unless channel.category?
|
245
|
+
|
246
|
+
update_channel_data(parent_id: channel.id)
|
247
|
+
end
|
248
|
+
|
249
|
+
alias_method :parent=, :category=
|
250
|
+
|
251
|
+
# Sorts this channel's position to follow another channel.
|
252
|
+
# @param other [Channel, String, Integer, nil] The channel, or its ID, below which this channel should be sorted. If the given
|
253
|
+
# channel is a category, this channel will be sorted at the top of that category. If it is `nil`, the channel will
|
254
|
+
# be sorted at the top of the channel list.
|
255
|
+
# @param lock_permissions [true, false] Whether the channel's permissions should be synced to the category's
|
256
|
+
def sort_after(other = nil, lock_permissions = false)
|
257
|
+
raise TypeError, 'other must be one of Channel, NilClass, String, or Integer' unless other.is_a?(Channel) || other.nil? || other.respond_to?(:resolve_id)
|
258
|
+
|
259
|
+
other = @bot.channel(other.resolve_id) if other
|
260
|
+
|
261
|
+
# Container for the API request payload
|
262
|
+
move_argument = []
|
263
|
+
|
264
|
+
if other
|
265
|
+
raise ArgumentError, 'Can only sort a channel after a channel of the same type!' unless other.category? || (@type == other.type)
|
266
|
+
|
267
|
+
raise ArgumentError, 'Can only sort a channel after a channel in the same server!' unless other.server == server
|
268
|
+
|
269
|
+
# Store `others` parent (or if `other` is a category itself)
|
270
|
+
parent = if category? && other.category?
|
271
|
+
# If we're sorting two categories, there is no new parent
|
272
|
+
nil
|
273
|
+
elsif other.category?
|
274
|
+
# `other` is the category this channel will be moved into
|
275
|
+
other
|
276
|
+
else
|
277
|
+
# `other`'s parent is the category this channel will be
|
278
|
+
# moved into (if it exists)
|
279
|
+
other.parent
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# Collect and sort the IDs within the context (category or not) that we
|
284
|
+
# need to form our payload with
|
285
|
+
ids = if parent
|
286
|
+
parent.children
|
287
|
+
else
|
288
|
+
server.channels.reject(&:parent_id).select { |c| c.type == @type }
|
289
|
+
end.sort_by(&:position).map(&:id)
|
290
|
+
|
291
|
+
# Move our channel ID after the target ID by deleting it,
|
292
|
+
# getting the index of `other`, and inserting it after.
|
293
|
+
ids.delete(@id) if ids.include?(@id)
|
294
|
+
index = other ? (ids.index { |c| c == other.id } || -1) + 1 : 0
|
295
|
+
ids.insert(index, @id)
|
296
|
+
|
297
|
+
# Generate `move_argument`, making the positions in order from how
|
298
|
+
# we have sorted them in the above logic
|
299
|
+
ids.each_with_index do |id, pos|
|
300
|
+
# These keys are present in each element
|
301
|
+
hash = { id: id, position: pos }
|
302
|
+
|
303
|
+
# Conditionally add `lock_permissions` and `parent_id` if we're
|
304
|
+
# iterating past ourselves
|
305
|
+
if id == @id
|
306
|
+
hash[:lock_permissions] = true if lock_permissions
|
307
|
+
hash[:parent_id] = parent.nil? ? nil : parent.id
|
308
|
+
end
|
309
|
+
|
310
|
+
# Add it to the stack
|
311
|
+
move_argument << hash
|
312
|
+
end
|
313
|
+
|
314
|
+
API::Server.update_channel_positions(@bot.token, @server_id, move_argument)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Sets whether this channel is NSFW
|
318
|
+
# @param nsfw [true, false]
|
319
|
+
# @raise [ArgumentError] if value isn't one of true, false
|
320
|
+
def nsfw=(nsfw)
|
321
|
+
raise ArgumentError, 'nsfw value must be true or false' unless nsfw.is_a?(TrueClass) || nsfw.is_a?(FalseClass)
|
322
|
+
|
323
|
+
update_channel_data(nsfw: nsfw)
|
324
|
+
end
|
325
|
+
|
326
|
+
# This channel's permission overwrites
|
327
|
+
# @overload permission_overwrites
|
328
|
+
# The overwrites represented as a hash of role/user ID
|
329
|
+
# to an Overwrite object
|
330
|
+
# @return [Hash<Integer => Overwrite>] the channel's permission overwrites
|
331
|
+
# @overload permission_overwrites(type)
|
332
|
+
# Return an array of a certain type of overwrite
|
333
|
+
# @param type [Symbol] the kind of overwrite to return
|
334
|
+
# @return [Array<Overwrite>]
|
335
|
+
def permission_overwrites(type = nil)
|
336
|
+
return @permission_overwrites unless type
|
337
|
+
|
338
|
+
@permission_overwrites.values.select { |e| e.type == type }
|
339
|
+
end
|
340
|
+
|
341
|
+
alias_method :overwrites, :permission_overwrites
|
342
|
+
|
343
|
+
# Bulk sets this channels permission overwrites
|
344
|
+
# @param overwrites [Array<Overwrite>]
|
345
|
+
def permission_overwrites=(overwrites)
|
346
|
+
update_channel_data(permission_overwrites: overwrites)
|
347
|
+
end
|
348
|
+
|
349
|
+
# Sets the amount of time (in seconds) users have to wait in between sending messages.
|
350
|
+
# @param rate [Integer]
|
351
|
+
# @raise [ArgumentError] if value isn't between 0 and 21600
|
352
|
+
def rate_limit_per_user=(rate)
|
353
|
+
raise ArgumentError, 'rate_limit_per_user must be between 0 and 21600' unless rate.between?(0, 21_600)
|
354
|
+
|
355
|
+
update_channel_data(rate_limit_per_user: rate)
|
356
|
+
end
|
357
|
+
|
358
|
+
alias_method :slowmode_rate=, :rate_limit_per_user=
|
359
|
+
|
360
|
+
# Syncs this channels overwrites with its parent category
|
361
|
+
# @raise [RuntimeError] if this channel is not in a category
|
362
|
+
def sync_overwrites
|
363
|
+
raise 'Cannot sync overwrites on a channel with no parent category' unless parent
|
364
|
+
|
365
|
+
self.permission_overwrites = parent.permission_overwrites
|
366
|
+
end
|
367
|
+
|
368
|
+
alias_method :sync, :sync_overwrites
|
369
|
+
|
370
|
+
# @return [true, false, nil] whether this channels permissions match the permission overwrites of the category that it's in, or nil if it is not in a category
|
371
|
+
def synchronized?
|
372
|
+
return unless parent
|
373
|
+
|
374
|
+
permission_overwrites == parent.permission_overwrites
|
375
|
+
end
|
376
|
+
|
377
|
+
alias_method :synced?, :synchronized?
|
378
|
+
|
379
|
+
# Returns the children of this channel, if it is a category. Otherwise returns an empty array.
|
380
|
+
# @return [Array<Channel>]
|
381
|
+
def children
|
382
|
+
return [] unless category?
|
383
|
+
|
384
|
+
server.channels.select { |c| c.parent_id == id }
|
385
|
+
end
|
386
|
+
|
387
|
+
alias_method :channels, :children
|
388
|
+
|
389
|
+
# Returns the text channels in this category, if it is a category channel. Otherwise returns an empty array.
|
390
|
+
# @return [Array<Channel>]
|
391
|
+
def text_channels
|
392
|
+
children.select(&:text?)
|
393
|
+
end
|
394
|
+
|
395
|
+
# Returns the voice channels in this category, if it is a category channel. Otherwise returns an empty array.
|
396
|
+
# @return [Array<Channel>]
|
397
|
+
def voice_channels
|
398
|
+
children.select(&:voice?)
|
399
|
+
end
|
400
|
+
|
401
|
+
# @return [Overwrite] any member-type permission overwrites on this channel
|
402
|
+
def member_overwrites
|
403
|
+
permission_overwrites :member
|
404
|
+
end
|
405
|
+
|
406
|
+
# @return [Overwrite] any role-type permission overwrites on this channel
|
407
|
+
def role_overwrites
|
408
|
+
permission_overwrites :role
|
409
|
+
end
|
410
|
+
|
411
|
+
# @return [true, false] whether or not this channel is the default channel
|
412
|
+
def default_channel?
|
413
|
+
server.default_channel == self
|
414
|
+
end
|
415
|
+
|
416
|
+
alias_method :default?, :default_channel?
|
417
|
+
|
418
|
+
# @return [true, false] whether or not this channel has slowmode enabled
|
419
|
+
def slowmode?
|
420
|
+
@rate_limit_per_user != 0
|
421
|
+
end
|
422
|
+
|
423
|
+
# Sends a message to this channel.
|
424
|
+
# @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
|
425
|
+
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
426
|
+
# @param embed [Hash, Discordrb::Webhooks::Embed, nil] The rich embed to append to this message.
|
427
|
+
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
428
|
+
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
429
|
+
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
430
|
+
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
431
|
+
# @return [Message] the message that was sent.
|
432
|
+
def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
|
433
|
+
@bot.send_message(@id, content, tts, embed, attachments, allowed_mentions, message_reference, components)
|
434
|
+
end
|
435
|
+
|
436
|
+
alias_method :send, :send_message
|
437
|
+
|
438
|
+
# Sends a temporary message to this channel.
|
439
|
+
# @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
|
440
|
+
# @param timeout [Float] The amount of time in seconds after which the message sent will be deleted.
|
441
|
+
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
442
|
+
# @param embed [Hash, Discordrb::Webhooks::Embed, nil] The rich embed to append to this message.
|
443
|
+
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
444
|
+
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
445
|
+
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
446
|
+
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
447
|
+
def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
|
448
|
+
@bot.send_temporary_message(@id, content, timeout, tts, embed, attachments, allowed_mentions, message_reference, components)
|
449
|
+
end
|
450
|
+
|
451
|
+
# Convenience method to send a message with an embed.
|
452
|
+
# @example Send a message with an embed
|
453
|
+
# channel.send_embed do |embed|
|
454
|
+
# embed.title = 'The Ruby logo'
|
455
|
+
# embed.image = Discordrb::Webhooks::EmbedImage.new(url: 'https://www.ruby-lang.org/images/header-ruby-logo.png')
|
456
|
+
# end
|
457
|
+
# @param message [String] The message that should be sent along with the embed. If this is the empty string, only the embed will be shown.
|
458
|
+
# @param embed [Discordrb::Webhooks::Embed, nil] The embed to start the building process with, or nil if one should be created anew.
|
459
|
+
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
460
|
+
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
461
|
+
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
462
|
+
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
463
|
+
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
464
|
+
# @yield [embed] Yields the embed to allow for easy building inside a block.
|
465
|
+
# @yieldparam embed [Discordrb::Webhooks::Embed] The embed from the parameters, or a new one.
|
466
|
+
# @return [Message] The resulting message.
|
467
|
+
def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, components = nil)
|
468
|
+
embed ||= Discordrb::Webhooks::Embed.new
|
469
|
+
view = Discordrb::Webhooks::View.new
|
470
|
+
|
471
|
+
yield(embed, view) if block_given?
|
472
|
+
|
473
|
+
send_message(message, tts, embed, attachments, allowed_mentions, message_reference, components || view.to_a)
|
474
|
+
end
|
475
|
+
|
476
|
+
# Sends multiple messages to a channel
|
477
|
+
# @param content [Array<String>] The messages to send.
|
478
|
+
def send_multiple(content)
|
479
|
+
content.each { |e| send_message(e) }
|
480
|
+
end
|
481
|
+
|
482
|
+
# Splits a message into chunks whose length is at most the Discord character limit, then sends them individually.
|
483
|
+
# Useful for sending long messages, but be wary of rate limits!
|
484
|
+
def split_send(content)
|
485
|
+
send_multiple(Discordrb.split_message(content))
|
486
|
+
nil
|
487
|
+
end
|
488
|
+
|
489
|
+
# Sends a file to this channel. If it is an image, it will be embedded.
|
490
|
+
# @param file [File] The file to send. There's no clear size limit for this, you'll have to attempt it for yourself (most non-image files are fine, large images may fail to embed)
|
491
|
+
# @param caption [string] The caption for the file.
|
492
|
+
# @param tts [true, false] Whether or not this file's caption should be sent using Discord text-to-speech.
|
493
|
+
# @param filename [String] Overrides the filename of the uploaded file
|
494
|
+
# @param spoiler [true, false] Whether or not this file should appear as a spoiler.
|
495
|
+
# @example Send a file from disk
|
496
|
+
# channel.send_file(File.open('rubytaco.png', 'r'))
|
497
|
+
def send_file(file, caption: nil, tts: false, filename: nil, spoiler: nil)
|
498
|
+
@bot.send_file(@id, file, caption: caption, tts: tts, filename: filename, spoiler: spoiler)
|
499
|
+
end
|
500
|
+
|
501
|
+
# Deletes a message on this channel. Mostly useful in case a message needs to be deleted when only the ID is known
|
502
|
+
# @param message [Message, String, Integer, String, Integer] The message, or its ID, that should be deleted.
|
503
|
+
def delete_message(message)
|
504
|
+
API::Channel.delete_message(@bot.token, @id, message.resolve_id)
|
505
|
+
end
|
506
|
+
|
507
|
+
# Permanently deletes this channel
|
508
|
+
# @param reason [String] The reason the for the channel deletion.
|
509
|
+
def delete(reason = nil)
|
510
|
+
API::Channel.delete(@bot.token, @id, reason)
|
511
|
+
end
|
512
|
+
|
513
|
+
# Sets this channel's name. The name must be alphanumeric with dashes, unless this is a voice channel (then there are no limitations)
|
514
|
+
# @param name [String] The new name.
|
515
|
+
def name=(name)
|
516
|
+
update_channel_data(name: name)
|
517
|
+
end
|
518
|
+
|
519
|
+
# Sets this channel's topic.
|
520
|
+
# @param topic [String] The new topic.
|
521
|
+
def topic=(topic)
|
522
|
+
raise 'Tried to set topic on voice channel' if voice?
|
523
|
+
|
524
|
+
update_channel_data(topic: topic)
|
525
|
+
end
|
526
|
+
|
527
|
+
# Sets this channel's bitrate.
|
528
|
+
# @param bitrate [Integer] The new bitrate (in bps). Number has to be between 8000-96000 (128000 for VIP servers)
|
529
|
+
def bitrate=(bitrate)
|
530
|
+
raise 'Tried to set bitrate on text channel' if text?
|
531
|
+
|
532
|
+
update_channel_data(bitrate: bitrate)
|
533
|
+
end
|
534
|
+
|
535
|
+
# Sets this channel's user limit.
|
536
|
+
# @param limit [Integer] The new user limit. `0` for unlimited, has to be a number between 0-99
|
537
|
+
def user_limit=(limit)
|
538
|
+
raise 'Tried to set user_limit on text channel' if text?
|
539
|
+
|
540
|
+
update_channel_data(user_limit: limit)
|
541
|
+
end
|
542
|
+
|
543
|
+
alias_method :limit=, :user_limit=
|
544
|
+
|
545
|
+
# Sets this channel's position in the list.
|
546
|
+
# @param position [Integer] The new position.
|
547
|
+
def position=(position)
|
548
|
+
update_channel_data(position: position)
|
549
|
+
end
|
550
|
+
|
551
|
+
# Defines a permission overwrite for this channel that sets the specified thing to the specified allow and deny
|
552
|
+
# permission sets, or change an existing one.
|
553
|
+
# @overload define_overwrite(overwrite)
|
554
|
+
# @param thing [Overwrite] an Overwrite object to apply to this channel
|
555
|
+
# @param reason [String] The reason the for defining the overwrite.
|
556
|
+
# @overload define_overwrite(thing, allow, deny)
|
557
|
+
# @param thing [User, Role] What to define an overwrite for.
|
558
|
+
# @param allow [#bits, Permissions, Integer] The permission sets that should receive an `allow` override (i.e. a
|
559
|
+
# green checkmark on Discord)
|
560
|
+
# @param deny [#bits, Permissions, Integer] The permission sets that should receive a `deny` override (i.e. a red
|
561
|
+
# cross on Discord)
|
562
|
+
# @param reason [String] The reason the for defining the overwrite.
|
563
|
+
# @example Define a permission overwrite for a user that can then mention everyone and use TTS, but not create any invites
|
564
|
+
# allow = Discordrb::Permissions.new
|
565
|
+
# allow.can_mention_everyone = true
|
566
|
+
# allow.can_send_tts_messages = true
|
567
|
+
#
|
568
|
+
# deny = Discordrb::Permissions.new
|
569
|
+
# deny.can_create_instant_invite = true
|
570
|
+
#
|
571
|
+
# channel.define_overwrite(user, allow, deny)
|
572
|
+
def define_overwrite(thing, allow = 0, deny = 0, reason: nil)
|
573
|
+
unless thing.is_a? Overwrite
|
574
|
+
allow_bits = allow.respond_to?(:bits) ? allow.bits : allow
|
575
|
+
deny_bits = deny.respond_to?(:bits) ? deny.bits : deny
|
576
|
+
|
577
|
+
thing = Overwrite.new thing, allow: allow_bits, deny: deny_bits
|
578
|
+
end
|
579
|
+
|
580
|
+
API::Channel.update_permission(@bot.token, @id, thing.id, thing.allow.bits, thing.deny.bits, thing.type, reason)
|
581
|
+
end
|
582
|
+
|
583
|
+
# Deletes a permission overwrite for this channel
|
584
|
+
# @param target [Member, User, Role, Profile, Recipient, String, Integer] What permission overwrite to delete
|
585
|
+
# @param reason [String] The reason the for the overwrite deletion.
|
586
|
+
def delete_overwrite(target, reason = nil)
|
587
|
+
raise 'Tried deleting a overwrite for an invalid target' unless target.is_a?(Member) || target.is_a?(User) || target.is_a?(Role) || target.is_a?(Profile) || target.is_a?(Recipient) || target.respond_to?(:resolve_id)
|
588
|
+
|
589
|
+
API::Channel.delete_permission(@bot.token, @id, target.resolve_id, reason)
|
590
|
+
end
|
591
|
+
|
592
|
+
# Updates the cached data from another channel.
|
593
|
+
# @note For internal use only
|
594
|
+
# @!visibility private
|
595
|
+
def update_from(other)
|
596
|
+
@name = other.name
|
597
|
+
@position = other.position
|
598
|
+
@topic = other.topic
|
599
|
+
@recipients = other.recipients
|
600
|
+
@bitrate = other.bitrate
|
601
|
+
@user_limit = other.user_limit
|
602
|
+
@permission_overwrites = other.permission_overwrites
|
603
|
+
@nsfw = other.nsfw
|
604
|
+
@parent_id = other.parent_id
|
605
|
+
@rate_limit_per_user = other.rate_limit_per_user
|
606
|
+
end
|
607
|
+
|
608
|
+
# The list of users currently in this channel. For a voice channel, it will return all the members currently
|
609
|
+
# in that channel. For a text channel, it will return all online members that have permission to read it.
|
610
|
+
# @return [Array<Member>] the users in this channel
|
611
|
+
def users
|
612
|
+
if text?
|
613
|
+
server.online_members(include_idle: true).select { |u| u.can_read_messages? self }
|
614
|
+
elsif voice?
|
615
|
+
server.voice_states.filter_map { |id, voice_state| server.member(id) if !voice_state.voice_channel.nil? && voice_state.voice_channel.id == @id }
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
# Retrieves some of this channel's message history.
|
620
|
+
# @param amount [Integer] How many messages to retrieve. This must be less than or equal to 100, if it is higher
|
621
|
+
# than 100 it will be treated as 100 on Discord's side.
|
622
|
+
# @param before_id [Integer] The ID of the most recent message the retrieval should start at, or nil if it should
|
623
|
+
# start at the current message.
|
624
|
+
# @param after_id [Integer] The ID of the oldest message the retrieval should start at, or nil if it should start
|
625
|
+
# as soon as possible with the specified amount.
|
626
|
+
# @param around_id [Integer] The ID of the message retrieval should start from, reading in both directions
|
627
|
+
# @example Count the number of messages in the last 50 messages that contain the letter 'e'.
|
628
|
+
# message_count = channel.history(50).count {|message| message.content.include? "e"}
|
629
|
+
# @example Get the last 10 messages before the provided message.
|
630
|
+
# last_ten_messages = channel.history(10, message.id)
|
631
|
+
# @return [Array<Message>] the retrieved messages.
|
632
|
+
def history(amount, before_id = nil, after_id = nil, around_id = nil)
|
633
|
+
logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
|
634
|
+
JSON.parse(logs).map { |message| Message.new(message, @bot) }
|
635
|
+
end
|
636
|
+
|
637
|
+
# Retrieves message history, but only message IDs for use with prune.
|
638
|
+
# @note For internal use only
|
639
|
+
# @!visibility private
|
640
|
+
def history_ids(amount, before_id = nil, after_id = nil, around_id = nil)
|
641
|
+
logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
|
642
|
+
JSON.parse(logs).map { |message| message['id'].to_i }
|
643
|
+
end
|
644
|
+
|
645
|
+
# Returns a single message from this channel's history by ID.
|
646
|
+
# @param message_id [Integer] The ID of the message to retrieve.
|
647
|
+
# @return [Message, nil] the retrieved message, or `nil` if it couldn't be found.
|
648
|
+
def load_message(message_id)
|
649
|
+
raise ArgumentError, 'message_id cannot be nil' if message_id.nil?
|
650
|
+
|
651
|
+
response = API::Channel.message(@bot.token, @id, message_id)
|
652
|
+
Message.new(JSON.parse(response), @bot)
|
653
|
+
rescue Discordrb::Errors::UnknownMessage
|
654
|
+
nil
|
655
|
+
end
|
656
|
+
|
657
|
+
alias_method :message, :load_message
|
658
|
+
|
659
|
+
# Requests all pinned messages in a channel.
|
660
|
+
# @return [Array<Message>] the received messages.
|
661
|
+
def pins
|
662
|
+
msgs = API::Channel.pinned_messages(@bot.token, @id)
|
663
|
+
JSON.parse(msgs).map { |msg| Message.new(msg, @bot) }
|
664
|
+
end
|
665
|
+
|
666
|
+
# Delete the last N messages on this channel.
|
667
|
+
# @param amount [Integer] The amount of message history to consider for pruning. Must be a value between 2 and 100 (Discord limitation)
|
668
|
+
# @param strict [true, false] Whether an error should be raised when a message is reached that is too old to be bulk
|
669
|
+
# deleted. If this is false only a warning message will be output to the console.
|
670
|
+
# @param reason [String, nil] The reason for pruning
|
671
|
+
# @raise [ArgumentError] if the amount of messages is not a value between 2 and 100
|
672
|
+
# @yield [message] Yields each message in this channels history for filtering the messages to delete
|
673
|
+
# @example Pruning messages from a specific user ID
|
674
|
+
# channel.prune(100) { |m| m.author.id == 83283213010599936 }
|
675
|
+
# @return [Integer] The amount of messages that were successfully deleted
|
676
|
+
def prune(amount, strict = false, reason = nil, &block)
|
677
|
+
raise ArgumentError, 'Can only delete between 1 and 100 messages!' unless amount.between?(1, 100)
|
678
|
+
|
679
|
+
messages =
|
680
|
+
if block
|
681
|
+
history(amount).select(&block).map(&:id)
|
682
|
+
else
|
683
|
+
history_ids(amount)
|
684
|
+
end
|
685
|
+
|
686
|
+
case messages.size
|
687
|
+
when 0
|
688
|
+
0
|
689
|
+
when 1
|
690
|
+
API::Channel.delete_message(@bot.token, @id, messages.first, reason)
|
691
|
+
1
|
692
|
+
else
|
693
|
+
bulk_delete(messages, strict, reason)
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
# Deletes a collection of messages
|
698
|
+
# @param messages [Array<Message, String, Integer>] the messages (or message IDs) to delete. Total must be an amount between 2 and 100 (Discord limitation)
|
699
|
+
# @param strict [true, false] Whether an error should be raised when a message is reached that is too old to be bulk
|
700
|
+
# deleted. If this is false only a warning message will be output to the console.
|
701
|
+
# @param reason [String, nil] The reason for deleting the messages
|
702
|
+
# @raise [ArgumentError] if the amount of messages is not a value between 2 and 100
|
703
|
+
# @return [Integer] The amount of messages that were successfully deleted
|
704
|
+
def delete_messages(messages, strict = false, reason = nil)
|
705
|
+
raise ArgumentError, 'Can only delete between 2 and 100 messages!' unless messages.count.between?(2, 100)
|
706
|
+
|
707
|
+
messages.map!(&:resolve_id)
|
708
|
+
bulk_delete(messages, strict, reason)
|
709
|
+
end
|
710
|
+
|
711
|
+
# Updates the cached permission overwrites
|
712
|
+
# @note For internal use only
|
713
|
+
# @!visibility private
|
714
|
+
def update_overwrites(overwrites)
|
715
|
+
@permission_overwrites = overwrites
|
716
|
+
end
|
717
|
+
|
718
|
+
# Add an {Await} for a message in this channel. This is identical in functionality to adding a
|
719
|
+
# {Discordrb::Events::MessageEvent} await with the `in` attribute as this channel.
|
720
|
+
# @see Bot#add_await
|
721
|
+
# @deprecated Will be changed to blocking behavior in v4.0. Use {#await!} instead.
|
722
|
+
def await(key, attributes = {}, &block)
|
723
|
+
@bot.add_await(key, Discordrb::Events::MessageEvent, { in: @id }.merge(attributes), &block)
|
724
|
+
end
|
725
|
+
|
726
|
+
# Add a blocking {Await} for a message in this channel. This is identical in functionality to adding a
|
727
|
+
# {Discordrb::Events::MessageEvent} await with the `in` attribute as this channel.
|
728
|
+
# @see Bot#add_await!
|
729
|
+
def await!(attributes = {}, &block)
|
730
|
+
@bot.add_await!(Discordrb::Events::MessageEvent, { in: @id }.merge(attributes), &block)
|
731
|
+
end
|
732
|
+
|
733
|
+
# Creates a new invite to this channel.
|
734
|
+
# @param max_age [Integer] How many seconds this invite should last.
|
735
|
+
# @param max_uses [Integer] How many times this invite should be able to be used.
|
736
|
+
# @param temporary [true, false] Whether membership should be temporary (kicked after going offline).
|
737
|
+
# @param unique [true, false] If true, Discord will always send a unique invite instead of possibly re-using a similar one
|
738
|
+
# @param reason [String] The reason the for the creation of this invite.
|
739
|
+
# @return [Invite] the created invite.
|
740
|
+
def make_invite(max_age = 0, max_uses = 0, temporary = false, unique = false, reason = nil)
|
741
|
+
response = API::Channel.create_invite(@bot.token, @id, max_age, max_uses, temporary, unique, reason)
|
742
|
+
Invite.new(JSON.parse(response), @bot)
|
743
|
+
end
|
744
|
+
|
745
|
+
alias_method :invite, :make_invite
|
746
|
+
|
747
|
+
# Starts typing, which displays the typing indicator on the client for five seconds.
|
748
|
+
# If you want to keep typing you'll have to resend this every five seconds. (An abstraction
|
749
|
+
# for this will eventually be coming)
|
750
|
+
# @example Send a typing indicator for the bot in a given channel.
|
751
|
+
# channel.start_typing()
|
752
|
+
def start_typing
|
753
|
+
API::Channel.start_typing(@bot.token, @id)
|
754
|
+
end
|
755
|
+
|
756
|
+
# Creates a Group channel
|
757
|
+
# @param user_ids [Array<Integer>] Array of user IDs to add to the new group channel (Excluding
|
758
|
+
# the recipient of the PM channel).
|
759
|
+
# @return [Channel] the created channel.
|
760
|
+
def create_group(user_ids)
|
761
|
+
raise 'Attempted to create group channel on a non-pm channel!' unless pm?
|
762
|
+
|
763
|
+
response = API::Channel.create_group(@bot.token, @id, user_ids.shift)
|
764
|
+
channel = Channel.new(JSON.parse(response), @bot)
|
765
|
+
channel.add_group_users(user_ids)
|
766
|
+
end
|
767
|
+
|
768
|
+
# Adds a user to a group channel.
|
769
|
+
# @param user_ids [Array<String, Integer>, String, Integer] User ID or array of user IDs to add to the group channel.
|
770
|
+
# @return [Channel] the group channel.
|
771
|
+
def add_group_users(user_ids)
|
772
|
+
raise 'Attempted to add a user to a non-group channel!' unless group?
|
773
|
+
|
774
|
+
user_ids = [user_ids] unless user_ids.is_a? Array
|
775
|
+
user_ids.each do |user_id|
|
776
|
+
API::Channel.add_group_user(@bot.token, @id, user_id.resolve_id)
|
777
|
+
end
|
778
|
+
self
|
779
|
+
end
|
780
|
+
|
781
|
+
alias_method :add_group_user, :add_group_users
|
782
|
+
|
783
|
+
# Removes a user from a group channel.
|
784
|
+
# @param user_ids [Array<String, Integer>, String, Integer] User ID or array of user IDs to remove from the group channel.
|
785
|
+
# @return [Channel] the group channel.
|
786
|
+
def remove_group_users(user_ids)
|
787
|
+
raise 'Attempted to remove a user from a non-group channel!' unless group?
|
788
|
+
|
789
|
+
user_ids = [user_ids] unless user_ids.is_a? Array
|
790
|
+
user_ids.each do |user_id|
|
791
|
+
API::Channel.remove_group_user(@bot.token, @id, user_id.resolve_id)
|
792
|
+
end
|
793
|
+
self
|
794
|
+
end
|
795
|
+
|
796
|
+
alias_method :remove_group_user, :remove_group_users
|
797
|
+
|
798
|
+
# Leaves the group.
|
799
|
+
def leave_group
|
800
|
+
raise 'Attempted to leave a non-group channel!' unless group?
|
801
|
+
|
802
|
+
API::Channel.leave_group(@bot.token, @id)
|
803
|
+
end
|
804
|
+
|
805
|
+
alias_method :leave, :leave_group
|
806
|
+
|
807
|
+
# Creates a webhook in this channel
|
808
|
+
# @param name [String] the default name of this webhook.
|
809
|
+
# @param avatar [String] the default avatar URL to give this webhook.
|
810
|
+
# @param reason [String] the reason for the webhook creation.
|
811
|
+
# @raise [ArgumentError] if the channel isn't a text channel in a server.
|
812
|
+
# @return [Webhook] the created webhook.
|
813
|
+
def create_webhook(name, avatar = nil, reason = nil)
|
814
|
+
raise ArgumentError, 'Tried to create a webhook in a non-server channel' unless server
|
815
|
+
raise ArgumentError, 'Tried to create a webhook in a non-text channel' unless text?
|
816
|
+
|
817
|
+
response = API::Channel.create_webhook(@bot.token, @id, name, avatar, reason)
|
818
|
+
Webhook.new(JSON.parse(response), @bot)
|
819
|
+
end
|
820
|
+
|
821
|
+
# Requests a list of Webhooks on the channel.
|
822
|
+
# @return [Array<Webhook>] webhooks on the channel.
|
823
|
+
def webhooks
|
824
|
+
raise 'Tried to request webhooks from a non-server channel' unless server
|
825
|
+
|
826
|
+
webhooks = JSON.parse(API::Channel.webhooks(@bot.token, @id))
|
827
|
+
webhooks.map { |webhook_data| Webhook.new(webhook_data, @bot) }
|
828
|
+
end
|
829
|
+
|
830
|
+
# Requests a list of Invites to the channel.
|
831
|
+
# @return [Array<Invite>] invites to the channel.
|
832
|
+
def invites
|
833
|
+
raise 'Tried to request invites from a non-server channel' unless server
|
834
|
+
|
835
|
+
invites = JSON.parse(API::Channel.invites(@bot.token, @id))
|
836
|
+
invites.map { |invite_data| Invite.new(invite_data, @bot) }
|
837
|
+
end
|
838
|
+
|
839
|
+
# Start a thread.
|
840
|
+
# @param name [String] The name of the thread.
|
841
|
+
# @param auto_archive_duration [60, 1440, 4320, 10080] How long before a thread is automatically
|
842
|
+
# archived.
|
843
|
+
# @param message [Message, Integer, String] The message to reference when starting this thread.
|
844
|
+
# @param type [Symbol, Integer] The type of thread to create. Can be a key from {TYPES} or the value.
|
845
|
+
# @return [Channel]
|
846
|
+
def start_thread(name, auto_archive_duration, message: nil, type: 11)
|
847
|
+
message_id = message&.id || message
|
848
|
+
type = TYPES[type] || type
|
849
|
+
|
850
|
+
data = if message
|
851
|
+
API::Channel.start_thread_with_message(@bot.token, @id, message_id, name, auto_archive_duration)
|
852
|
+
else
|
853
|
+
API::Channel.start_thread_without_message(@bot.token, @id, name, auto_archive_duration, type)
|
854
|
+
end
|
855
|
+
|
856
|
+
Channel.new(JSON.parse(data), @bot, @server)
|
857
|
+
end
|
858
|
+
|
859
|
+
# @!group Threads
|
860
|
+
|
861
|
+
# Join this thread.
|
862
|
+
def join_thread
|
863
|
+
@bot.join_thread(@id)
|
864
|
+
end
|
865
|
+
|
866
|
+
# Leave this thread
|
867
|
+
def leave_thread
|
868
|
+
@bot.leave_thread(@id)
|
869
|
+
end
|
870
|
+
|
871
|
+
# Members in the thread.
|
872
|
+
def members
|
873
|
+
@bot.thread_members[@id].collect { |id| @server_id ? @bot.member(@server_id, id) : @bot.user(id) }
|
874
|
+
end
|
875
|
+
|
876
|
+
# Add a member to the thread
|
877
|
+
# @param member [Member, Integer, String] The member, or ID of the member, to add to this thread.
|
878
|
+
def add_member(member)
|
879
|
+
@bot.add_thread_member(@id, member)
|
880
|
+
end
|
881
|
+
|
882
|
+
# @param member [Member, Integer, String] The member, or ID of the member, to remove from a thread.
|
883
|
+
def remove_member(member)
|
884
|
+
@bot.remove_thread_member(@id, member)
|
885
|
+
end
|
886
|
+
|
887
|
+
# @!endgroup
|
888
|
+
|
889
|
+
# The default `inspect` method is overwritten to give more useful output.
|
890
|
+
def inspect
|
891
|
+
"<Channel name=#{@name} id=#{@id} topic=\"#{@topic}\" type=#{@type} position=#{@position} server=#{@server || @server_id}>"
|
892
|
+
end
|
893
|
+
|
894
|
+
# Adds a recipient to a group channel.
|
895
|
+
# @param recipient [Recipient] the recipient to add to the group
|
896
|
+
# @raise [ArgumentError] if tried to add a non-recipient
|
897
|
+
# @note For internal use only
|
898
|
+
# @!visibility private
|
899
|
+
def add_recipient(recipient)
|
900
|
+
raise 'Tried to add recipient to a non-group channel' unless group?
|
901
|
+
raise ArgumentError, 'Tried to add a non-recipient to a group' unless recipient.is_a?(Recipient)
|
902
|
+
|
903
|
+
@recipients << recipient
|
904
|
+
end
|
905
|
+
|
906
|
+
# Removes a recipient from a group channel.
|
907
|
+
# @param recipient [Recipient] the recipient to remove from the group
|
908
|
+
# @raise [ArgumentError] if tried to remove a non-recipient
|
909
|
+
# @note For internal use only
|
910
|
+
# @!visibility private
|
911
|
+
def remove_recipient(recipient)
|
912
|
+
raise 'Tried to remove recipient from a non-group channel' unless group?
|
913
|
+
raise ArgumentError, 'Tried to remove a non-recipient from a group' unless recipient.is_a?(Recipient)
|
914
|
+
|
915
|
+
@recipients.delete(recipient)
|
916
|
+
end
|
917
|
+
|
918
|
+
# Updates the cached data with new data
|
919
|
+
# @note For internal use only
|
920
|
+
# @!visibility private
|
921
|
+
def update_data(new_data = nil)
|
922
|
+
new_data ||= JSON.parse(API::Channel.resolve(@bot.token, @id))
|
923
|
+
@name = new_data[:name] || new_data['name'] || @name
|
924
|
+
@topic = new_data[:topic] || new_data['topic'] || @topic
|
925
|
+
@position = new_data[:position] || new_data['position'] || @position
|
926
|
+
@bitrate = new_data[:bitrate] || new_data['bitrate'] || @bitrate
|
927
|
+
@user_limit = new_data[:user_limit] || new_data['user_limit'] || @user_limit
|
928
|
+
new_nsfw = new_data.key?(:nsfw) ? new_data[:nsfw] : new_data['nsfw']
|
929
|
+
@nsfw = new_nsfw.nil? ? @nsfw : new_nsfw
|
930
|
+
@parent_id = new_data[:parent_id] || new_data['parent_id'] || @parent_id
|
931
|
+
process_permission_overwrites(new_data[:permission_overwrites] || new_data['permission_overwrites'])
|
932
|
+
@rate_limit_per_user = new_data[:rate_limit_per_user] || new_data['rate_limit_per_user'] || @rate_limit_per_user
|
933
|
+
end
|
934
|
+
|
935
|
+
# @return [String] a URL that a user can use to navigate to this channel in the client
|
936
|
+
def link
|
937
|
+
"https://discord.com/channels/#{@server_id || '@me'}/#{@channel.id}"
|
938
|
+
end
|
939
|
+
|
940
|
+
alias_method :jump_link, :link
|
941
|
+
|
942
|
+
private
|
943
|
+
|
944
|
+
# For bulk_delete checking
|
945
|
+
TWO_WEEKS = 86_400 * 14
|
946
|
+
|
947
|
+
# Deletes a list of messages on this channel using bulk delete.
|
948
|
+
def bulk_delete(ids, strict = false, reason = nil)
|
949
|
+
min_snowflake = IDObject.synthesise(Time.now - TWO_WEEKS)
|
950
|
+
|
951
|
+
ids.reject! do |e|
|
952
|
+
next unless e < min_snowflake
|
953
|
+
|
954
|
+
message = "Attempted to bulk_delete message #{e} which is too old (min = #{min_snowflake})"
|
955
|
+
raise ArgumentError, message if strict
|
956
|
+
|
957
|
+
Discordrb::LOGGER.warn(message)
|
958
|
+
true
|
959
|
+
end
|
960
|
+
|
961
|
+
API::Channel.bulk_delete_messages(@bot.token, @id, ids, reason)
|
962
|
+
ids.size
|
963
|
+
end
|
964
|
+
|
965
|
+
def update_channel_data(new_data)
|
966
|
+
new_nsfw = new_data[:nsfw].is_a?(TrueClass) || new_data[:nsfw].is_a?(FalseClass) ? new_data[:nsfw] : @nsfw
|
967
|
+
# send permission_overwrite only when explicitly set
|
968
|
+
overwrites = new_data[:permission_overwrites] ? new_data[:permission_overwrites].map { |_, v| v.to_hash } : nil
|
969
|
+
response = JSON.parse(API::Channel.update(@bot.token, @id,
|
970
|
+
new_data[:name] || @name,
|
971
|
+
new_data[:topic] || @topic,
|
972
|
+
new_data[:position] || @position,
|
973
|
+
new_data[:bitrate] || @bitrate,
|
974
|
+
new_data[:user_limit] || @user_limit,
|
975
|
+
new_nsfw,
|
976
|
+
overwrites,
|
977
|
+
new_data[:parent_id] || @parent_id,
|
978
|
+
new_data[:rate_limit_per_user] || @rate_limit_per_user))
|
979
|
+
update_data(response)
|
980
|
+
end
|
981
|
+
|
982
|
+
def process_permission_overwrites(overwrites)
|
983
|
+
# Populate permission overwrites
|
984
|
+
@permission_overwrites = {}
|
985
|
+
return unless overwrites
|
986
|
+
|
987
|
+
overwrites.each do |element|
|
988
|
+
id = element['id'].to_i
|
989
|
+
@permission_overwrites[id] = Overwrite.from_hash(element)
|
990
|
+
end
|
991
|
+
end
|
992
|
+
end
|
993
|
+
end
|