discorb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +56 -0
  3. data/.yardopts +6 -0
  4. data/Changelog.md +5 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +70 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +53 -0
  9. data/Rakefile +46 -0
  10. data/bin/console +15 -0
  11. data/bin/setup +8 -0
  12. data/discorb.gemspec +37 -0
  13. data/docs/Examples.md +26 -0
  14. data/docs/events.md +480 -0
  15. data/docs/voice_events.md +283 -0
  16. data/examples/components/authorization_button.rb +43 -0
  17. data/examples/components/select_menu.rb +61 -0
  18. data/examples/extension/main.rb +12 -0
  19. data/examples/extension/message_expander.rb +41 -0
  20. data/examples/simple/eval.rb +32 -0
  21. data/examples/simple/ping_pong.rb +16 -0
  22. data/examples/simple/rolepanel.rb +65 -0
  23. data/examples/simple/wait_for_message.rb +30 -0
  24. data/lib/discorb/application.rb +157 -0
  25. data/lib/discorb/asset.rb +57 -0
  26. data/lib/discorb/audit_logs.rb +323 -0
  27. data/lib/discorb/channel.rb +1101 -0
  28. data/lib/discorb/client.rb +363 -0
  29. data/lib/discorb/color.rb +173 -0
  30. data/lib/discorb/common.rb +123 -0
  31. data/lib/discorb/components.rb +290 -0
  32. data/lib/discorb/dictionary.rb +119 -0
  33. data/lib/discorb/embed.rb +345 -0
  34. data/lib/discorb/emoji.rb +218 -0
  35. data/lib/discorb/emoji_table.rb +3799 -0
  36. data/lib/discorb/error.rb +98 -0
  37. data/lib/discorb/event.rb +35 -0
  38. data/lib/discorb/extend.rb +18 -0
  39. data/lib/discorb/extension.rb +54 -0
  40. data/lib/discorb/file.rb +69 -0
  41. data/lib/discorb/flag.rb +109 -0
  42. data/lib/discorb/gateway.rb +967 -0
  43. data/lib/discorb/gateway_requests.rb +47 -0
  44. data/lib/discorb/guild.rb +1244 -0
  45. data/lib/discorb/guild_template.rb +211 -0
  46. data/lib/discorb/image.rb +43 -0
  47. data/lib/discorb/integration.rb +111 -0
  48. data/lib/discorb/intents.rb +137 -0
  49. data/lib/discorb/interaction.rb +333 -0
  50. data/lib/discorb/internet.rb +285 -0
  51. data/lib/discorb/invite.rb +145 -0
  52. data/lib/discorb/log.rb +70 -0
  53. data/lib/discorb/member.rb +232 -0
  54. data/lib/discorb/message.rb +583 -0
  55. data/lib/discorb/modules.rb +138 -0
  56. data/lib/discorb/permission.rb +270 -0
  57. data/lib/discorb/presence.rb +308 -0
  58. data/lib/discorb/reaction.rb +48 -0
  59. data/lib/discorb/role.rb +189 -0
  60. data/lib/discorb/sticker.rb +157 -0
  61. data/lib/discorb/user.rb +163 -0
  62. data/lib/discorb/utils.rb +16 -0
  63. data/lib/discorb/voice_state.rb +251 -0
  64. data/lib/discorb/webhook.rb +420 -0
  65. data/lib/discorb.rb +51 -0
  66. metadata +120 -0
@@ -0,0 +1,1101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "async"
4
+
5
+ module Discorb
6
+ #
7
+ # Represents a channel of Discord.
8
+ # @abstract
9
+ #
10
+ class Channel < DiscordModel
11
+ # @return [Discorb::Snowflake] The ID of the channel.
12
+ attr_reader :id
13
+ # @return [String] The name of the channel.
14
+ attr_reader :name
15
+
16
+ # @!attribute [r] type
17
+ # @return [Integer] The type of the channel as integer.
18
+
19
+ @channel_type = nil
20
+ @subclasses = []
21
+
22
+ # @!visibility private
23
+ def initialize(client, data, no_cache: false)
24
+ @client = client
25
+ @data = {}
26
+ @no_cache = no_cache
27
+ _set_data(data)
28
+ end
29
+
30
+ #
31
+ # Checks if the channel is other channel.
32
+ #
33
+ # @param [Discorb::Channel] other The channel to check.
34
+ #
35
+ # @return [Boolean] True if the channel is other channel.
36
+ #
37
+ def ==(other)
38
+ return false unless other.respond_to?(:id)
39
+
40
+ @id == other.id
41
+ end
42
+
43
+ def inspect
44
+ "#<#{self.class} \"##{@name}\" id=#{@id}>"
45
+ end
46
+
47
+ # @!visibility private
48
+ def self.descendants
49
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
50
+ end
51
+
52
+ # @!visibility private
53
+ def self.make_channel(client, data, no_cache: false)
54
+ descendants.each do |klass|
55
+ return klass.new(client, data, no_cache: no_cache) if !klass.channel_type.nil? && klass.channel_type == data[:type]
56
+ end
57
+ client.log.warn("Unknown channel type #{data[:type]}, initialized GuildChannel")
58
+ GuildChannel.new(client, data)
59
+ end
60
+
61
+ class << self
62
+ # @!visibility private
63
+ attr_reader :channel_type
64
+ end
65
+
66
+ def type
67
+ self.class.channel_type
68
+ end
69
+
70
+ # @!visibility private
71
+ def base_url
72
+ Async do
73
+ "/channels/#{@id}"
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def _set_data(data)
80
+ @id = Snowflake.new(data[:id])
81
+ @name = data[:name]
82
+ @client.channels[@id] = self if !@no_cache && !(data[:no_cache])
83
+ @data.update(data)
84
+ end
85
+ end
86
+
87
+ #
88
+ # Represents a channel in guild.
89
+ # @abstract
90
+ #
91
+ class GuildChannel < Channel
92
+ # @return [Integer] The position of the channel as integer.
93
+ attr_reader :position
94
+ # @return [Hash{Discorb::Role, Discorb::Member => PermissionOverwrite}] The permission overwrites of the channel.
95
+ attr_reader :permission_overwrites
96
+
97
+ # @!attribute [r] mention
98
+ # @return [String] The mention of the channel.
99
+ #
100
+ # @!attribute [r] parent
101
+ # @macro client_cache
102
+ # @return [Discorb::CategoryChannel] The parent of channel.
103
+ # @return [nil] If the channel is not a child of category.
104
+ #
105
+ # @!attribute [r] guild
106
+ # @return [Discorb::Guild] The guild of channel.
107
+ # @macro client_cache
108
+
109
+ include Comparable
110
+ @channel_type = nil
111
+
112
+ #
113
+ # Compares position of two channels.
114
+ #
115
+ # @param [Discorb::GuildChannel] other The channel to compare.
116
+ #
117
+ # @return [-1, 1] -1 if the channel is at lower than the other, 1 if the channel is at highter than the other.
118
+ #
119
+ def <=>(other)
120
+ return 0 unless other.respond_to?(:position)
121
+
122
+ @position <=> other.position
123
+ end
124
+
125
+ #
126
+ # Checks if the channel is same as another.
127
+ #
128
+ # @param [Discorb::GuildChannel] other The channel to check.
129
+ #
130
+ # @return [Boolean] `true` if the channel is same as another.
131
+ #
132
+ def ==(other)
133
+ return false unless other.respond_to?(:id)
134
+
135
+ @id == other.id
136
+ end
137
+
138
+ #
139
+ # Stringifies the channel.
140
+ #
141
+ # @return [String] The name of the channel with `#`.
142
+ #
143
+ def to_s
144
+ "##{@name}"
145
+ end
146
+
147
+ def mention
148
+ "<##{@id}>"
149
+ end
150
+
151
+ def parent
152
+ return nil unless @parent_id
153
+
154
+ @client.channels[@parent_id]
155
+ end
156
+
157
+ alias category parent
158
+
159
+ def guild
160
+ @client.guilds[@guild_id]
161
+ end
162
+
163
+ def inspect
164
+ "#<#{self.class} \"##{@name}\" id=#{@id}>"
165
+ end
166
+
167
+ #
168
+ # Deletes the channel.
169
+ # @macro async
170
+ # @macro http
171
+ #
172
+ # @param [String] reason The reason of deleting the channel.
173
+ #
174
+ # @return [self] The deleted channel.
175
+ #
176
+ def delete!(reason: nil)
177
+ Async do
178
+ @client.internet.delete(base_url.wait.to_s, audit_log_reason: reason).wait
179
+ @deleted = true
180
+ self
181
+ end
182
+ end
183
+
184
+ alias close! delete!
185
+ alias destroy! delete!
186
+
187
+ #
188
+ # Moves the channel to another position.
189
+ # @macro async
190
+ # @macro http
191
+ #
192
+ # @param [Integer] position The position to move the channel.
193
+ # @param [Boolean] lock_permissions Whether to lock the permissions of the channel.
194
+ # @param [Discorb::CategoryChannel] parent The parent of channel.
195
+ # @param [String] reason The reason of moving the channel.
196
+ #
197
+ # @return [self] The moved channel.
198
+ #
199
+ def move(position, lock_permissions: false, parent: :unset, reason: nil)
200
+ Async do
201
+ payload = {
202
+ position: position,
203
+ }
204
+ payload[:lock_permissions] = lock_permissions
205
+ payload[:parent_id] = parent&.id if parent != :unset
206
+ @client.internet.patch("/guilds/#{@guild_id}/channels", payload, audit_log_reason: reason).wait
207
+ end
208
+ end
209
+
210
+ private
211
+
212
+ def _set_data(data)
213
+ @guild_id = data[:guild_id]
214
+ @position = data[:position]
215
+ @permission_overwrites = if data[:permission_overwrites]
216
+ data[:permission_overwrites].map do |ow|
217
+ [(ow[:type] == 1 ? guild.roles : guild.members)[ow[:id]], PermissionOverwrite.new(ow[:allow], ow[:deny])]
218
+ end.to_h
219
+ else
220
+ {}
221
+ end
222
+ @parent_id = data[:parent_id]
223
+
224
+ super
225
+ end
226
+ end
227
+
228
+ #
229
+ # Represents a text channel.
230
+ #
231
+ class TextChannel < GuildChannel
232
+ # @return [String] The topic of the channel.
233
+ attr_reader :topic
234
+ # @return [Boolean] Whether the channel is nsfw.
235
+ attr_reader :nsfw
236
+ # @return [Discorb::Snowflake] The id of the last message.
237
+ attr_reader :last_message_id
238
+ # @return [Integer] The rate limit per user (Slowmode) in the channel.
239
+ attr_reader :rate_limit_per_user
240
+ alias slowmode rate_limit_per_user
241
+ # @return [Time] The time when the last pinned message was pinned.
242
+ attr_reader :last_pin_timestamp
243
+ alias last_pinned_at last_pin_timestamp
244
+ # @return [Array<Discorb::ThreadChannel>] The threads in the channel.
245
+ attr_reader :threads
246
+
247
+ include Messageable
248
+
249
+ @channel_type = 0
250
+
251
+ # @!visibility private
252
+ def initialize(client, data, no_cache: false)
253
+ super
254
+ @threads = Dictionary.new
255
+ end
256
+
257
+ #
258
+ # Edits the channel.
259
+ # @macro async
260
+ # @macro http
261
+ # @macro edit
262
+ #
263
+ # @param [String] name The name of the channel.
264
+ # @param [Integer] position The position of the channel.
265
+ # @param [Discorb::CategoryChannel, nil] category The parent of channel. Specify `nil` to remove the parent.
266
+ # @param [Discorb::CategoryChannel, nil] parent Alias of `category`.
267
+ # @param [String] topic The topic of the channel.
268
+ # @param [Boolean] nsfw Whether the channel is nsfw.
269
+ # @param [Boolean] announce Whether the channel is announce channel.
270
+ # @param [Integer] rate_limit_per_user The rate limit per user (Slowmode) in the channel.
271
+ # @param [Integer] slowmode Alias of `rate_limit_per_user`.
272
+ # @param [Integer] default_auto_archive_duration The default auto archive duration of the channel.
273
+ # @param [Integer] archive_in Alias of `default_auto_archive_duration`.
274
+ # @param [String] reason The reason of editing the channel.
275
+ #
276
+ # @return [self] The edited channel.
277
+ #
278
+ def edit(name: :unset, position: :unset, category: :unset, parent: :unset,
279
+ topic: :unset, nsfw: :unset, announce: :unset,
280
+ rate_limit_per_user: :unset, slowmode: :unset, default_auto_archive_duration: :unset,
281
+ archive_in: :unset, reason: nil)
282
+ Async do
283
+ payload = {}
284
+ payload[:name] = name if name != :unset
285
+ payload[:announce] = announce ? 5 : 0 if announce != :unset
286
+ payload[:position] = position if position != :unset
287
+ payload[:topic] = topic || "" if topic != :unset
288
+ payload[:nsfw] = nsfw if nsfw != :unset
289
+
290
+ slowmode = rate_limit_per_user if slowmode == :unset
291
+ payload[:rate_limit_per_user] = slowmode || 0 if slowmode != :unset
292
+ parent = category if parent == :unset
293
+ payload[:parent_id] = parent&.id if parent != :unset
294
+
295
+ default_auto_archive_duration ||= archive_in
296
+ payload[:default_auto_archive_duration] = default_auto_archive_duration if default_auto_archive_duration != :unset
297
+
298
+ @client.internet.patch("/channels/#{@id}", payload, audit_log_reason: reason).wait
299
+ self
300
+ end
301
+ end
302
+
303
+ alias modify edit
304
+
305
+ #
306
+ # Create webhook in the channel.
307
+ # @macro async
308
+ # @macro http
309
+ #
310
+ # @param [String] name The name of the webhook.
311
+ # @param [Discorb::Image] avatar The avatar of the webhook.
312
+ #
313
+ # @return [Discorb::Webhook::IncomingWebhook] The created webhook.
314
+ #
315
+ def create_webhook(name, avatar: nil)
316
+ Async do
317
+ payload = {}
318
+ payload[:name] = name
319
+ payload[:avatar] = avatar.to_s if avatar
320
+ _resp, data = @client.internet.post("/channels/#{@id}/webhooks", payload).wait
321
+ Webhook.new([@client, data])
322
+ end
323
+ end
324
+
325
+ #
326
+ # Fetch webhooks in the channel.
327
+ # @macro async
328
+ # @macro http
329
+ #
330
+ # @return [Array<Discorb::Webhook>] The webhooks in the channel.
331
+ #
332
+ def fetch_webhooks
333
+ Async do
334
+ _resp, data = @client.internet.get("/channels/#{@id}/webhooks").wait
335
+ data.map { |webhook| Webhook.new([@client, webhook]) }
336
+ end
337
+ end
338
+
339
+ #
340
+ # Bulk delete messages in the channel.
341
+ # @macro async
342
+ # @macro http
343
+ #
344
+ # @param [Discorb::Message] messages The messages to delete.
345
+ # @param [Boolean] force Whether to ignore the validation for message (14 days limit).
346
+ #
347
+ def delete_messages!(*messages, force: false)
348
+ Async do
349
+ messages = messages.first if messages.length == 1 && messages.first.is_a?(Array)
350
+ unless force
351
+ time = Time.now
352
+ messages.delete_if do |message|
353
+ next false unless message.is_a?(Message)
354
+
355
+ time - message.created_at > 60 * 60 * 24 * 14
356
+ end
357
+ end
358
+
359
+ message_ids = messages.map { |m| Discorb::Utils.try(m, :id).to_s }
360
+
361
+ @client.internet.post("/channels/#{@id}/messages/bulk-delete", { messages: message_ids }).wait
362
+ end
363
+ end
364
+
365
+ alias bulk_delete! delete_messages!
366
+ alias destroy_messages! delete_messages!
367
+
368
+ #
369
+ # Set the channel's permission overwrite.
370
+ # @macro async
371
+ # @macro http
372
+ #
373
+ # @param [Discorb::Role, Discorb::Member] target The target of the overwrite.
374
+ # @param [String] reason The reason of setting the overwrite.
375
+ # @param [Symbol => Boolean] perms The permission overwrites to replace.
376
+ #
377
+ def set_permissions(target, reason: nil, **perms)
378
+ Async do
379
+ allow_value = @permission_overwrites[target]&.allow_value.to_i
380
+ deny_value = @permission_overwrites[target]&.deny_value.to_i
381
+ perms.each do |perm, value|
382
+ allow_value[Discorb::Permission.bits[perm]] = 1 if value == true
383
+ deny_value[Discorb::Permission.bits[perm]] = 1 if value == false
384
+ end
385
+ payload = {
386
+ allow: allow_value,
387
+ deny: deny_value,
388
+ type: target.is_a?(Member) ? 1 : 0,
389
+ }
390
+ @client.internet.put("/channels/#{@id}/permissions/#{target.id}", payload, audit_log_reason: reason).wait
391
+ end
392
+ end
393
+
394
+ alias modify_permissions set_permissions
395
+ alias modify_permisssion set_permissions
396
+ alias edit_permissions set_permissions
397
+ alias edit_permission set_permissions
398
+
399
+ #
400
+ # Delete the channel's permission overwrite.
401
+ # @macro async
402
+ # @macro http
403
+ #
404
+ # @param [Discorb::Role, Discorb::Member] target The target of the overwrite.
405
+ # @param [String] reason The reason of deleting the overwrite.
406
+ #
407
+ def delete_permissions(target, reason: nil)
408
+ Async do
409
+ @client.internet.delete("/channels/#{@id}/permissions/#{target.id}", audit_log_reason: reason).wait
410
+ end
411
+ end
412
+
413
+ alias delete_permission delete_permissions
414
+ alias destroy_permissions delete_permissions
415
+ alias destroy_permission delete_permissions
416
+
417
+ #
418
+ # Fetch the channel's invites.
419
+ # @macro async
420
+ # @macro http
421
+ #
422
+ # @return [Array<Discorb::Invite>] The invites in the channel.
423
+ #
424
+ def fetch_invites
425
+ Async do
426
+ _resp, data = @client.internet.get("/channels/#{@id}/invites").wait
427
+ data.map { |invite| Invite.new(@client, invite) }
428
+ end
429
+ end
430
+
431
+ #
432
+ # Create an invite in the channel.
433
+ # @macro async
434
+ # @macro http
435
+ #
436
+ # @param [Integer] max_age The max age of the invite.
437
+ # @param [Integer] max_uses The max uses of the invite.
438
+ # @param [Boolean] temporary Whether the invite is temporary.
439
+ # @param [Boolean] unique Whether the invite is unique.
440
+ # @note if it's `false` it may return existing invite.
441
+ # @param [String] reason The reason of creating the invite.
442
+ #
443
+ # @return [Invite] The created invite.
444
+ #
445
+ def create_invite(max_age: nil, max_uses: nil, temporary: false, unique: false, reason: nil)
446
+ Async do
447
+ _resp, data = @client.internet.post("/channels/#{@id}/invites", {
448
+ max_age: max_age,
449
+ max_uses: max_uses,
450
+ temporary: temporary,
451
+ unique: unique,
452
+ }, audit_log_reason: reason).wait
453
+ Invite.new(@client, data)
454
+ end
455
+ end
456
+
457
+ #
458
+ # Follow the existing announcement channel.
459
+ # @macro async
460
+ # @macro http
461
+ #
462
+ # @param [Discorb::NewsChannel] target The channel to follow.
463
+ # @param [String] reason The reason of following the channel.
464
+ #
465
+ def follow_from(target, reason: nil)
466
+ Async do
467
+ @client.internet.post("/channels/#{target.id}/followers", { webhook_channel_id: @id }, audit_log_reason: reason).wait
468
+ end
469
+ end
470
+
471
+ #
472
+ # Follow the existing announcement channel from self.
473
+ # @macro async
474
+ # @macro http
475
+ #
476
+ # @param [Discorb::TextChannel] target The channel to follow to.
477
+ # @param [String] reason The reason of following the channel.
478
+ #
479
+ def follow_to(target, reason: nil)
480
+ Async do
481
+ @client.internet.post("/channels/#{@id}/followers", { webhook_channel_id: target.id }, audit_log_reason: reason).wait
482
+ end
483
+ end
484
+
485
+ #
486
+ # Fetch the pinned messages in the channel.
487
+ # @macro async
488
+ # @macro http
489
+ #
490
+ # @return [Array<Discorb::Message>] The pinned messages in the channel.
491
+ #
492
+ def fetch_pins
493
+ Async do
494
+ _resp, data = @client.internet.get("/channels/#{@id}/pins").wait
495
+ data.map { |pin| Message.new(@client, pin) }
496
+ end
497
+ end
498
+
499
+ #
500
+ # Pin a message in the channel.
501
+ # @macro async
502
+ # @macro http
503
+ #
504
+ # @param [Discorb::Message] message The message to pin.
505
+ # @param [String] reason The reason of pinning the message.
506
+ #
507
+ def pin_message(message, reason: nil)
508
+ Async do
509
+ @client.internet.put("/channels/#{@id}/pins/#{message.id}", {}, audit_log_reason: reason).wait
510
+ end
511
+ end
512
+
513
+ #
514
+ # Unpin a message in the channel.
515
+ # @macro async
516
+ # @macro http
517
+ #
518
+ # @param [Discorb::Message] message The message to unpin.
519
+ # @param [String] reason The reason of unpinning the message.
520
+ #
521
+ def unpin_message(message, reason: nil)
522
+ Async do
523
+ @client.internet.delete("/channels/#{@id}/pins/#{message.id}", {}, audit_log_reason: reason).wait
524
+ end
525
+ end
526
+
527
+ #
528
+ # Start thread in the channel.
529
+ # @macro async
530
+ # @macro http
531
+ #
532
+ # @param [String] name The name of the thread.
533
+ # @param [Discorb::Message] message The message to start the thread.
534
+ # @param [Integer] auto_archive_duration The duration of auto-archiving.
535
+ # @param [Boolean] public Whether the thread is public.
536
+ # @param [String] reason The reason of starting the thread.
537
+ #
538
+ # @return [Discorb::ThreadChannel] The started thread.
539
+ #
540
+ def start_thread(name, message: nil, auto_archive_duration: 1440, public: true, reason: nil)
541
+ Async do
542
+ _resp, data = if message.nil?
543
+ @client.internet.post("/channels/#{@id}/threads", {
544
+ name: name, auto_archive_duration: auto_archive_duration, type: public ? 11 : 10,
545
+ },
546
+ audit_log_reason: reason).wait
547
+ else
548
+ @client.internet.post("/channels/#{@id}/messages/#{Utils.try(message, :id)}/threads", {
549
+ name: name, auto_archive_duration: auto_archive_duration,
550
+ }, audit_log_reason: reason).wait
551
+ end
552
+ Channel.make_channel(@client, data)
553
+ end
554
+ end
555
+
556
+ alias create_thread start_thread
557
+
558
+ #
559
+ # Fetch archived threads in the channel.
560
+ # @macro async
561
+ # @macro http
562
+ #
563
+ # @return [Array<Discorb::ThreadChannel>] The archived threads in the channel.
564
+ #
565
+ def fetch_archived_public_threads
566
+ Async do
567
+ _resp, data = @client.internet.get("/channels/#{@id}/threads/archived/public").wait
568
+ data.map { |thread| Channel.make_channel(@client, thread) }
569
+ end
570
+ end
571
+
572
+ #
573
+ # Fetch archived private threads in the channel.
574
+ # @macro async
575
+ # @macro http
576
+ #
577
+ # @return [Array<Discorb::ThreadChannel>] The archived private threads in the channel.
578
+ #
579
+ def fetch_archived_private_threads
580
+ Async do
581
+ _resp, data = @client.internet.get("/channels/#{@id}/threads/archived/private").wait
582
+ data.map { |thread| Channel.make_channel(@client, thread) }
583
+ end
584
+ end
585
+
586
+ #
587
+ # Fetch joined archived private threads in the channel.
588
+ # @macro async
589
+ # @macro http
590
+ #
591
+ # @param [Integer] limit The limit of threads to fetch.
592
+ # @param [Time] before <description>
593
+ #
594
+ # @return [Array<Discorb::ThreadChannel>] The joined archived private threads in the channel.
595
+ #
596
+ def fetch_joined_archived_private_threads(limit: nil, before: nil)
597
+ Async do
598
+ if limit.nil?
599
+ before = 0
600
+ threads = []
601
+ loop do
602
+ _resp, data = @client.internet.get("/channels/#{@id}/users/@me/threads/archived/private?before=#{before}").wait
603
+ threads += data[:threads].map { |thread| Channel.make_channel(@client, thread) }
604
+ before = data[:threads][-1][:id]
605
+
606
+ break unless data[:has_more]
607
+ end
608
+ threads
609
+ else
610
+ _resp, data = @client.internet.get("/channels/#{@id}/users/@me/threads/archived/private?limit=#{limit}&before=#{before}").wait
611
+ data.map { |thread| Channel.make_channel(@client, thread) }
612
+ end
613
+ end
614
+ end
615
+
616
+ private
617
+
618
+ def _set_data(data)
619
+ @topic = data[:topic]
620
+ @nsfw = data[:nsfw]
621
+ @last_message_id = data[:last_message_id]
622
+ @rate_limit_per_user = data[:rate_limit_per_user]
623
+ @last_pin_timestamp = data[:last_pin_timestamp] && Time.iso8601(data[:last_pin_timestamp])
624
+ super
625
+ end
626
+ end
627
+
628
+ #
629
+ # Represents a news channel (announcement channel).
630
+ #
631
+ class NewsChannel < TextChannel
632
+ include Messageable
633
+
634
+ @channel_type = 5
635
+ end
636
+
637
+ #
638
+ # Represents a voice channel.
639
+ # @todo Implement connecting to voice channel.
640
+ #
641
+ class VoiceChannel < GuildChannel
642
+ # @return [Integer] The bitrate of the voice channel.
643
+ attr_reader :bitrate
644
+ # @return [Integer] The user limit of the voice channel.
645
+ # @return [nil] If the user limit is not set.
646
+ attr_reader :user_limit
647
+
648
+ @channel_type = 2
649
+ #
650
+ # Edit the voice channel.
651
+ # @macro async
652
+ # @macro http
653
+ # @macro edit
654
+ #
655
+ # @param [String] name The name of the voice channel.
656
+ # @param [Integer] position The position of the voice channel.
657
+ # @param [Integer] bitrate The bitrate of the voice channel.
658
+ # @param [Integer] user_limit The user limit of the voice channel.
659
+ # @param [Symbol] rtc_region The region of the voice channel.
660
+ # @param [String] reason The reason of editing the voice channel.
661
+ #
662
+ # @return [self] The edited voice channel.
663
+ #
664
+ def edit(name: :unset, position: :unset, bitrate: :unset, user_limit: :unset, rtc_region: :unset, reason: nil)
665
+ Async do
666
+ payload = {}
667
+ payload[:name] = name if name != :unset
668
+ payload[:position] = position if position != :unset
669
+ payload[:bitrate] = bitrate if bitrate != :unset
670
+ payload[:user_limit] = user_limit if user_limit != :unset
671
+ payload[:rtc_region] = rtc_region if rtc_region != :unset
672
+
673
+ @client.internet.patch("/channels/#{@id}", payload, audit_log_reason: reason).wait
674
+ self
675
+ end
676
+ end
677
+
678
+ alias modify edit
679
+
680
+ private
681
+
682
+ def _set_data(data)
683
+ @bitrate = data[:bitrate]
684
+ @user_limit = (data[:user_limit]).zero? ? nil : data[:user_limit]
685
+ @rtc_region = data[:rtc_region]&.to_sym
686
+ @video_quality_mode = data[:video_quality_mode] == 1 ? :auto : :full
687
+ super
688
+ end
689
+ end
690
+
691
+ #
692
+ # Represents a stage channel.
693
+ #
694
+ class StageChannel < GuildChannel
695
+ # @return [Integer] The bitrate of the voice channel.
696
+ attr_reader :bitrate
697
+ # @return [Integer] The user limit of the voice channel.
698
+ attr_reader :user_limit
699
+ # @!visibility private
700
+ attr_reader :stage_instances
701
+
702
+ # @!attribute [r] stage_instance
703
+ # @return [Discorb::StageInstance] The stage instance of the channel.
704
+
705
+ @channel_type = 13
706
+ # @!visibility private
707
+ def initialize(...)
708
+ @stage_instances = Dictionary.new
709
+ super(...)
710
+ end
711
+
712
+ def stage_instance
713
+ @stage_instances[0]
714
+ end
715
+
716
+ #
717
+ # Edit the stage channel.
718
+ # @macro async
719
+ # @macro http
720
+ # @macro edit
721
+ #
722
+ # @param [String] name The name of the stage channel.
723
+ # @param [Integer] position The position of the stage channel.
724
+ # @param [Integer] bitrate The bitrate of the stage channel.
725
+ # @param [Symbol] rtc_region The region of the stage channel.
726
+ # @param [String] reason The reason of editing the stage channel.
727
+ #
728
+ # @return [self] The edited stage channel.
729
+ #
730
+ def edit(name: :unset, position: :unset, bitrate: :unset, rtc_region: :unset, reason: nil)
731
+ Async do
732
+ payload = {}
733
+ payload[:name] = name if name != :unset
734
+ payload[:position] = position if position != :unset
735
+ payload[:bitrate] = bitrate if bitrate != :unset
736
+ payload[:rtc_region] = rtc_region if rtc_region != :unset
737
+ @client.internet.patch("/channels/#{@id}", payload, audit_log_reason: reason).wait
738
+ self
739
+ end
740
+ end
741
+
742
+ alias modify edit
743
+
744
+ #
745
+ # Start a stage instance.
746
+ # @macro async
747
+ # @macro http
748
+ #
749
+ # @param [String] topic The topic of the stage instance.
750
+ # @param [Boolean] public Whether the stage instance is public or not.
751
+ # @param [String] reason The reason of starting the stage instance.
752
+ #
753
+ # @return [Discorb::StageInstance] The started stage instance.
754
+ #
755
+ def start(topic, public: false, reason: nil)
756
+ Async do
757
+ _resp, data = @client.internet.post("/stage-instances", { channel_id: @id, topic: topic, public: public ? 2 : 1 }, audit_log_reason: reason).wait
758
+ StageInstance.new(@client, data)
759
+ end
760
+ end
761
+
762
+ #
763
+ # Fetch a current stage instance.
764
+ # @macro async
765
+ # @macro http
766
+ #
767
+ # @return [StageInstance] The current stage instance.
768
+ # @return [nil] If there is no current stage instance.
769
+ #
770
+ def fetch_stage_instance
771
+ Async do
772
+ _resp, data = @client.internet.get("/stage-instances/#{@id}").wait
773
+ rescue Discorb::NotFoundError
774
+ nil
775
+ else
776
+ StageInstance.new(@client, data)
777
+ end
778
+ end
779
+
780
+ private
781
+
782
+ def _set_data(data)
783
+ @bitrate = data[:bitrate]
784
+ @user_limit = data[:user_limit]
785
+ @topic = data[:topic]
786
+ @rtc_region = data[:rtc_region]&.to_sym
787
+ super
788
+ end
789
+ end
790
+
791
+ #
792
+ # Represents a thread.
793
+ # @abstract
794
+ #
795
+ class ThreadChannel < Channel
796
+ # @return [Discorb::Snowflake] The ID of the channel.
797
+ # @note This ID is same as the starter message's ID
798
+ attr_reader :id
799
+ # @return [String] The name of the thread.
800
+ attr_reader :name
801
+ # @return [Integer] The number of messages in the thread.
802
+ # @note This will stop counting at 50.
803
+ attr_reader :message_count
804
+ # @return [Integer] The number of recipients in the thread.
805
+ # @note This will stop counting at 50.
806
+ attr_reader :member_count
807
+ alias recipient_count member_count
808
+ # @return [Integer] The rate limit per user (slowmode) in the thread.
809
+ attr_reader :rate_limit_per_user
810
+ alias slowmode rate_limit_per_user
811
+ # @return [Array<Discorb::ThreadChannel::Member>] The members of the thread.
812
+ attr_reader :members
813
+ # @return [Time] The time the thread was archived.
814
+ # @return [nil] If the thread is not archived.
815
+ attr_reader :archived_timestamp
816
+ alias archived_at archived_timestamp
817
+ # @return [Integer] Auto archive duration in seconds.
818
+ attr_reader :auto_archive_duration
819
+ alias archive_in auto_archive_duration
820
+ # @return [Boolean] Whether the thread is archived or not.
821
+ attr_reader :archived
822
+ alias archived? archived
823
+
824
+ # @!attribute [r] parent
825
+ # @macro client_cache
826
+ # @return [Discorb::GuildChannel] The parent channel of the thread.
827
+
828
+ include Messageable
829
+ @channel_type = nil
830
+
831
+ # @!visibility private
832
+ def initialize(client, data, no_cache: false)
833
+ @members = Dictionary.new
834
+ super
835
+ @client.channels[@parent_id].threads[@id] = self
836
+
837
+ @client.channels[@id] = self unless no_cache
838
+ end
839
+
840
+ #
841
+ # Edit the thread.
842
+ # @macro async
843
+ # @macro http
844
+ # @macro edit
845
+ #
846
+ # @param [String] name The name of the thread.
847
+ # @param [Boolean] archived Whether the thread is archived or not.
848
+ # @param [Integer] auto_archive_duration The auto archive duration in seconds.
849
+ # @param [Integer] archive_in Alias of `auto_archive_duration`.
850
+ # @param [Boolean] locked Whether the thread is locked or not.
851
+ # @param [String] reason The reason of editing the thread.
852
+ #
853
+ # @return [self] The edited thread.
854
+ #
855
+ # @see #archive
856
+ # @see #lock
857
+ # @see #unarchive
858
+ # @see #unlock
859
+ #
860
+ def edit(name: :unset, archived: :unset, auto_archive_duration: :unset, archive_in: :unset, locked: :unset, reason: nil)
861
+ Async do
862
+ payload = {}
863
+ payload[:name] = name if name != :unset
864
+ payload[:archived] = archived if archived != :unset
865
+ auto_archive_duration ||= archive_in
866
+ payload[:auto_archive_duration] = auto_archive_duration if auto_archive_duration != :unset
867
+ payload[:locked] = locked if locked != :unset
868
+ @client.internet.patch("/channels/#{@id}", payload, audit_log_reason: reason).wait
869
+ self
870
+ end
871
+ end
872
+
873
+ #
874
+ # Helper method to archive the thread.
875
+ #
876
+ # @param [String] reason The reason of archiving the thread.
877
+ #
878
+ # @return [self] The archived thread.
879
+ #
880
+ def archive(reason: nil)
881
+ edit(archived: true, reason: reason)
882
+ end
883
+
884
+ #
885
+ # Helper method to lock the thread.
886
+ #
887
+ # @param [String] reason The reason of locking the thread.
888
+ #
889
+ # @return [self] The locked thread.
890
+ #
891
+ def lock(reason: nil)
892
+ edit(archived: true, locked: true, reason: reason)
893
+ end
894
+
895
+ #
896
+ # Helper method to unarchive the thread.
897
+ #
898
+ # @param [String] reason The reason of unarchiving the thread.
899
+ #
900
+ # @return [self] The unarchived thread.
901
+ #
902
+ def unarchive(reason: nil)
903
+ edit(archived: false, reason: reason)
904
+ end
905
+
906
+ #
907
+ # Helper method to unlock the thread.
908
+ #
909
+ # @param [String] reason The reason of unlocking the thread.
910
+ #
911
+ # @return [self] The unlocked thread.
912
+ #
913
+ # @note This method won't unarchive the thread. Use {#unarchive} instead.
914
+ #
915
+ def unlock(reason: nil)
916
+ edit(archived: !unarchive, locked: false, reason: reason)
917
+ end
918
+
919
+ def parent
920
+ return nil unless @parent_id
921
+
922
+ @client.channels[@parent_id]
923
+ end
924
+
925
+ alias channel parent
926
+
927
+ def me
928
+ @members[@client.user.id]
929
+ end
930
+
931
+ def joined?
932
+ @members[@client.user.id]
933
+ end
934
+
935
+ def guild
936
+ @client.guilds[@guild]
937
+ end
938
+
939
+ def owner
940
+ guild.members[@owner_id]
941
+ end
942
+
943
+ def inspect
944
+ "#<#{self.class} \"##{@name}\" id=#{@id}>"
945
+ end
946
+
947
+ def add_member(member = :me)
948
+ Async do
949
+ if member == :me
950
+ @client.internet.post("/channels/#{@id}/thread-members/@me").wait
951
+ else
952
+ @client.internet.post("/channels/#{@id}/thread-members/#{Utils.try(member, :id)}").wait
953
+ end
954
+ end
955
+ end
956
+
957
+ alias join add_member
958
+
959
+ def remove_member(member = :me)
960
+ Async do
961
+ if member == :me
962
+ @client.internet.delete("/channels/#{@id}/thread-members/@me").wait
963
+ else
964
+ @client.internet.delete("/channels/#{@id}/thread-members/#{Utils.try(member, :id)}").wait
965
+ end
966
+ end
967
+ end
968
+
969
+ alias leave remove_member
970
+
971
+ def fetch_members
972
+ Async do
973
+ _resp, data = @client.internet.get("/channels/#{@id}/thread-members").wait
974
+ data.map { |d| @members[d[:id]] = Member.new(@client, d) }
975
+ end
976
+ end
977
+
978
+ class Public < ThreadChannel
979
+ @channel_type = 11
980
+ end
981
+
982
+ class Private < ThreadChannel
983
+ @channel_type = 12
984
+ end
985
+
986
+ class << self
987
+ attr_reader :channel_type
988
+ end
989
+
990
+ class Member < DiscordModel
991
+ attr_reader :joined_at
992
+
993
+ def initialize(cilent, data)
994
+ @cilent = cilent
995
+ @thread_id = data[:id]
996
+ @user_id = data[:user_id]
997
+ @joined_at = Time.iso8601(data[:join_timestamp])
998
+ end
999
+
1000
+ def thread
1001
+ @client.channels[@thread_id]
1002
+ end
1003
+
1004
+ def member
1005
+ thread && thread.members[@user_id]
1006
+ end
1007
+
1008
+ def id
1009
+ @user_id
1010
+ end
1011
+
1012
+ def user
1013
+ @cilent.users[@user_id]
1014
+ end
1015
+
1016
+ def inspect
1017
+ "#<#{self.class} id=#{@id.inspect}>"
1018
+ end
1019
+ end
1020
+
1021
+ private
1022
+
1023
+ def _set_data(data)
1024
+ @id = Snowflake.new(data[:id])
1025
+ @name = data[:name]
1026
+ @guild_id = data[:guild_id]
1027
+ @parent_id = data[:parent_id]
1028
+ @archived = data[:thread_metadata][:archived]
1029
+ @owner_id = data[:owner_id]
1030
+ @archived_timestamp = data[:thread_metadata][:archived_timestamp] && Time.iso8601(data[:thread_metadata][:archived_timestamp])
1031
+ @auto_archive_duration = data[:thread_metadata][:auto_archive_duration]
1032
+ @locked = data[:thread_metadata][:locked]
1033
+ @member_count = data[:member_count]
1034
+ @message_count = data[:message_count]
1035
+ @members[@client.user.id] = ThreadChannel::Member.new(@client, data[:member].merge({ id: data[:id], user_id: @client.user.id })) if data[:member]
1036
+ @data.merge!(data)
1037
+ end
1038
+ end
1039
+
1040
+ class CategoryChannel < GuildChannel
1041
+ attr_reader :channels
1042
+
1043
+ @channel_type = 4
1044
+
1045
+ def text_channels
1046
+ @channels.filter { |c| c.is_a? TextChannel }
1047
+ end
1048
+
1049
+ def voice_channels
1050
+ @channels.filter { |c| c.is_a? VoiceChannel }
1051
+ end
1052
+
1053
+ def news_channel
1054
+ @channels.filter { |c| c.is_a? NewsChannel }
1055
+ end
1056
+
1057
+ def stage_channels
1058
+ @channels.filter { |c| c.is_a? StageChannel }
1059
+ end
1060
+
1061
+ def create_text_channel(*args, **kwargs)
1062
+ guild.create_text_channel(*args, parent: self, **kwargs)
1063
+ end
1064
+
1065
+ def create_voice_channel(*args, **kwargs)
1066
+ guild.create_voice_channel(*args, parent: self, **kwargs)
1067
+ end
1068
+
1069
+ def create_news_channel(*args, **kwargs)
1070
+ guild.create_news_channel(*args, parent: self, **kwargs)
1071
+ end
1072
+
1073
+ def create_stage_channel(*args, **kwargs)
1074
+ guild.create_stage_channel(*args, parent: self, **kwargs)
1075
+ end
1076
+
1077
+ private
1078
+
1079
+ def _set_data(data)
1080
+ @channels = @client.channels.values.filter { |channel| channel.parent == self }
1081
+ super
1082
+ end
1083
+ end
1084
+
1085
+ class DMChannel < Channel
1086
+ include Messageable
1087
+
1088
+ # @!visibility private
1089
+ def base_url
1090
+ Async do
1091
+ "/channels/#{@id}"
1092
+ end
1093
+ end
1094
+
1095
+ private
1096
+
1097
+ def _set_data(data)
1098
+ @id = Snowflake.new(data)
1099
+ end
1100
+ end
1101
+ end