onyxcord 1.1.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 +7 -0
- data/.devcontainer/Dockerfile +13 -0
- data/.devcontainer/devcontainer.json +29 -0
- data/.devcontainer/postcreate.sh +4 -0
- data/.github/CONTRIBUTING.md +13 -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/ci.yml +78 -0
- data/.github/workflows/codeql.yml +65 -0
- data/.github/workflows/deploy.yml +54 -0
- data/.github/workflows/release.yml +51 -0
- data/.gitignore +16 -0
- data/.markdownlint.json +4 -0
- data/.overcommit.yml +7 -0
- data/.rspec +2 -0
- data/.rubocop.yml +129 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +0 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +305 -0
- data/Rakefile +17 -0
- data/bin/console +15 -0
- data/bin/setup +7 -0
- data/lib/onyxcord/allowed_mentions.rb +43 -0
- data/lib/onyxcord/api/application.rb +316 -0
- data/lib/onyxcord/api/channel.rb +700 -0
- data/lib/onyxcord/api/interaction.rb +67 -0
- data/lib/onyxcord/api/invite.rb +44 -0
- data/lib/onyxcord/api/server.rb +775 -0
- data/lib/onyxcord/api/user.rb +158 -0
- data/lib/onyxcord/api/webhook.rb +163 -0
- data/lib/onyxcord/api.rb +335 -0
- data/lib/onyxcord/await.rb +51 -0
- data/lib/onyxcord/bot.rb +1971 -0
- data/lib/onyxcord/cache.rb +326 -0
- data/lib/onyxcord/colour_rgb.rb +43 -0
- data/lib/onyxcord/commands/command_bot.rb +511 -0
- data/lib/onyxcord/commands/container.rb +112 -0
- data/lib/onyxcord/commands/events.rb +11 -0
- data/lib/onyxcord/commands/parser.rb +327 -0
- data/lib/onyxcord/commands/rate_limiter.rb +144 -0
- data/lib/onyxcord/configuration.rb +125 -0
- data/lib/onyxcord/container.rb +988 -0
- data/lib/onyxcord/data/activity.rb +271 -0
- data/lib/onyxcord/data/application.rb +341 -0
- data/lib/onyxcord/data/attachment.rb +91 -0
- data/lib/onyxcord/data/audit_logs.rb +438 -0
- data/lib/onyxcord/data/avatar_decoration.rb +26 -0
- data/lib/onyxcord/data/call.rb +22 -0
- data/lib/onyxcord/data/channel.rb +1355 -0
- data/lib/onyxcord/data/channel_tag.rb +69 -0
- data/lib/onyxcord/data/collectibles.rb +47 -0
- data/lib/onyxcord/data/component.rb +583 -0
- data/lib/onyxcord/data/embed.rb +258 -0
- data/lib/onyxcord/data/emoji.rb +123 -0
- data/lib/onyxcord/data/install_params.rb +24 -0
- data/lib/onyxcord/data/integration.rb +144 -0
- data/lib/onyxcord/data/interaction.rb +1141 -0
- data/lib/onyxcord/data/invite.rb +137 -0
- data/lib/onyxcord/data/member.rb +528 -0
- data/lib/onyxcord/data/message.rb +612 -0
- data/lib/onyxcord/data/message_activity.rb +41 -0
- data/lib/onyxcord/data/overwrite.rb +109 -0
- data/lib/onyxcord/data/poll.rb +365 -0
- data/lib/onyxcord/data/primary_server.rb +60 -0
- data/lib/onyxcord/data/profile.rb +79 -0
- data/lib/onyxcord/data/reaction.rb +64 -0
- data/lib/onyxcord/data/recipient.rb +34 -0
- data/lib/onyxcord/data/role.rb +449 -0
- data/lib/onyxcord/data/role_connection_data.rb +69 -0
- data/lib/onyxcord/data/role_subscription.rb +41 -0
- data/lib/onyxcord/data/scheduled_event.rb +513 -0
- data/lib/onyxcord/data/server.rb +1614 -0
- data/lib/onyxcord/data/server_preview.rb +68 -0
- data/lib/onyxcord/data/snapshot.rb +112 -0
- data/lib/onyxcord/data/team.rb +98 -0
- data/lib/onyxcord/data/timestamp.rb +69 -0
- data/lib/onyxcord/data/user.rb +324 -0
- data/lib/onyxcord/data/voice_region.rb +46 -0
- data/lib/onyxcord/data/voice_state.rb +41 -0
- data/lib/onyxcord/data/webhook.rb +238 -0
- data/lib/onyxcord/data.rb +57 -0
- data/lib/onyxcord/errors.rb +246 -0
- data/lib/onyxcord/event_executor.rb +80 -0
- data/lib/onyxcord/events/await.rb +48 -0
- data/lib/onyxcord/events/bans.rb +60 -0
- data/lib/onyxcord/events/channels.rb +225 -0
- data/lib/onyxcord/events/generic.rb +129 -0
- data/lib/onyxcord/events/guilds.rb +269 -0
- data/lib/onyxcord/events/integrations.rb +100 -0
- data/lib/onyxcord/events/interactions.rb +624 -0
- data/lib/onyxcord/events/invites.rb +127 -0
- data/lib/onyxcord/events/lifetime.rb +31 -0
- data/lib/onyxcord/events/members.rb +110 -0
- data/lib/onyxcord/events/message.rb +399 -0
- data/lib/onyxcord/events/polls.rb +118 -0
- data/lib/onyxcord/events/presence.rb +131 -0
- data/lib/onyxcord/events/raw.rb +74 -0
- data/lib/onyxcord/events/reactions.rb +218 -0
- data/lib/onyxcord/events/roles.rb +87 -0
- data/lib/onyxcord/events/scheduled_events.rb +171 -0
- data/lib/onyxcord/events/threads.rb +100 -0
- data/lib/onyxcord/events/typing.rb +73 -0
- data/lib/onyxcord/events/voice_server_update.rb +48 -0
- data/lib/onyxcord/events/voice_state_update.rb +106 -0
- data/lib/onyxcord/events/webhooks.rb +65 -0
- data/lib/onyxcord/gateway.rb +890 -0
- data/lib/onyxcord/id_object.rb +39 -0
- data/lib/onyxcord/light/data.rb +62 -0
- data/lib/onyxcord/light/integrations.rb +73 -0
- data/lib/onyxcord/light/light_bot.rb +58 -0
- data/lib/onyxcord/light.rb +8 -0
- data/lib/onyxcord/logger.rb +120 -0
- data/lib/onyxcord/message_components.rb +70 -0
- data/lib/onyxcord/paginator.rb +60 -0
- data/lib/onyxcord/permissions.rb +255 -0
- data/lib/onyxcord/rate_limiter/gateway.rb +42 -0
- data/lib/onyxcord/rate_limiter/rest.rb +89 -0
- data/lib/onyxcord/version.rb +7 -0
- data/lib/onyxcord/voice/encoder.rb +115 -0
- data/lib/onyxcord/voice/network.rb +380 -0
- data/lib/onyxcord/voice/opcodes.rb +29 -0
- data/lib/onyxcord/voice/sodium.rb +157 -0
- data/lib/onyxcord/voice/timer.rb +19 -0
- data/lib/onyxcord/voice/voice_bot.rb +386 -0
- data/lib/onyxcord/webhooks.rb +14 -0
- data/lib/onyxcord/websocket.rb +62 -0
- data/lib/onyxcord.rb +180 -0
- data/onyxcord-webhooks.gemspec +30 -0
- data/onyxcord.gemspec +50 -0
- metadata +421 -0
|
@@ -0,0 +1,1355 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'onyxcord/webhooks/view'
|
|
4
|
+
require 'onyxcord/message_components'
|
|
5
|
+
require 'time'
|
|
6
|
+
|
|
7
|
+
module OnyxCord
|
|
8
|
+
# A Discord channel, including data like the topic
|
|
9
|
+
class Channel
|
|
10
|
+
include IDObject
|
|
11
|
+
|
|
12
|
+
# Map of channel types.
|
|
13
|
+
TYPES = {
|
|
14
|
+
text: 0,
|
|
15
|
+
dm: 1,
|
|
16
|
+
voice: 2,
|
|
17
|
+
group: 3,
|
|
18
|
+
category: 4,
|
|
19
|
+
news: 5,
|
|
20
|
+
store: 6,
|
|
21
|
+
news_thread: 10,
|
|
22
|
+
public_thread: 11,
|
|
23
|
+
private_thread: 12,
|
|
24
|
+
stage_voice: 13,
|
|
25
|
+
directory: 14,
|
|
26
|
+
forum: 15,
|
|
27
|
+
media: 16
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
# Map of channel flags.
|
|
31
|
+
FLAGS = {
|
|
32
|
+
pinned: 1 << 1,
|
|
33
|
+
require_tag: 1 << 4,
|
|
34
|
+
hide_download_options: 1 << 15
|
|
35
|
+
}.freeze
|
|
36
|
+
|
|
37
|
+
# Map of forum layouts.
|
|
38
|
+
FORUM_LAYOUTS = {
|
|
39
|
+
not_set: 0,
|
|
40
|
+
list_view: 1,
|
|
41
|
+
gallery_view: 2
|
|
42
|
+
}.freeze
|
|
43
|
+
|
|
44
|
+
# Map of forum sort orders.
|
|
45
|
+
FORUM_SORT_ORDERS = {
|
|
46
|
+
latest_activity: 0,
|
|
47
|
+
creation_time: 1
|
|
48
|
+
}.freeze
|
|
49
|
+
|
|
50
|
+
# Map of video quality modes.
|
|
51
|
+
VIDEO_QUALITY_MODES = {
|
|
52
|
+
auto: 1,
|
|
53
|
+
full: 2
|
|
54
|
+
}.freeze
|
|
55
|
+
|
|
56
|
+
# @return [String] this channel's name.
|
|
57
|
+
attr_reader :name
|
|
58
|
+
|
|
59
|
+
# @return [Integer, nil] the ID of the parent channel, if this channel is inside a category. If this channel is a
|
|
60
|
+
# thread, this is the text channel it is a child to.
|
|
61
|
+
attr_reader :parent_id
|
|
62
|
+
|
|
63
|
+
# @return [Integer] the type of this channel
|
|
64
|
+
# @see TYPES
|
|
65
|
+
attr_reader :type
|
|
66
|
+
|
|
67
|
+
# @return [Integer, nil] the ID of the owner of the group channel or nil if this is not a group channel. If this
|
|
68
|
+
# channel is a thread, this is the member that started the thread.
|
|
69
|
+
attr_reader :owner_id
|
|
70
|
+
|
|
71
|
+
# @return [Array<Recipient>, nil] the array of recipients of the private messages, or nil if this is not a Private channel
|
|
72
|
+
attr_reader :recipients
|
|
73
|
+
|
|
74
|
+
# @return [String] the channel's topic
|
|
75
|
+
attr_reader :topic
|
|
76
|
+
|
|
77
|
+
# @return [Integer] the bitrate (in bps) of the channel
|
|
78
|
+
attr_reader :bitrate
|
|
79
|
+
|
|
80
|
+
# @return [Integer] the amount of users that can be in the channel. `0` means it is unlimited.
|
|
81
|
+
attr_reader :user_limit
|
|
82
|
+
alias_method :limit, :user_limit
|
|
83
|
+
|
|
84
|
+
# @return [Integer] the channel's position on the channel list
|
|
85
|
+
attr_reader :position
|
|
86
|
+
|
|
87
|
+
# @return [Integer] the amount of time (in seconds) users need to wait to send in between messages.
|
|
88
|
+
attr_reader :rate_limit_per_user
|
|
89
|
+
alias_method :slowmode_rate, :rate_limit_per_user
|
|
90
|
+
|
|
91
|
+
# @return [Integer, nil] An approximate count of messages sent in a thread, excluding deleted messages.
|
|
92
|
+
attr_reader :message_count
|
|
93
|
+
|
|
94
|
+
# @return [Integer, nil] An approximate count of members in a thread. Stops counting at 50.
|
|
95
|
+
attr_reader :member_count
|
|
96
|
+
|
|
97
|
+
# @return [true, false, nil] Whether or not this thread is archived.
|
|
98
|
+
attr_reader :archived
|
|
99
|
+
alias_method :archived?, :archived
|
|
100
|
+
|
|
101
|
+
# @return [Integer, nil] How long after the last message before a thread is automatically archived.
|
|
102
|
+
attr_reader :auto_archive_duration
|
|
103
|
+
|
|
104
|
+
# @return [Time, nil] The timestamp of when this threads status last changed.
|
|
105
|
+
attr_reader :archive_timestamp
|
|
106
|
+
|
|
107
|
+
# @return [true, false, nil] Whether this thread is locked or not.
|
|
108
|
+
attr_reader :locked
|
|
109
|
+
alias_method :locked?, :locked
|
|
110
|
+
|
|
111
|
+
# @return [Time, nil] When the current user joined this thread.
|
|
112
|
+
attr_reader :join_timestamp
|
|
113
|
+
|
|
114
|
+
# @return [Integer, nil] Member flags for this thread, used for notifications.
|
|
115
|
+
attr_reader :member_flags
|
|
116
|
+
|
|
117
|
+
# @return [true, false, nil] For private threads, determines whether non-moderators can add other non-moderators to
|
|
118
|
+
# a thread.
|
|
119
|
+
attr_reader :invitable
|
|
120
|
+
alias_method :invitable?, :invitable
|
|
121
|
+
|
|
122
|
+
# @return [Time, nil] The time at when the last pinned message was pinned in this channel.
|
|
123
|
+
attr_reader :last_pin_timestamp
|
|
124
|
+
|
|
125
|
+
# @return [Integer, nil] The ID of the last message sent in this channel. This may not point to a valid message.
|
|
126
|
+
attr_reader :last_message_id
|
|
127
|
+
|
|
128
|
+
# @return [Integer] An approximate count of messages sent in this thread, including deleted messages.
|
|
129
|
+
attr_reader :total_message_sent
|
|
130
|
+
alias_method :total_messages_sent, :total_message_sent
|
|
131
|
+
|
|
132
|
+
# @return [Integer] The flags set on this channel combined as a bitfield.
|
|
133
|
+
attr_reader :flags
|
|
134
|
+
|
|
135
|
+
# @return [String, nil] The ID of the RTC voice region for this voice or stage channel. A region of `nil` means the
|
|
136
|
+
# the voice region will automatically be determined by Discord.
|
|
137
|
+
attr_reader :voice_region
|
|
138
|
+
|
|
139
|
+
# @return [Integer, nil] The video quality mode of this voice or stage channel.
|
|
140
|
+
attr_reader :video_quality_mode
|
|
141
|
+
|
|
142
|
+
# @return [Integer, nil] The default client-side duration before a thread is automatically hidden.
|
|
143
|
+
attr_reader :default_auto_archive_duration
|
|
144
|
+
|
|
145
|
+
# @return [Integer, nil] The default sorting order for threads in this forum or media channel.
|
|
146
|
+
attr_reader :default_sort_order
|
|
147
|
+
|
|
148
|
+
# @return [Integer, nil] The default layout used to display threads in this forum or media channel.
|
|
149
|
+
attr_reader :default_forum_layout
|
|
150
|
+
|
|
151
|
+
# @return [Integer, nil] The initial slowmode rate set on newly created threads in this channel.
|
|
152
|
+
attr_reader :default_thread_rate_limit_per_user
|
|
153
|
+
|
|
154
|
+
# @return [true, false] whether or not this channel is a PM or group channel.
|
|
155
|
+
def private?
|
|
156
|
+
pm? || group?
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# @return [String] a string that will mention the channel as a clickable link on Discord.
|
|
160
|
+
def mention
|
|
161
|
+
"<##{@id}>"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# @return [Recipient, nil] the recipient of the private messages, or nil if this is not a PM channel
|
|
165
|
+
def recipient
|
|
166
|
+
@recipients.first if pm?
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# @!visibility private
|
|
170
|
+
def initialize(data, bot, server = nil)
|
|
171
|
+
@bot = bot
|
|
172
|
+
# data is sometimes a Hash and other times an array of Hashes, you only want the last one if it's an array
|
|
173
|
+
data = data[-1] if data.is_a?(Array)
|
|
174
|
+
|
|
175
|
+
@id = data['id'].to_i
|
|
176
|
+
@type = data['type'] || 0
|
|
177
|
+
@topic = data['topic']
|
|
178
|
+
@bitrate = data['bitrate']
|
|
179
|
+
@user_limit = data['user_limit']
|
|
180
|
+
@position = data['position']
|
|
181
|
+
@parent_id = data['parent_id']&.to_i
|
|
182
|
+
|
|
183
|
+
if private?
|
|
184
|
+
@recipients = []
|
|
185
|
+
data['recipients']&.each do |recipient|
|
|
186
|
+
recipient_user = bot.ensure_user(recipient)
|
|
187
|
+
@recipients << Recipient.new(recipient_user, self, bot)
|
|
188
|
+
end
|
|
189
|
+
if pm?
|
|
190
|
+
@name = @recipients.first.username
|
|
191
|
+
else
|
|
192
|
+
@name = data['name']
|
|
193
|
+
@owner_id = data['owner_id']
|
|
194
|
+
end
|
|
195
|
+
else
|
|
196
|
+
@name = data['name']
|
|
197
|
+
@server_id = server&.id || data['guild_id'].to_i
|
|
198
|
+
@server = server
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
@nsfw = data['nsfw'] || false
|
|
202
|
+
@rate_limit_per_user = data['rate_limit_per_user'] || 0
|
|
203
|
+
@message_count = data['message_count']
|
|
204
|
+
@member_count = data['member_count']
|
|
205
|
+
@total_message_sent = data['total_message_sent'] || 0
|
|
206
|
+
|
|
207
|
+
if (metadata = data['thread_metadata'])
|
|
208
|
+
@archived = metadata['archived']
|
|
209
|
+
@auto_archive_duration = metadata['auto_archive_duration']
|
|
210
|
+
@archive_timestamp = Time.iso8601(metadata['archive_timestamp'])
|
|
211
|
+
@locked = metadata['locked']
|
|
212
|
+
@invitable = metadata['invitable']
|
|
213
|
+
@create_timestamp = Time.iso8601(metadata['create_timestamp']) if metadata['create_timestamp']
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
if (member = data['member'])
|
|
217
|
+
@join_timestamp = Time.iso8601(member['join_timestamp'])
|
|
218
|
+
@member_flags = member['flags']
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
@flags = data['flags'] || 0
|
|
222
|
+
@voice_region = data['rtc_region']
|
|
223
|
+
@video_quality_mode = data['video_quality_mode']
|
|
224
|
+
@last_message_id = data['last_message_id']&.to_i
|
|
225
|
+
|
|
226
|
+
@default_auto_archive_duration = data['default_auto_archive_duration']
|
|
227
|
+
@default_sort_order = data['default_sort_order']
|
|
228
|
+
@default_forum_layout = data['default_forum_layout']
|
|
229
|
+
@default_thread_rate_limit_per_user = data['default_thread_rate_limit_per_user']
|
|
230
|
+
|
|
231
|
+
@applied_tags = data['applied_tags']&.map(&:to_i) || []
|
|
232
|
+
|
|
233
|
+
process_available_tags(data['available_tags'])
|
|
234
|
+
process_last_pin_timestamp(data['last_pin_timestamp'])
|
|
235
|
+
process_permission_overwrites(data['permission_overwrites'])
|
|
236
|
+
process_default_reaction_emoji(data['default_reaction_emoji'])
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# @return [Server, nil] the server this channel is on. If this channel is a PM channel, it will be nil.
|
|
240
|
+
# @raise [OnyxCord::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
|
|
241
|
+
# authorized with the `bot` scope.
|
|
242
|
+
def server
|
|
243
|
+
return @server if @server
|
|
244
|
+
return nil if private?
|
|
245
|
+
|
|
246
|
+
@server = @bot.server(@server_id)
|
|
247
|
+
raise OnyxCord::Errors::NoPermission, 'The bot does not have access to this server' unless @server
|
|
248
|
+
|
|
249
|
+
@server
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# @return [true, false] whether or not this channel is a text channel
|
|
253
|
+
def text?
|
|
254
|
+
@type.zero?
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# @return [true, false] whether or not this channel is a PM channel.
|
|
258
|
+
def pm?
|
|
259
|
+
@type == 1
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# @return [true, false] whether or not this channel is a voice channel.
|
|
263
|
+
def voice?
|
|
264
|
+
@type == 2
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# @return [true, false] whether or not this channel is a group channel.
|
|
268
|
+
def group?
|
|
269
|
+
@type == 3
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# @return [true, false] whether or not this channel is a category channel.
|
|
273
|
+
def category?
|
|
274
|
+
@type == 4
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# @return [true, false] whether or not this channel is a news channel.
|
|
278
|
+
def news?
|
|
279
|
+
@type == 5
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# @return [true, false] whether or not this channel is a store channel.
|
|
283
|
+
def store?
|
|
284
|
+
@type == 6
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# @return [true, false] whether or not this channel is a news thread.
|
|
288
|
+
def news_thread?
|
|
289
|
+
@type == 10
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# @return [true, false] whether or not this channel is a public thread.
|
|
293
|
+
def public_thread?
|
|
294
|
+
@type == 11
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# @return [true, false] whether or not this channel is a private thread.
|
|
298
|
+
def private_thread?
|
|
299
|
+
@type == 12
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# @return [true, false] whether or not this channel is a thread.
|
|
303
|
+
def thread?
|
|
304
|
+
news_thread? || public_thread? || private_thread?
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# @return [true, false] whether or not this channel is a stage channel.
|
|
308
|
+
def stage?
|
|
309
|
+
@type == 13
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# @return [true, false] whether or not this channel is a directory channel.
|
|
313
|
+
def directory?
|
|
314
|
+
@type == 14
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# @return [true, false] whether or not this channel is a forum channel.
|
|
318
|
+
def forum?
|
|
319
|
+
@type == 15
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# @return [true, false] whether or not this channel is a media channel.
|
|
323
|
+
def media?
|
|
324
|
+
@type == 16
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Check if this channel is a forum or media channel.
|
|
328
|
+
# @return [true, false] whether or not only threads can be created in this channel.
|
|
329
|
+
def thread_only?
|
|
330
|
+
forum? || media?
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# @return [Channel, nil] the category channel, if this channel is in a category
|
|
334
|
+
def category
|
|
335
|
+
@bot.channel(@parent_id) if @parent_id
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
alias_method :parent, :category
|
|
339
|
+
|
|
340
|
+
# Sets this channels parent category
|
|
341
|
+
# @param channel [Channel, String, Integer] the target category channel, or its ID
|
|
342
|
+
# @raise [ArgumentError] if the target channel isn't a category
|
|
343
|
+
def category=(channel)
|
|
344
|
+
channel = @bot.channel(channel)
|
|
345
|
+
raise ArgumentError, 'Cannot set parent category to a channel that isn\'t a category' unless channel.category?
|
|
346
|
+
|
|
347
|
+
modify(parent: channel)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
alias_method :parent=, :category=
|
|
351
|
+
|
|
352
|
+
# Sorts this channel's position to follow another channel.
|
|
353
|
+
# @param other [Channel, String, Integer, nil] The channel, or its ID, below which this channel should be sorted. If the given
|
|
354
|
+
# channel is a category, this channel will be sorted at the top of that category. If it is `nil`, the channel will
|
|
355
|
+
# be sorted at the top of the channel list.
|
|
356
|
+
# @param lock_permissions [true, false] Whether the channel's permissions should be synced to the category's
|
|
357
|
+
def sort_after(other = nil, lock_permissions = false)
|
|
358
|
+
raise TypeError, 'other must be one of Channel, NilClass, String, or Integer' unless other.is_a?(Channel) || other.nil? || other.respond_to?(:resolve_id)
|
|
359
|
+
|
|
360
|
+
other = @bot.channel(other.resolve_id) if other
|
|
361
|
+
|
|
362
|
+
# Container for the API request payload
|
|
363
|
+
move_argument = []
|
|
364
|
+
|
|
365
|
+
if other
|
|
366
|
+
raise ArgumentError, 'Can only sort a channel after a channel of the same type!' unless other.category? || (@type == other.type)
|
|
367
|
+
|
|
368
|
+
raise ArgumentError, 'Can only sort a channel after a channel in the same server!' unless other.server == server
|
|
369
|
+
|
|
370
|
+
# Store `others` parent (or if `other` is a category itself)
|
|
371
|
+
parent = if category? && other.category?
|
|
372
|
+
# If we're sorting two categories, there is no new parent
|
|
373
|
+
nil
|
|
374
|
+
elsif other.category?
|
|
375
|
+
# `other` is the category this channel will be moved into
|
|
376
|
+
other
|
|
377
|
+
else
|
|
378
|
+
# `other`'s parent is the category this channel will be
|
|
379
|
+
# moved into (if it exists)
|
|
380
|
+
other.parent
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Collect and sort the IDs within the context (category or not) that we
|
|
385
|
+
# need to form our payload with
|
|
386
|
+
ids = if parent
|
|
387
|
+
parent.children
|
|
388
|
+
else
|
|
389
|
+
server.channels.reject(&:parent_id).select { |c| c.type == @type }
|
|
390
|
+
end.sort_by(&:position).map(&:id)
|
|
391
|
+
|
|
392
|
+
# Move our channel ID after the target ID by deleting it,
|
|
393
|
+
# getting the index of `other`, and inserting it after.
|
|
394
|
+
ids.delete(@id) if ids.include?(@id)
|
|
395
|
+
index = other ? (ids.index { |c| c == other.id } || -1) + 1 : 0
|
|
396
|
+
ids.insert(index, @id)
|
|
397
|
+
|
|
398
|
+
# Generate `move_argument`, making the positions in order from how
|
|
399
|
+
# we have sorted them in the above logic
|
|
400
|
+
ids.each_with_index do |id, pos|
|
|
401
|
+
# These keys are present in each element
|
|
402
|
+
hash = { id: id, position: pos }
|
|
403
|
+
|
|
404
|
+
# Conditionally add `lock_permissions` and `parent_id` if we're
|
|
405
|
+
# iterating past ourselves
|
|
406
|
+
if id == @id
|
|
407
|
+
hash[:lock_permissions] = true if lock_permissions
|
|
408
|
+
hash[:parent_id] = parent.nil? ? nil : parent.id
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# Add it to the stack
|
|
412
|
+
move_argument << hash
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
API::Server.update_channel_positions(@bot.token, @server_id, move_argument)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Check if this channel is marked as NSFW.
|
|
419
|
+
# @return [true, false] Whether or not this channel is marked as NSFW.
|
|
420
|
+
def nsfw?
|
|
421
|
+
thread? ? parent.nsfw? : @nsfw
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Get the time at when this channel was created at.
|
|
425
|
+
# @return [Time, nil] The time at when the channel was created at.
|
|
426
|
+
def creation_time
|
|
427
|
+
return @create_timestamp if @create_timestamp
|
|
428
|
+
|
|
429
|
+
Time.at(((@id >> 22) + OnyxCord::DISCORD_EPOCH) / 1000.0)
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# Sets whether this channel is NSFW
|
|
433
|
+
# @param nsfw [true, false]
|
|
434
|
+
# @raise [ArgumentError] if value isn't one of true, false
|
|
435
|
+
def nsfw=(nsfw)
|
|
436
|
+
raise ArgumentError, 'nsfw value must be true or false' unless nsfw.is_a?(TrueClass) || nsfw.is_a?(FalseClass)
|
|
437
|
+
|
|
438
|
+
modify(nsfw: nsfw)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# This channel's permission overwrites
|
|
442
|
+
# @overload permission_overwrites
|
|
443
|
+
# The overwrites represented as a hash of role/user ID
|
|
444
|
+
# to an Overwrite object
|
|
445
|
+
# @return [Hash<Integer => Overwrite>] the channel's permission overwrites
|
|
446
|
+
# @overload permission_overwrites(type)
|
|
447
|
+
# Return an array of a certain type of overwrite
|
|
448
|
+
# @param type [Symbol] the kind of overwrite to return
|
|
449
|
+
# @return [Array<Overwrite>]
|
|
450
|
+
def permission_overwrites(type = nil)
|
|
451
|
+
return @permission_overwrites unless type
|
|
452
|
+
|
|
453
|
+
@permission_overwrites.values.select { |e| e.type == type }
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
alias_method :overwrites, :permission_overwrites
|
|
457
|
+
|
|
458
|
+
# Bulk sets this channels permission overwrites
|
|
459
|
+
# @param overwrites [Array<Overwrite>]
|
|
460
|
+
def permission_overwrites=(overwrites)
|
|
461
|
+
modify(permission_overwrites: overwrites)
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
# Sets the amount of time (in seconds) users have to wait in between sending messages.
|
|
465
|
+
# @param rate [Integer]
|
|
466
|
+
# @raise [ArgumentError] if value isn't between 0 and 21600
|
|
467
|
+
def rate_limit_per_user=(rate)
|
|
468
|
+
raise ArgumentError, 'rate_limit_per_user must be between 0 and 21600' unless rate.between?(0, 21_600)
|
|
469
|
+
|
|
470
|
+
modify(rate_limit_per_user: rate)
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
alias_method :slowmode_rate=, :rate_limit_per_user=
|
|
474
|
+
|
|
475
|
+
# Syncs this channels overwrites with its parent category
|
|
476
|
+
# @raise [RuntimeError] if this channel is not in a category
|
|
477
|
+
def sync_overwrites
|
|
478
|
+
raise 'Cannot sync overwrites on a channel with no parent category' unless parent
|
|
479
|
+
|
|
480
|
+
self.permission_overwrites = parent.permission_overwrites
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
alias_method :sync, :sync_overwrites
|
|
484
|
+
|
|
485
|
+
# @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
|
|
486
|
+
def synchronized?
|
|
487
|
+
return unless parent
|
|
488
|
+
|
|
489
|
+
permission_overwrites == parent.permission_overwrites
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
alias_method :synced?, :synchronized?
|
|
493
|
+
|
|
494
|
+
# Returns the children of this channel, if it is a category. Otherwise returns an empty array.
|
|
495
|
+
# @return [Array<Channel>]
|
|
496
|
+
def children
|
|
497
|
+
return [] unless category?
|
|
498
|
+
|
|
499
|
+
server.channels.select { |c| c.parent_id == id }
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
alias_method :channels, :children
|
|
503
|
+
|
|
504
|
+
# Returns the text channels in this category, if it is a category channel. Otherwise returns an empty array.
|
|
505
|
+
# @return [Array<Channel>]
|
|
506
|
+
def text_channels
|
|
507
|
+
children.select(&:text?)
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# Returns the voice channels in this category, if it is a category channel. Otherwise returns an empty array.
|
|
511
|
+
# @return [Array<Channel>]
|
|
512
|
+
def voice_channels
|
|
513
|
+
children.select(&:voice?)
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
# @return [Overwrite] any member-type permission overwrites on this channel
|
|
517
|
+
def member_overwrites
|
|
518
|
+
permission_overwrites :member
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
# @return [Overwrite] any role-type permission overwrites on this channel
|
|
522
|
+
def role_overwrites
|
|
523
|
+
permission_overwrites :role
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
# @return [true, false] whether or not this channel is the default channel
|
|
527
|
+
def default_channel?
|
|
528
|
+
server.default_channel == self
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
alias_method :default?, :default_channel?
|
|
532
|
+
|
|
533
|
+
# @return [true, false] whether or not this channel has slowmode enabled
|
|
534
|
+
def slowmode?
|
|
535
|
+
@rate_limit_per_user != 0
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
# Sends a message to this channel.
|
|
539
|
+
# @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
|
|
540
|
+
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
|
541
|
+
# @param embed [Hash, OnyxCord::Webhooks::Embed, nil] The rich embed to append to this message.
|
|
542
|
+
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
|
543
|
+
# @param allowed_mentions [Hash, OnyxCord::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
|
544
|
+
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
|
545
|
+
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
|
546
|
+
# @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
|
|
547
|
+
# @return [Message] the message that was sent.
|
|
548
|
+
def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0)
|
|
549
|
+
@bot.send_message(@id, content, tts, embed, attachments, allowed_mentions, message_reference, components, flags)
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
alias_method :send, :send_message
|
|
553
|
+
|
|
554
|
+
# Sends a temporary message to this channel.
|
|
555
|
+
# @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
|
|
556
|
+
# @param timeout [Float] The amount of time in seconds after which the message sent will be deleted.
|
|
557
|
+
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
|
558
|
+
# @param embed [Hash, OnyxCord::Webhooks::Embed, nil] The rich embed to append to this message.
|
|
559
|
+
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
|
560
|
+
# @param allowed_mentions [Hash, OnyxCord::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
|
561
|
+
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
|
562
|
+
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
|
563
|
+
# @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
|
|
564
|
+
def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0)
|
|
565
|
+
@bot.send_temporary_message(@id, content, timeout, tts, embed, attachments, allowed_mentions, message_reference, components, flags)
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
# Convenience method to send a message with an embed.
|
|
569
|
+
# @example Send a message with an embed
|
|
570
|
+
# channel.send_embed do |embed|
|
|
571
|
+
# embed.title = 'The Ruby logo'
|
|
572
|
+
# embed.image = OnyxCord::Webhooks::EmbedImage.new(url: 'https://www.ruby-lang.org/images/header-ruby-logo.png')
|
|
573
|
+
# end
|
|
574
|
+
# @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.
|
|
575
|
+
# @param embed [OnyxCord::Webhooks::Embed, nil] The embed to start the building process with, or nil if one should be created anew.
|
|
576
|
+
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
|
577
|
+
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
|
578
|
+
# @param allowed_mentions [Hash, OnyxCord::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
|
579
|
+
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
|
580
|
+
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
|
581
|
+
# @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
|
|
582
|
+
# @yield [embed] Yields the embed to allow for easy building inside a block.
|
|
583
|
+
# @yieldparam embed [OnyxCord::Webhooks::Embed] The embed from the parameters, or a new one.
|
|
584
|
+
# @return [Message] The resulting message.
|
|
585
|
+
def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0)
|
|
586
|
+
embed ||= OnyxCord::Webhooks::Embed.new
|
|
587
|
+
view = OnyxCord::Webhooks::View.new
|
|
588
|
+
|
|
589
|
+
yield(embed, view) if block_given?
|
|
590
|
+
|
|
591
|
+
send_message(message, tts, embed, attachments, allowed_mentions, message_reference, components || view.to_a, flags)
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
# Send a message to this channel.
|
|
595
|
+
# @example This sends a silent message with an embed.
|
|
596
|
+
# channel.send_message!(content: 'Hi <@171764626755813376>', flags: :suppress_notifications) do |builder|
|
|
597
|
+
# builder.add_embed do |embed|
|
|
598
|
+
# embed.title = 'The Ruby logo'
|
|
599
|
+
# embed.image = OnyxCord::Webhooks::EmbedImage.new(url: 'https://www.ruby-lang.org/images/header-ruby-logo.png')
|
|
600
|
+
# end
|
|
601
|
+
# end
|
|
602
|
+
# @param content [String] The content of the message. Should not be longer than 2000 characters or it will result in an error.
|
|
603
|
+
# @param timeout [Float, nil] The amount of time in seconds after which the message sent will be deleted, or `nil` if the message should not be deleted.
|
|
604
|
+
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
|
605
|
+
# @param embeds [Array<Hash, Webhooks::Embed>] The embeds that should be attached to the message.
|
|
606
|
+
# @param attachments [Array<File>] Files that can be referenced in embeds and components via `attachment://file.png`.
|
|
607
|
+
# @param allowed_mentions [Hash, OnyxCord::AllowedMentions, nil] Mentions that are allowed to ping on this message.
|
|
608
|
+
# @param reference [Message, String, Integer, Hash, nil] The optional message, or message ID, to reply to or forward.
|
|
609
|
+
# @param components [View, Array<#to_h>] Interaction components to associate with this message.
|
|
610
|
+
# @param flags [Integer, Symbol, Array<Symbol, Integer>] Flags for this message. Currently only `:suppress_embeds` (1 << 2), `:suppress_notifications` (1 << 12), and `:uikit_components` (1 << 15) can be set.
|
|
611
|
+
# @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables sending content, polls, and embeds.
|
|
612
|
+
# @param nonce [nil, String, Integer, false] The 25 character nonce that should be used when sending this message.
|
|
613
|
+
# @param enforce_nonce [true, false] Whether the provided nonce should be enforced and used for message de-duplication.
|
|
614
|
+
# @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to the message.
|
|
615
|
+
# @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the builder overwrite method data.
|
|
616
|
+
# @yieldparam view [Webhooks::View] An optional component builder. Arguments passed to the builder overwrite method data.
|
|
617
|
+
# @return [Message, nil] The resulting message that was created, or `nil` if the `timeout` parameter was set to a non `nil` value.
|
|
618
|
+
def send_message!(content: '', timeout: nil, tts: false, embeds: [], attachments: nil, allowed_mentions: nil, reference: nil, components: nil, flags: 0, has_components: false, components_v2: false, nonce: nil, enforce_nonce: false, poll: nil)
|
|
619
|
+
builder = OnyxCord::Webhooks::Builder.new
|
|
620
|
+
view = OnyxCord::Webhooks::View.new
|
|
621
|
+
|
|
622
|
+
builder.tts = tts
|
|
623
|
+
builder.poll = poll
|
|
624
|
+
builder.content = content
|
|
625
|
+
embeds&.each { |embed| builder << embed }
|
|
626
|
+
builder.allowed_mentions = allowed_mentions
|
|
627
|
+
|
|
628
|
+
yield(builder, view) if block_given?
|
|
629
|
+
|
|
630
|
+
components = components&.to_a || view.to_a
|
|
631
|
+
flags = Array(flags).map { |flag| OnyxCord::Message::FLAGS[flag] || flag }.reduce(0, &:|)
|
|
632
|
+
flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components, force: has_components || components_v2)
|
|
633
|
+
builder = builder.to_json_hash
|
|
634
|
+
|
|
635
|
+
if timeout
|
|
636
|
+
@bot.send_temporary_message(@id, builder[:content], timeout, builder[:tts], builder[:embeds], attachments, builder[:allowed_mentions], reference, components, flags, nonce, enforce_nonce, builder[:poll])
|
|
637
|
+
else
|
|
638
|
+
@bot.send_message(@id, builder[:content], builder[:tts], builder[:embeds], attachments, builder[:allowed_mentions], reference, components, flags, nonce, enforce_nonce, builder[:poll])
|
|
639
|
+
end
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
# Sends multiple messages to a channel
|
|
643
|
+
# @param content [Array<String>] The messages to send.
|
|
644
|
+
def send_multiple(content)
|
|
645
|
+
content.each { |text| send_message!(content: text) }
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
# Splits a message into chunks whose length is at most the Discord character limit, then sends them individually.
|
|
649
|
+
# Useful for sending long messages, but be wary of rate limits!
|
|
650
|
+
def split_send(content)
|
|
651
|
+
send_multiple(OnyxCord.split_message(content))
|
|
652
|
+
nil
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
# Sends a file to this channel. If it is an image, it will be embedded.
|
|
656
|
+
# @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)
|
|
657
|
+
# @param caption [string] The caption for the file.
|
|
658
|
+
# @param tts [true, false] Whether or not this file's caption should be sent using Discord text-to-speech.
|
|
659
|
+
# @param filename [String] Overrides the filename of the uploaded file
|
|
660
|
+
# @param spoiler [true, false] Whether or not this file should appear as a spoiler.
|
|
661
|
+
# @example Send a file from disk
|
|
662
|
+
# channel.send_file(File.open('rubytaco.png', 'r'))
|
|
663
|
+
def send_file(file, caption: nil, tts: false, filename: nil, spoiler: nil)
|
|
664
|
+
@bot.send_file(@id, file, caption: caption, tts: tts, filename: filename, spoiler: spoiler)
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
# Deletes a message on this channel. Mostly useful in case a message needs to be deleted when only the ID is known
|
|
668
|
+
# @param message [Message, String, Integer, String, Integer] The message, or its ID, that should be deleted.
|
|
669
|
+
def delete_message(message)
|
|
670
|
+
API::Channel.delete_message(@bot.token, @id, message.resolve_id)
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
# Permanently deletes this channel
|
|
674
|
+
# @param reason [String] The reason the for the channel deletion.
|
|
675
|
+
def delete(reason = nil)
|
|
676
|
+
API::Channel.delete(@bot.token, @id, reason)
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
# Sets this channel's name. The name must be alphanumeric with dashes, unless this is a voice channel (then there are no limitations)
|
|
680
|
+
# @param name [String] The new name.
|
|
681
|
+
def name=(name)
|
|
682
|
+
modify(name: name)
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
# Sets this channel's topic.
|
|
686
|
+
# @param topic [String] The new topic.
|
|
687
|
+
def topic=(topic)
|
|
688
|
+
raise 'Tried to set topic on voice channel' if voice?
|
|
689
|
+
|
|
690
|
+
modify(topic: topic)
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
# Sets this channel's bitrate.
|
|
694
|
+
# @param bitrate [Integer] The new bitrate (in bps). Number has to be between 8000-96000 (128000 for VIP servers)
|
|
695
|
+
def bitrate=(bitrate)
|
|
696
|
+
raise 'Tried to set bitrate on text channel' if text?
|
|
697
|
+
|
|
698
|
+
modify(bitrate: bitrate)
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
# Sets this channel's user limit.
|
|
702
|
+
# @param limit [Integer] The new user limit. `0` for unlimited, has to be a number between 0-99
|
|
703
|
+
def user_limit=(limit)
|
|
704
|
+
raise 'Tried to set user_limit on text channel' if text?
|
|
705
|
+
|
|
706
|
+
modify(user_limit: limit)
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
alias_method :limit=, :user_limit=
|
|
710
|
+
|
|
711
|
+
# Sets this channel's position in the list.
|
|
712
|
+
# @param position [Integer] The new position.
|
|
713
|
+
def position=(position)
|
|
714
|
+
modify(position: position)
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
# Defines a permission overwrite for this channel that sets the specified thing to the specified allow and deny
|
|
718
|
+
# permission sets, or change an existing one.
|
|
719
|
+
# @overload define_overwrite(overwrite)
|
|
720
|
+
# @param thing [Overwrite] an Overwrite object to apply to this channel
|
|
721
|
+
# @param reason [String] The reason the for defining the overwrite.
|
|
722
|
+
# @overload define_overwrite(thing, allow, deny)
|
|
723
|
+
# @param thing [User, Role] What to define an overwrite for.
|
|
724
|
+
# @param allow [#bits, Permissions, Integer] The permission sets that should receive an `allow` override (i.e. a
|
|
725
|
+
# green checkmark on Discord)
|
|
726
|
+
# @param deny [#bits, Permissions, Integer] The permission sets that should receive a `deny` override (i.e. a red
|
|
727
|
+
# cross on Discord)
|
|
728
|
+
# @param reason [String] The reason the for defining the overwrite.
|
|
729
|
+
# @example Define a permission overwrite for a user that can then mention everyone and use TTS, but not create any invites
|
|
730
|
+
# allow = OnyxCord::Permissions.new
|
|
731
|
+
# allow.can_mention_everyone = true
|
|
732
|
+
# allow.can_send_tts_messages = true
|
|
733
|
+
#
|
|
734
|
+
# deny = OnyxCord::Permissions.new
|
|
735
|
+
# deny.can_create_instant_invite = true
|
|
736
|
+
#
|
|
737
|
+
# channel.define_overwrite(user, allow, deny)
|
|
738
|
+
def define_overwrite(thing, allow = 0, deny = 0, reason: nil)
|
|
739
|
+
unless thing.is_a? Overwrite
|
|
740
|
+
allow_bits = allow.respond_to?(:bits) ? allow.bits : allow
|
|
741
|
+
deny_bits = deny.respond_to?(:bits) ? deny.bits : deny
|
|
742
|
+
|
|
743
|
+
thing = Overwrite.new(thing, allow: allow_bits, deny: deny_bits)
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
API::Channel.update_permission(@bot.token, @id, thing.id, thing.allow.bits, thing.deny.bits, thing.type, reason)
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
# Deletes a permission overwrite for this channel
|
|
750
|
+
# @param target [Member, User, Role, Profile, Recipient, String, Integer] What permission overwrite to delete
|
|
751
|
+
# @param reason [String] The reason the for the overwrite deletion.
|
|
752
|
+
def delete_overwrite(target, reason = nil)
|
|
753
|
+
raise 'Tried deleting a overwrite for an invalid target' unless target.respond_to?(:resolve_id)
|
|
754
|
+
|
|
755
|
+
API::Channel.delete_permission(@bot.token, @id, target.resolve_id, reason)
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
# The list of users currently in this channel. For a voice channel, it will return all the members currently
|
|
759
|
+
# in that channel. For a text channel, it will return all online members that have permission to read it.
|
|
760
|
+
# @return [Array<Member>] the users in this channel
|
|
761
|
+
def users
|
|
762
|
+
if text?
|
|
763
|
+
server.online_members(include_idle: true).select { |u| u.can_read_messages? self }
|
|
764
|
+
elsif voice?
|
|
765
|
+
server.voice_states.filter_map { |id, voice_state| server.member(id) if !voice_state.voice_channel.nil? && voice_state.voice_channel.id == @id }
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
# Retrieves some of this channel's message history.
|
|
770
|
+
# @param amount [Integer] How many messages to retrieve. This must be less than or equal to 100, if it is higher
|
|
771
|
+
# than 100 it will be treated as 100 on Discord's side.
|
|
772
|
+
# @param before_id [Integer] The ID of the most recent message the retrieval should start at, or nil if it should
|
|
773
|
+
# start at the current message.
|
|
774
|
+
# @param after_id [Integer] The ID of the oldest message the retrieval should start at, or nil if it should start
|
|
775
|
+
# as soon as possible with the specified amount.
|
|
776
|
+
# @param around_id [Integer] The ID of the message retrieval should start from, reading in both directions
|
|
777
|
+
# @example Count the number of messages in the last 50 messages that contain the letter 'e'.
|
|
778
|
+
# message_count = channel.history(50).count {|message| message.content.include? "e"}
|
|
779
|
+
# @example Get the last 10 messages before the provided message.
|
|
780
|
+
# last_ten_messages = channel.history(10, message.id)
|
|
781
|
+
# @return [Array<Message>] the retrieved messages.
|
|
782
|
+
def history(amount, before_id = nil, after_id = nil, around_id = nil)
|
|
783
|
+
logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
|
|
784
|
+
JSON.parse(logs).map { |message| Message.new(message, @bot) }
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
# Retrieves message history, but only message IDs for use with prune.
|
|
788
|
+
# @note For internal use only
|
|
789
|
+
# @!visibility private
|
|
790
|
+
def history_ids(amount, before_id = nil, after_id = nil, around_id = nil)
|
|
791
|
+
logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
|
|
792
|
+
JSON.parse(logs).map { |message| message['id'].to_i }
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
# Returns a single message from this channel's history by ID.
|
|
796
|
+
# @param message_id [Integer] The ID of the message to retrieve.
|
|
797
|
+
# @return [Message, nil] the retrieved message, or `nil` if it couldn't be found.
|
|
798
|
+
def load_message(message_id)
|
|
799
|
+
raise ArgumentError, 'message_id cannot be nil' if message_id.nil?
|
|
800
|
+
|
|
801
|
+
response = API::Channel.message(@bot.token, @id, message_id)
|
|
802
|
+
Message.new(JSON.parse(response), @bot)
|
|
803
|
+
rescue OnyxCord::Errors::UnknownMessage
|
|
804
|
+
nil
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
alias_method :message, :load_message
|
|
808
|
+
|
|
809
|
+
# Requests the pinned messages in a channel.
|
|
810
|
+
# @param limit [Integer, nil] the limit of how many pinned messages to retrieve. `nil` will return all the pinned messages.
|
|
811
|
+
# @return [Array<Message>] the messages pinned in the channel.
|
|
812
|
+
def pins(limit: 50)
|
|
813
|
+
get_pins = proc do |fetch_limit, before = nil|
|
|
814
|
+
resp = API::Channel.pinned_messages(@bot.token, @id, fetch_limit, before&.iso8601)
|
|
815
|
+
JSON.parse(resp)['items'].map { |pin| Message.new(pin['message'].merge({ 'pinned_at' => pin['pinned_at'] }), @bot) }
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
# Can be done without pagination.
|
|
819
|
+
return get_pins.call(limit) if limit && limit <= 50
|
|
820
|
+
|
|
821
|
+
paginator = Paginator.new(limit, :down) do |last_page|
|
|
822
|
+
if last_page && last_page.count < 50
|
|
823
|
+
[]
|
|
824
|
+
else
|
|
825
|
+
get_pins.call(50, last_page&.last&.pinned_at)
|
|
826
|
+
end
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
paginator.to_a
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
# Delete the last N messages on this channel.
|
|
833
|
+
# @param amount [Integer] The amount of message history to consider for pruning. Must be a value between 2 and 100 (Discord limitation)
|
|
834
|
+
# @param strict [true, false] Whether an error should be raised when a message is reached that is too old to be bulk
|
|
835
|
+
# deleted. If this is false only a warning message will be output to the console.
|
|
836
|
+
# @param reason [String, nil] The reason for pruning
|
|
837
|
+
# @raise [ArgumentError] if the amount of messages is not a value between 2 and 100
|
|
838
|
+
# @yield [message] Yields each message in this channels history for filtering the messages to delete
|
|
839
|
+
# @example Pruning messages from a specific user ID
|
|
840
|
+
# channel.prune(100) { |m| m.author.id == 83283213010599936 }
|
|
841
|
+
# @return [Integer] The amount of messages that were successfully deleted
|
|
842
|
+
def prune(amount, strict = false, reason = nil, &block)
|
|
843
|
+
raise ArgumentError, 'Can only delete between 1 and 100 messages!' unless amount.between?(1, 100)
|
|
844
|
+
|
|
845
|
+
messages =
|
|
846
|
+
if block
|
|
847
|
+
history(amount).select(&block).map(&:id)
|
|
848
|
+
else
|
|
849
|
+
history_ids(amount)
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
case messages.size
|
|
853
|
+
when 0
|
|
854
|
+
0
|
|
855
|
+
when 1
|
|
856
|
+
API::Channel.delete_message(@bot.token, @id, messages.first, reason)
|
|
857
|
+
1
|
|
858
|
+
else
|
|
859
|
+
bulk_delete(messages, strict, reason)
|
|
860
|
+
end
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
# Deletes a collection of messages
|
|
864
|
+
# @param messages [Array<Message, String, Integer>] the messages (or message IDs) to delete. Total must be an amount between 2 and 100 (Discord limitation)
|
|
865
|
+
# @param strict [true, false] Whether an error should be raised when a message is reached that is too old to be bulk
|
|
866
|
+
# deleted. If this is false only a warning message will be output to the console.
|
|
867
|
+
# @param reason [String, nil] The reason for deleting the messages
|
|
868
|
+
# @raise [ArgumentError] if the amount of messages is not a value between 2 and 100
|
|
869
|
+
# @return [Integer] The amount of messages that were successfully deleted
|
|
870
|
+
def delete_messages(messages, strict = false, reason = nil)
|
|
871
|
+
raise ArgumentError, 'Can only delete between 2 and 100 messages!' unless messages.count.between?(2, 100)
|
|
872
|
+
|
|
873
|
+
messages.map!(&:resolve_id)
|
|
874
|
+
bulk_delete(messages, strict, reason)
|
|
875
|
+
end
|
|
876
|
+
|
|
877
|
+
# Updates the cached permission overwrites
|
|
878
|
+
# @note For internal use only
|
|
879
|
+
# @!visibility private
|
|
880
|
+
def update_overwrites(overwrites)
|
|
881
|
+
@permission_overwrites = overwrites
|
|
882
|
+
end
|
|
883
|
+
|
|
884
|
+
# Add an {Await} for a message in this channel. This is identical in functionality to adding a
|
|
885
|
+
# {OnyxCord::Events::MessageEvent} await with the `in` attribute as this channel.
|
|
886
|
+
# @see Bot#add_await
|
|
887
|
+
# @deprecated Will be changed to blocking behavior in v4.0. Use {#await!} instead.
|
|
888
|
+
def await(key, attributes = {}, &block)
|
|
889
|
+
@bot.add_await(key, OnyxCord::Events::MessageEvent, { in: @id }.merge(attributes), &block)
|
|
890
|
+
end
|
|
891
|
+
|
|
892
|
+
# Add a blocking {Await} for a message in this channel. This is identical in functionality to adding a
|
|
893
|
+
# {OnyxCord::Events::MessageEvent} await with the `in` attribute as this channel.
|
|
894
|
+
# @see Bot#add_await!
|
|
895
|
+
def await!(attributes = {}, &block)
|
|
896
|
+
@bot.add_await!(OnyxCord::Events::MessageEvent, { in: @id }.merge(attributes), &block)
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
# Creates a new invite to this channel.
|
|
900
|
+
# @param max_age [Integer] How many seconds this invite should last.
|
|
901
|
+
# @param max_uses [Integer] How many times this invite should be able to be used.
|
|
902
|
+
# @param temporary [true, false] Whether membership should be temporary (kicked after going offline).
|
|
903
|
+
# @param unique [true, false] If true, Discord will always send a unique invite instead of possibly re-using a similar one
|
|
904
|
+
# @param reason [String] The reason the for the creation of this invite.
|
|
905
|
+
# @return [Invite] the created invite.
|
|
906
|
+
def make_invite(max_age = 0, max_uses = 0, temporary = false, unique = false, reason = nil)
|
|
907
|
+
response = API::Channel.create_invite(@bot.token, @id, max_age, max_uses, temporary, unique, reason)
|
|
908
|
+
Invite.new(JSON.parse(response), @bot)
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
alias_method :invite, :make_invite
|
|
912
|
+
|
|
913
|
+
# Starts typing, which displays the typing indicator on the client for five seconds.
|
|
914
|
+
# If you want to keep typing you'll have to resend this every five seconds. (An abstraction
|
|
915
|
+
# for this will eventually be coming)
|
|
916
|
+
# @example Send a typing indicator for the bot in a given channel.
|
|
917
|
+
# channel.start_typing()
|
|
918
|
+
def start_typing
|
|
919
|
+
API::Channel.start_typing(@bot.token, @id)
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
# Creates a webhook in this channel
|
|
923
|
+
# @param name [String] the default name of this webhook.
|
|
924
|
+
# @param avatar [String] the default avatar URL to give this webhook.
|
|
925
|
+
# @param reason [String] the reason for the webhook creation.
|
|
926
|
+
# @raise [ArgumentError] if the channel isn't a text channel in a server.
|
|
927
|
+
# @return [Webhook] the created webhook.
|
|
928
|
+
def create_webhook(name, avatar = nil, reason = nil)
|
|
929
|
+
raise ArgumentError, 'Tried to create a webhook in a non-server channel' unless server
|
|
930
|
+
|
|
931
|
+
response = API::Channel.create_webhook(@bot.token, @id, name, avatar, reason)
|
|
932
|
+
Webhook.new(JSON.parse(response), @bot)
|
|
933
|
+
end
|
|
934
|
+
|
|
935
|
+
# Requests a list of Webhooks on the channel.
|
|
936
|
+
# @return [Array<Webhook>] webhooks on the channel.
|
|
937
|
+
def webhooks
|
|
938
|
+
raise 'Tried to request webhooks from a non-server channel' unless server
|
|
939
|
+
|
|
940
|
+
webhooks = JSON.parse(API::Channel.webhooks(@bot.token, @id))
|
|
941
|
+
webhooks.map { |webhook_data| Webhook.new(webhook_data, @bot) }
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
# Requests a list of Invites to the channel.
|
|
945
|
+
# @return [Array<Invite>] invites to the channel.
|
|
946
|
+
def invites
|
|
947
|
+
raise 'Tried to request invites from a non-server channel' unless server
|
|
948
|
+
|
|
949
|
+
invites = JSON.parse(API::Channel.invites(@bot.token, @id))
|
|
950
|
+
invites.map { |invite_data| Invite.new(invite_data, @bot) }
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
# Follow the announcement (news) channel to send crossposted messages to a target channel.
|
|
954
|
+
# @param target [Channel, Integer, String] The target channel to send crossposted messages to.
|
|
955
|
+
# @param reason [String, nil] The audit log reason shown for the created webhook in the target channel.
|
|
956
|
+
# @return [Integer] the ID of the created webhook in the target channel.
|
|
957
|
+
def follow(target, reason: nil)
|
|
958
|
+
raise 'Cannot follow a non-announcement channel' unless news?
|
|
959
|
+
|
|
960
|
+
JSON.parse(API::Channel.follow_channel(@bot.token, @id, target.resolve_id, reason))['webhook_id'].to_i
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
# Returns the last message or forum post created in this channel.
|
|
964
|
+
# @return [Message, Channel, nil] the last message sent in this channel,
|
|
965
|
+
# the most recent forum post if this is a forum or media channel, or `nil`.
|
|
966
|
+
def last_message
|
|
967
|
+
return unless @last_message_id
|
|
968
|
+
|
|
969
|
+
if forum? || media?
|
|
970
|
+
@bot.channel(@last_message_id)
|
|
971
|
+
else
|
|
972
|
+
load_message(@last_message_id)
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
# Start a thread.
|
|
977
|
+
# @param name [String] The name of the thread.
|
|
978
|
+
# @param auto_archive_duration [60, 1440, 4320, 10080] How long before a thread is automatically
|
|
979
|
+
# archived.
|
|
980
|
+
# @param message [Message, Integer, String] The message to reference when starting this thread.
|
|
981
|
+
# @param type [Symbol, Integer] The type of thread to create. Can be a key from {TYPES} or the value.
|
|
982
|
+
# @return [Channel]
|
|
983
|
+
def start_thread(name, auto_archive_duration, message: nil, type: 11)
|
|
984
|
+
message_id = message&.id || message
|
|
985
|
+
type = TYPES[type] || type
|
|
986
|
+
|
|
987
|
+
data = if message
|
|
988
|
+
API::Channel.start_thread_with_message(@bot.token, @id, message_id, name, auto_archive_duration)
|
|
989
|
+
else
|
|
990
|
+
API::Channel.start_thread_without_message(@bot.token, @id, name, auto_archive_duration, type)
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
@bot.ensure_channel(JSON.parse(data))
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
# Start a thread in a forum or media channel.
|
|
997
|
+
# @param name [String] The name of the forum post to create.
|
|
998
|
+
# @param auto_archive_duration [Integer, nil] How long before the post is automatically archived.
|
|
999
|
+
# @param rate_limit_per_user [Integer, nil] The slowmode rate of the forum post to create.
|
|
1000
|
+
# @param tags [Array<#resolve_id>, nil] The tags of the forum channel to apply onto the forum post.
|
|
1001
|
+
# @param content [String, nil] The content of the forum post's starter message.
|
|
1002
|
+
# @param embeds [Array<Hash, Webhooks::Embed>, nil] The embeds that should be attached to the forum post's starter message.
|
|
1003
|
+
# @param allowed_mentions [Hash, OnyxCord::AllowedMentions, nil] Mentions that are allowed to ping on this forum post's starter message.
|
|
1004
|
+
# @param components [Webhooks::View, Array<#to_h>, nil] The interaction components to associate with this forum post's starter message.
|
|
1005
|
+
# @param stickers [Array<#resolve_id>, nil] The stickers to include in the forum post's starter message.
|
|
1006
|
+
# @param attachments [Array<File>, nil] Files that can be referenced in embeds and components via `attachment://file.png`.
|
|
1007
|
+
# @param flags [Integer, Symbol, Array<Symbol, Integer>, nil] The flags to set on the forum post's starter message. Currently only `:suppress_embeds` (1 << 2), `:suppress_notifications` (1 << 12), and `:uikit_components` (1 << 15) can be set.
|
|
1008
|
+
# @param has_components [true, false] Whether the starter message for this forum post includes any V2 components. Enabling this disables sending content and embeds.
|
|
1009
|
+
# @param reason [String, nil] The reason for creating this forum post.
|
|
1010
|
+
# @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the builder overwrite method data.
|
|
1011
|
+
# @yieldparam view [Webhooks::View] An optional component builder. Arguments passed to the builder overwrite method data.
|
|
1012
|
+
# @return [Message] the starter message of the forum post. The forum post that was created can be accessed via {Message#thread}.
|
|
1013
|
+
def start_forum_thread(name:, auto_archive_duration: nil, rate_limit_per_user: nil, tags: nil, content: nil, embeds: nil, allowed_mentions: nil, components: nil, stickers: nil, attachments: nil, flags: nil, has_components: false, components_v2: false, reason: nil)
|
|
1014
|
+
builder = OnyxCord::Webhooks::Builder.new
|
|
1015
|
+
view = OnyxCord::Webhooks::View.new
|
|
1016
|
+
|
|
1017
|
+
builder.content = content
|
|
1018
|
+
embeds&.each { |embed| builder << embed }
|
|
1019
|
+
builder.allowed_mentions = allowed_mentions
|
|
1020
|
+
|
|
1021
|
+
yield(builder, view) if block_given?
|
|
1022
|
+
|
|
1023
|
+
components = components&.to_a || view.to_a
|
|
1024
|
+
flags = Array(flags).map { |flag| OnyxCord::Message::FLAGS[flag] || flag }.reduce(0, &:|)
|
|
1025
|
+
flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components, force: has_components || components_v2)
|
|
1026
|
+
builder = builder.to_json_hash
|
|
1027
|
+
|
|
1028
|
+
message = { content: builder[:content], embeds: builder[:embeds], allowed_mentions: builder[:allowed_mentions], components: components, sticker_ids: stickers&.map(&:resolve_id), flags: flags }
|
|
1029
|
+
response = JSON.parse(API::Channel.start_thread_in_forum_or_media_channel(@bot.token, @id, name, message.compact, attachments, rate_limit_per_user, auto_archive_duration, tags&.map(&:resolve_id), reason))
|
|
1030
|
+
|
|
1031
|
+
Message.new(response['message'].merge!('channel_id' => response['id'], 'thread' => response), @bot)
|
|
1032
|
+
end
|
|
1033
|
+
|
|
1034
|
+
def default_reaction
|
|
1035
|
+
@default_reaction.is_a?(Integer) ? server.emojis[@default_reaction] : @default_reaction
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
# Get a tag in this forum or media channel.
|
|
1039
|
+
# @param id [String, Integer] The ID of the tag to find.
|
|
1040
|
+
# @return [ChannelTag, nil] The tag that was found or `nil` if it couldn't be found.
|
|
1041
|
+
def tag(id)
|
|
1042
|
+
id = id.resolve_id
|
|
1043
|
+
@available_tags.find { |tag| tag == id }
|
|
1044
|
+
end
|
|
1045
|
+
|
|
1046
|
+
# Check if a specific tag has been applied to this thread.
|
|
1047
|
+
# @param id [String, Integer, ChannelTag] The tag you want to check.
|
|
1048
|
+
# @return [true, false] Whether or not the thread has the tag applied.
|
|
1049
|
+
def tag?(id)
|
|
1050
|
+
@applied_tags.any?(id&.resolve_id)
|
|
1051
|
+
end
|
|
1052
|
+
|
|
1053
|
+
# Get the tags for this channel. If this channel is a thread channel,
|
|
1054
|
+
# then the tags that have been applied to the thread will be returned,
|
|
1055
|
+
# and if the channel is a forum or media channel, then the tags that can
|
|
1056
|
+
# be applied onto threads created in this channel will be returned instead.
|
|
1057
|
+
# @return [Array<ChannelTag>] The available or set channel tags for this channel.
|
|
1058
|
+
def tags
|
|
1059
|
+
return @available_tags if forum? || !thread_only?
|
|
1060
|
+
|
|
1061
|
+
@applied_tags.filter_map { |tag_id| parent&.tag(tag_id) }
|
|
1062
|
+
end
|
|
1063
|
+
|
|
1064
|
+
# Add one or more tags to this thread channel.
|
|
1065
|
+
# @param tags [Array, Integer, String, ChannelTag] The tags to add to the thread.
|
|
1066
|
+
def add_tags(tags, reason: nil)
|
|
1067
|
+
raise 'Cannot add tags to this channel' unless parent&.thread_only?
|
|
1068
|
+
|
|
1069
|
+
modify(tags: @applied_tags + Array(tags).map(&:resolve_id), reason: reason)
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
alias_method :add_tag, :add_tags
|
|
1073
|
+
|
|
1074
|
+
# Remove one or more tag from this thread channel.
|
|
1075
|
+
# @param tags [Array, Integer, String, ChannelTag] The tags to remove from the thread.
|
|
1076
|
+
def remove_tags(tags, reason: nil)
|
|
1077
|
+
raise 'Cannot remove tags from this channel' unless parent&.thread_only?
|
|
1078
|
+
|
|
1079
|
+
modify(tags: @applied_tags - Array(tags).map(&:resolve_id), reason: reason)
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
alias_method :remove_tag, :remove_tags
|
|
1083
|
+
|
|
1084
|
+
# Create a tag in this forum or media channel.
|
|
1085
|
+
# @param name [String] The 1-20 character name of the tag to create.
|
|
1086
|
+
# @param moderated [true, false] Whether or not the tag should be moderated.
|
|
1087
|
+
# @param emoji [Emoji, Integer, String, nil] An optional emoji to set for the tag.
|
|
1088
|
+
# @param reason [String, nil] The reason to show in the audit log for creating the tag.
|
|
1089
|
+
# @return [nil]
|
|
1090
|
+
def create_tag(name:, moderated:, emoji: nil, reason: nil)
|
|
1091
|
+
update_tags({ name:, moderated:, **Emoji.build_emoji_hash(emoji) }, reason) if thread_only?
|
|
1092
|
+
end
|
|
1093
|
+
|
|
1094
|
+
# @!group Threads
|
|
1095
|
+
|
|
1096
|
+
# Join this thread.
|
|
1097
|
+
def join_thread
|
|
1098
|
+
@bot.join_thread(@id)
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
# Leave this thread
|
|
1102
|
+
def leave_thread
|
|
1103
|
+
@bot.leave_thread(@id)
|
|
1104
|
+
end
|
|
1105
|
+
|
|
1106
|
+
# Members in the thread.
|
|
1107
|
+
def members
|
|
1108
|
+
@bot.thread_members[@id].collect { |id| @server_id ? @bot.member(@server_id, id) : @bot.user(id) }
|
|
1109
|
+
end
|
|
1110
|
+
|
|
1111
|
+
# Add a member to the thread
|
|
1112
|
+
# @param member [Member, Integer, String] The member, or ID of the member, to add to this thread.
|
|
1113
|
+
def add_member(member)
|
|
1114
|
+
@bot.add_thread_member(@id, member)
|
|
1115
|
+
end
|
|
1116
|
+
|
|
1117
|
+
# @param member [Member, Integer, String] The member, or ID of the member, to remove from a thread.
|
|
1118
|
+
def remove_member(member)
|
|
1119
|
+
@bot.remove_thread_member(@id, member)
|
|
1120
|
+
end
|
|
1121
|
+
|
|
1122
|
+
# @!endgroup
|
|
1123
|
+
|
|
1124
|
+
# Modify the properties of the channel.
|
|
1125
|
+
# @param name [String] The new 1-100 character name of the channel.
|
|
1126
|
+
# @param type [Integer, Symbol] The new type of the channel. You can only convert between text and announcement channels.
|
|
1127
|
+
# @param topic [String, nil] The 0-1024 character topic of the channel; 0-4096 characters for forum channels.
|
|
1128
|
+
# @param nsfw [true, false, nil] Whether or not the channel should be marked as age-restricted.
|
|
1129
|
+
# @param rate_limit_per_user [Integer, nil] The new slowmode-rate of the channel; between 0-21600 (in seconds).
|
|
1130
|
+
# @param bitrate [Integer, nil] The new bitrate of the voice or stage channel; minimum of 8000 (in bits).
|
|
1131
|
+
# @param user_limit [Integer, nil] The maximum number of users who can join the voice or stage channel; 0 for no limit.
|
|
1132
|
+
# @param permission_overwrites [Array<Overwrite, Hash, #to_hash>, nil] The new permission overwrites to set for the channel.
|
|
1133
|
+
# @param parent [Channel, Integer, String, nil] The new category channel to set, or `nil` to orphan the chnanel.
|
|
1134
|
+
# @param voice_region [VoiceRegion, String, nil] The new voice region to set for the voice or stage channel.
|
|
1135
|
+
# @param video_quality_mode [Symbol, Integer, nil] The new camera video quality mode to set for the voice or stage channel.
|
|
1136
|
+
# @param default_auto_archive_duration [Integer, nil] The default client-side duration before a thread is archived due to inactivity.
|
|
1137
|
+
# @param flags [Symbol, Integer, Array<Symbol, Integer>] The flags to set for the channel.
|
|
1138
|
+
# @param tags [Array<ChannelTag, #to_h, #resolve_id>] The tags to set on the thread channel, or the new tags that will be available in the forum channel.
|
|
1139
|
+
# @param default_reaction [Integer, String, Emoji, nil] The emoji to display on threads created in the forum channel.
|
|
1140
|
+
# @param default_sort_order [Integer, Symbol, nil] The default order used to order threads in the forum channel.
|
|
1141
|
+
# @param default_forum_layout [Integer, Symbol] The default layout type used to display threads in the forum channel.
|
|
1142
|
+
# @param archived [true, false] Whether or not the thread should be archived.
|
|
1143
|
+
# @param locked [true, false] Whether or not the thread should be locked.
|
|
1144
|
+
# @param invitable [true, false] Whether or not non-moderators should be able to add other non-moderators to the private thread.
|
|
1145
|
+
# @param add_flags [Symbol, Integer, Array<Symbol, Integer>] The flags to add to the channel. Mutually exclusive with `flags:`.
|
|
1146
|
+
# @param remove_flags [Symbol, Integer, Array<Symbol, Integer>] The flags to remove from the channel. Mutually exclusive with `flags:`.
|
|
1147
|
+
# @param position [Integer, nil] The new sorting position of the channel. Generally, this parameter should not be used. Please use {#sort_after} instead.
|
|
1148
|
+
# @param auto_archive_duration [Integer] The amount of minutes after which the thread will stop showing in the channel list.
|
|
1149
|
+
# @param default_thread_rate_limit_per_user [Integer] The default slowmode rate to set on threads created in the text or forum channel.
|
|
1150
|
+
# @param reason [String, nil] The reason to show in the server's audit log for modifying the channel.
|
|
1151
|
+
# @return [nil]
|
|
1152
|
+
def modify(
|
|
1153
|
+
name: :undef, type: :undef, topic: :undef, nsfw: :undef, rate_limit_per_user: :undef, bitrate: :undef,
|
|
1154
|
+
user_limit: :undef, permission_overwrites: :undef, parent: :undef, voice_region: :undef, video_quality_mode: :undef,
|
|
1155
|
+
default_auto_archive_duration: :undef, flags: :undef, tags: :undef, default_reaction: :undef, default_sort_order: :undef,
|
|
1156
|
+
default_forum_layout: :undef, archived: :undef, locked: :undef, invitable: :undef, add_flags: :undef, remove_flags: :undef,
|
|
1157
|
+
position: :undef, auto_archive_duration: :undef, default_thread_rate_limit_per_user: :undef, reason: nil
|
|
1158
|
+
)
|
|
1159
|
+
data = {
|
|
1160
|
+
name: name,
|
|
1161
|
+
type: TYPES[type] || type,
|
|
1162
|
+
topic: topic,
|
|
1163
|
+
nsfw: nsfw,
|
|
1164
|
+
position: position,
|
|
1165
|
+
rate_limit_per_user: rate_limit_per_user,
|
|
1166
|
+
bitrate: bitrate,
|
|
1167
|
+
user_limit: user_limit,
|
|
1168
|
+
permission_overwrites: permission_overwrites == :undef ? permission_overwrites : permission_overwrites&.map(&:to_hash),
|
|
1169
|
+
parent_id: parent == :undef ? parent : parent&.resolve_id,
|
|
1170
|
+
rtc_region: voice_region == :undef ? voice_region : voice_region&.to_s,
|
|
1171
|
+
video_quality_mode: VIDEO_QUALITY_MODES[video_quality_mode] || video_quality_mode,
|
|
1172
|
+
default_auto_archive_duration: default_auto_archive_duration,
|
|
1173
|
+
default_reaction_emoji: default_reaction == :undef ? default_reaction : Emoji.build_emoji_hash(default_reaction),
|
|
1174
|
+
default_sort_order: FORUM_SORT_ORDERS[default_sort_order] || default_sort_order,
|
|
1175
|
+
default_forum_layout: FORUM_LAYOUTS[default_forum_layout] || default_forum_layout,
|
|
1176
|
+
archived: archived,
|
|
1177
|
+
flags: flags == :undef ? flags : Array(flags).map { |bit| FLAGS[bit] || bit.to_i }.reduce(&:|),
|
|
1178
|
+
default_thread_rate_limit_per_user: default_thread_rate_limit_per_user,
|
|
1179
|
+
auto_archive_duration: auto_archive_duration,
|
|
1180
|
+
locked: locked,
|
|
1181
|
+
invitable: invitable
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
if tags != :undef && (thread_only? || thread?)
|
|
1185
|
+
tags = (thread? ? tags&.map(&:resolve_id) : tags&.map(&:to_h))
|
|
1186
|
+
|
|
1187
|
+
data[thread_only? ? :available_tags : :applied_tags] = tags
|
|
1188
|
+
end
|
|
1189
|
+
|
|
1190
|
+
if data[:type] != :undef
|
|
1191
|
+
if news? && data[:type] != TYPES[:text]
|
|
1192
|
+
raise ArgumentError, 'Can only convert news channels to text channels'
|
|
1193
|
+
elsif text? && data[:type] != TYPES[:news]
|
|
1194
|
+
raise ArgumentError, 'Can only convert text channels to news channels'
|
|
1195
|
+
elsif !text? && !news?
|
|
1196
|
+
raise ArgumentError, 'Can only convert between text and news channels'
|
|
1197
|
+
end
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
if add_flags != :undef || remove_flags != :undef
|
|
1201
|
+
raise ArgumentError, "'add_flags' and 'remove_flags' cannot be used with 'flags'" if flags != :undef
|
|
1202
|
+
|
|
1203
|
+
to_flags = lambda do |value|
|
|
1204
|
+
[*(value == :undef ? 0 : value)].map { |bit| FLAGS[bit] || bit.to_i }.reduce(&:|)
|
|
1205
|
+
end
|
|
1206
|
+
|
|
1207
|
+
data[:flags] = ((@flags & ~to_flags.call(remove_flags)) | to_flags.call(add_flags))
|
|
1208
|
+
end
|
|
1209
|
+
|
|
1210
|
+
update_data(JSON.parse(API::Channel.update!(@bot.token, @id, **data, reason: reason)))
|
|
1211
|
+
nil
|
|
1212
|
+
end
|
|
1213
|
+
|
|
1214
|
+
# The default `inspect` method is overwritten to give more useful output.
|
|
1215
|
+
def inspect
|
|
1216
|
+
"<Channel name=#{@name} id=#{@id} topic=\"#{@topic}\" type=#{@type} position=#{@position} server=#{@server || @server_id}>"
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
# Set the last pin timestamp of a channel.
|
|
1220
|
+
# @param time [String, nil] the time of the last pinned message in the channel
|
|
1221
|
+
# @note For internal use only
|
|
1222
|
+
# @!visibility private
|
|
1223
|
+
def process_last_pin_timestamp(time)
|
|
1224
|
+
@last_pin_timestamp = time ? Time.parse(time) : time
|
|
1225
|
+
end
|
|
1226
|
+
|
|
1227
|
+
# Set the last message ID of a channel.
|
|
1228
|
+
# @param id [Integer, nil] the ID of the last message in a channel
|
|
1229
|
+
# @note For internal use only
|
|
1230
|
+
# @!visibility private
|
|
1231
|
+
def process_last_message_id(id)
|
|
1232
|
+
@last_message_id = id
|
|
1233
|
+
end
|
|
1234
|
+
|
|
1235
|
+
# Set the available tags of a channel.
|
|
1236
|
+
# @param tag [Hash] the data for the tag to create
|
|
1237
|
+
# @param reason [String, nil] the reason to show in the audit log
|
|
1238
|
+
# @note For internal use only
|
|
1239
|
+
# @!visibility private
|
|
1240
|
+
def update_tags(tag, reason)
|
|
1241
|
+
raise 'Cannot execute action on channel' unless thread_only?
|
|
1242
|
+
|
|
1243
|
+
tags = @available_tags.dup.tap { |old| old.delete(tag[:id]) }
|
|
1244
|
+
|
|
1245
|
+
modify(tags: (tag[:d] ? tags : (tags << tag)), reason: reason)
|
|
1246
|
+
end
|
|
1247
|
+
|
|
1248
|
+
# Updates the cached data with new data
|
|
1249
|
+
# @note For internal use only
|
|
1250
|
+
# @!visibility private
|
|
1251
|
+
def update_data(new_data = nil)
|
|
1252
|
+
new_data ||= JSON.parse(API::Channel.resolve(@bot.token, @id))
|
|
1253
|
+
@type = new_data['type'] || 0
|
|
1254
|
+
@topic = new_data['topic']
|
|
1255
|
+
@bitrate = new_data['bitrate']
|
|
1256
|
+
@name = new_data['name'] || @name
|
|
1257
|
+
@user_limit = new_data['user_limit']
|
|
1258
|
+
|
|
1259
|
+
@position = new_data['position']
|
|
1260
|
+
@parent_id = new_data['parent_id']&.to_i
|
|
1261
|
+
@nsfw = new_data['nsfw'] || false
|
|
1262
|
+
@rate_limit_per_user = new_data['rate_limit_per_user'] || 0
|
|
1263
|
+
@message_count = new_data['message_count']
|
|
1264
|
+
@member_count = new_data['member_count']
|
|
1265
|
+
|
|
1266
|
+
@total_message_sent = new_data['total_message_sent'] || 0
|
|
1267
|
+
@flags = new_data['flags'] || 0
|
|
1268
|
+
@voice_region = new_data['rtc_region']
|
|
1269
|
+
@video_quality_mode = new_data['video_quality_mode']
|
|
1270
|
+
@last_message_id = new_data['last_message_id']&.to_i
|
|
1271
|
+
|
|
1272
|
+
@default_auto_archive_duration = new_data['default_auto_archive_duration']
|
|
1273
|
+
@default_sort_order = new_data['default_sort_order']
|
|
1274
|
+
@default_forum_layout = new_data['default_forum_layout']
|
|
1275
|
+
@default_thread_rate_limit_per_user = new_data['default_thread_rate_limit_per_user']
|
|
1276
|
+
|
|
1277
|
+
if (metadata = new_data['thread_metadata'])
|
|
1278
|
+
@archived = metadata['archived']
|
|
1279
|
+
@auto_archive_duration = metadata['auto_archive_duration']
|
|
1280
|
+
@archive_timestamp = Time.iso8601(metadata['archive_timestamp'])
|
|
1281
|
+
@locked = metadata['locked']
|
|
1282
|
+
@invitable = metadata['invitable']
|
|
1283
|
+
end
|
|
1284
|
+
|
|
1285
|
+
@applied_tags = new_data['applied_tags']&.map(&:to_i) || []
|
|
1286
|
+
|
|
1287
|
+
process_available_tags(new_data['available_tags'])
|
|
1288
|
+
process_last_pin_timestamp(new_data['last_pin_timestamp'])
|
|
1289
|
+
process_permission_overwrites(new_data['permission_overwrites'])
|
|
1290
|
+
process_default_reaction_emoji(new_data['default_reaction_emoji'])
|
|
1291
|
+
end
|
|
1292
|
+
|
|
1293
|
+
# @return [String] a URL that a user can use to navigate to this channel in the client
|
|
1294
|
+
def link
|
|
1295
|
+
"https://discord.com/channels/#{@server_id || '@me'}/#{@id}"
|
|
1296
|
+
end
|
|
1297
|
+
|
|
1298
|
+
alias_method :jump_link, :link
|
|
1299
|
+
|
|
1300
|
+
private
|
|
1301
|
+
|
|
1302
|
+
TWO_WEEKS = 86_400 * 14
|
|
1303
|
+
private_constant :TWO_WEEKS
|
|
1304
|
+
|
|
1305
|
+
# Deletes a list of messages on this channel using bulk delete.
|
|
1306
|
+
def bulk_delete(ids, strict = false, reason = nil)
|
|
1307
|
+
min_snowflake = IDObject.synthesise(Time.now - TWO_WEEKS)
|
|
1308
|
+
|
|
1309
|
+
ids.reject! do |e|
|
|
1310
|
+
next unless e < min_snowflake
|
|
1311
|
+
|
|
1312
|
+
message = "Attempted to bulk_delete message #{e} which is too old (min = #{min_snowflake})"
|
|
1313
|
+
raise ArgumentError, message if strict
|
|
1314
|
+
|
|
1315
|
+
OnyxCord::LOGGER.warn(message)
|
|
1316
|
+
true
|
|
1317
|
+
end
|
|
1318
|
+
|
|
1319
|
+
API::Channel.bulk_delete_messages(@bot.token, @id, ids, reason)
|
|
1320
|
+
ids.size
|
|
1321
|
+
end
|
|
1322
|
+
|
|
1323
|
+
# @!visibility private
|
|
1324
|
+
def process_permission_overwrites(overwrites)
|
|
1325
|
+
# Populate permission overwrites
|
|
1326
|
+
@permission_overwrites = {}
|
|
1327
|
+
|
|
1328
|
+
overwrites&.each do |element|
|
|
1329
|
+
id = element['id'].to_i
|
|
1330
|
+
@permission_overwrites[id] = Overwrite.from_hash(element)
|
|
1331
|
+
end
|
|
1332
|
+
end
|
|
1333
|
+
|
|
1334
|
+
# @!visibility private
|
|
1335
|
+
def process_available_tags(tags)
|
|
1336
|
+
# Populate available tags
|
|
1337
|
+
@available_tags = []
|
|
1338
|
+
|
|
1339
|
+
tags&.each do |element|
|
|
1340
|
+
@available_tags << ChannelTag.new(element, self, @bot)
|
|
1341
|
+
end
|
|
1342
|
+
end
|
|
1343
|
+
|
|
1344
|
+
# @!visibility private
|
|
1345
|
+
def process_default_reaction_emoji(emoji)
|
|
1346
|
+
return @default_reaction = nil unless emoji
|
|
1347
|
+
|
|
1348
|
+
@default_reaction = if (name = emoji['emoji_name'])
|
|
1349
|
+
Emoji.new({ 'name' => name }, @bot)
|
|
1350
|
+
else
|
|
1351
|
+
emoji['emoji_id']&.to_i
|
|
1352
|
+
end
|
|
1353
|
+
end
|
|
1354
|
+
end
|
|
1355
|
+
end
|