discorb 0.16.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/.github/workflows/build_main.yml +2 -2
  4. data/.github/workflows/build_version.yml +1 -1
  5. data/.github/workflows/codeql-analysis.yml +1 -1
  6. data/.github/workflows/lint-push.yml +3 -5
  7. data/.github/workflows/lint.yml +2 -4
  8. data/.github/workflows/spec.yml +33 -0
  9. data/.github/workflows/validate.yml +21 -0
  10. data/.gitignore +2 -0
  11. data/.lefthook/commit-msg/validator.rb +5 -0
  12. data/.rspec +2 -0
  13. data/.rspec_parallel +2 -0
  14. data/.rubocop.yml +43 -6
  15. data/Changelog.md +30 -1
  16. data/Gemfile +20 -8
  17. data/Rakefile +226 -98
  18. data/Steepfile +28 -0
  19. data/bin/console +3 -3
  20. data/docs/Examples.md +1 -1
  21. data/docs/application_command.md +156 -47
  22. data/docs/cli/irb.md +2 -2
  23. data/docs/cli/new.md +14 -9
  24. data/docs/cli/run.md +7 -11
  25. data/docs/cli.md +17 -10
  26. data/docs/events.md +247 -213
  27. data/docs/extension.md +1 -2
  28. data/docs/faq.md +0 -1
  29. data/docs/tutorial.md +18 -18
  30. data/docs/voice_events.md +106 -106
  31. data/examples/commands/message.rb +68 -0
  32. data/examples/commands/permission.rb +19 -0
  33. data/examples/commands/slash.rb +48 -0
  34. data/examples/commands/user.rb +54 -0
  35. data/examples/components/authorization_button.rb +4 -3
  36. data/examples/components/select_menu.rb +6 -3
  37. data/examples/extension/main.rb +2 -1
  38. data/examples/extension/message_expander.rb +6 -2
  39. data/examples/sig/commands/message.rbs +5 -0
  40. data/examples/simple/eval.rb +3 -2
  41. data/examples/simple/ping_pong.rb +2 -1
  42. data/examples/simple/rolepanel.rb +17 -6
  43. data/examples/simple/shard.rb +3 -2
  44. data/examples/simple/wait_for_message.rb +4 -1
  45. data/exe/discorb +33 -18
  46. data/lefthook.yml +45 -0
  47. data/lib/discorb/allowed_mentions.rb +2 -1
  48. data/lib/discorb/app_command/command.rb +130 -72
  49. data/lib/discorb/app_command/common.rb +25 -0
  50. data/lib/discorb/app_command/handler.rb +130 -33
  51. data/lib/discorb/app_command.rb +2 -1
  52. data/lib/discorb/application.rb +1 -0
  53. data/lib/discorb/asset.rb +1 -2
  54. data/lib/discorb/attachment.rb +1 -1
  55. data/lib/discorb/audit_logs.rb +19 -10
  56. data/lib/discorb/automod.rb +269 -0
  57. data/lib/discorb/channel/base.rb +108 -0
  58. data/lib/discorb/channel/category.rb +32 -0
  59. data/lib/discorb/channel/container.rb +44 -0
  60. data/lib/discorb/channel/dm.rb +28 -0
  61. data/lib/discorb/channel/guild.rb +246 -0
  62. data/lib/discorb/channel/stage.rb +140 -0
  63. data/lib/discorb/channel/text.rb +336 -0
  64. data/lib/discorb/channel/thread.rb +325 -0
  65. data/lib/discorb/channel/voice.rb +79 -0
  66. data/lib/discorb/channel.rb +2 -1165
  67. data/lib/discorb/client.rb +50 -36
  68. data/lib/discorb/color.rb +37 -60
  69. data/lib/discorb/common.rb +2 -1
  70. data/lib/discorb/components/button.rb +2 -1
  71. data/lib/discorb/components/select_menu.rb +4 -2
  72. data/lib/discorb/components/text_input.rb +12 -2
  73. data/lib/discorb/components.rb +1 -1
  74. data/lib/discorb/dictionary.rb +1 -1
  75. data/lib/discorb/embed.rb +26 -10
  76. data/lib/discorb/emoji.rb +31 -4
  77. data/lib/discorb/emoji_table.rb +4969 -3
  78. data/lib/discorb/event.rb +29 -4
  79. data/lib/discorb/exe/about.rb +2 -1
  80. data/lib/discorb/exe/irb.rb +2 -4
  81. data/lib/discorb/exe/new.rb +89 -26
  82. data/lib/discorb/exe/run.rb +8 -22
  83. data/lib/discorb/exe/setup.rb +25 -12
  84. data/lib/discorb/exe/show.rb +4 -3
  85. data/lib/discorb/extend.rb +1 -0
  86. data/lib/discorb/extension.rb +6 -7
  87. data/lib/discorb/flag.rb +13 -2
  88. data/lib/discorb/gateway.rb +79 -589
  89. data/lib/discorb/gateway_events.rb +638 -0
  90. data/lib/discorb/guild.rb +318 -67
  91. data/lib/discorb/guild_template.rb +11 -5
  92. data/lib/discorb/http.rb +53 -24
  93. data/lib/discorb/integration.rb +4 -1
  94. data/lib/discorb/intents.rb +28 -19
  95. data/lib/discorb/interaction/autocomplete.rb +28 -16
  96. data/lib/discorb/interaction/command.rb +42 -14
  97. data/lib/discorb/interaction/components.rb +5 -2
  98. data/lib/discorb/interaction/modal.rb +0 -1
  99. data/lib/discorb/interaction/response.rb +125 -26
  100. data/lib/discorb/interaction/root.rb +13 -13
  101. data/lib/discorb/interaction.rb +1 -0
  102. data/lib/discorb/invite.rb +5 -2
  103. data/lib/discorb/member.rb +28 -8
  104. data/lib/discorb/message.rb +60 -25
  105. data/lib/discorb/message_meta.rb +3 -3
  106. data/lib/discorb/modules.rb +59 -16
  107. data/lib/discorb/presence.rb +2 -0
  108. data/lib/discorb/rate_limit.rb +7 -2
  109. data/lib/discorb/reaction.rb +2 -2
  110. data/lib/discorb/role.rb +20 -5
  111. data/lib/discorb/shard.rb +1 -1
  112. data/lib/discorb/sticker.rb +9 -8
  113. data/lib/discorb/user.rb +4 -3
  114. data/lib/discorb/utils/colored_puts.rb +1 -0
  115. data/lib/discorb/voice_state.rb +6 -2
  116. data/lib/discorb/webhook.rb +64 -31
  117. data/lib/discorb.rb +7 -5
  118. data/po/yard.pot +20 -20
  119. data/rbs_collection.lock.yaml +88 -0
  120. data/rbs_collection.yaml +21 -0
  121. data/sig/async.rbs +11 -0
  122. data/sig/discorb/activity.rbs +23 -0
  123. data/sig/discorb/allowed_mentions.rbs +44 -0
  124. data/sig/discorb/app_command/base.rbs +282 -0
  125. data/sig/discorb/app_command/handler.rbs +171 -0
  126. data/sig/discorb/application.rbs +142 -0
  127. data/sig/discorb/asset.rbs +32 -0
  128. data/sig/discorb/attachment.rbs +91 -0
  129. data/sig/discorb/audit_log.rbs +231 -0
  130. data/sig/discorb/automod.rbs +128 -0
  131. data/sig/discorb/avatar.rbs +26 -0
  132. data/sig/discorb/channel/base.rbs +179 -0
  133. data/sig/discorb/channel/category.rbs +56 -0
  134. data/sig/discorb/channel/container.rbs +29 -0
  135. data/sig/discorb/channel/dm.rbs +14 -0
  136. data/sig/discorb/channel/news.rbs +20 -0
  137. data/sig/discorb/channel/stage.rbs +77 -0
  138. data/sig/discorb/channel/text.rbs +158 -0
  139. data/sig/discorb/channel/thread.rbs +185 -0
  140. data/sig/discorb/channel/voice.rbs +41 -0
  141. data/sig/discorb/client.rbs +2495 -0
  142. data/sig/discorb/color.rbs +142 -0
  143. data/sig/discorb/component/base.rbs +28 -0
  144. data/sig/discorb/component/button.rbs +65 -0
  145. data/sig/discorb/component/select_menu.rbs +107 -0
  146. data/sig/discorb/component/text_input.rbs +69 -0
  147. data/sig/discorb/connectable.rbs +8 -0
  148. data/sig/discorb/custom_emoji.rbs +90 -0
  149. data/sig/discorb/dictionary.rbs +85 -0
  150. data/sig/discorb/discord_model.rbs +15 -0
  151. data/sig/discorb/embed.rbs +279 -0
  152. data/sig/discorb/emoji.rbs +13 -0
  153. data/sig/discorb/error.rbs +73 -0
  154. data/sig/discorb/event_handler.rbs +27 -0
  155. data/sig/discorb/extension.rbs +1734 -0
  156. data/sig/discorb/flag.rbs +72 -0
  157. data/sig/discorb/gateway.rbs +481 -0
  158. data/sig/discorb/guild.rbs +870 -0
  159. data/sig/discorb/guild_template.rbs +174 -0
  160. data/sig/discorb/http.rbs +147 -0
  161. data/sig/discorb/image.rbs +20 -0
  162. data/sig/discorb/integration.rbs +118 -0
  163. data/sig/discorb/intents.rbs +97 -0
  164. data/sig/discorb/interaction/autocomplete.rbs +9 -0
  165. data/sig/discorb/interaction/base.rbs +66 -0
  166. data/sig/discorb/interaction/command.rbs +66 -0
  167. data/sig/discorb/interaction/message_component.rbs +140 -0
  168. data/sig/discorb/interaction/modal.rbs +50 -0
  169. data/sig/discorb/interaction/responder.rbs +157 -0
  170. data/sig/discorb/invite.rbs +86 -0
  171. data/sig/discorb/member.rbs +187 -0
  172. data/sig/discorb/message.rbs +469 -0
  173. data/sig/discorb/messageable.rbs +153 -0
  174. data/sig/discorb/partial_emoji.rbs +35 -0
  175. data/sig/discorb/permissions.rbs +149 -0
  176. data/sig/discorb/presence.rbs +237 -0
  177. data/sig/discorb/reaction.rbs +33 -0
  178. data/sig/discorb/role.rbs +145 -0
  179. data/sig/discorb/scheduled_event.rbs +148 -0
  180. data/sig/discorb/shard.rbs +62 -0
  181. data/sig/discorb/snowflake.rbs +56 -0
  182. data/sig/discorb/stage_instance.rbs +63 -0
  183. data/sig/discorb/sticker.rbs +116 -0
  184. data/sig/discorb/system_channel_flag.rbs +17 -0
  185. data/sig/discorb/unicode_emoji.rbs +49 -0
  186. data/sig/discorb/user.rbs +93 -0
  187. data/sig/discorb/utils.rbs +8 -0
  188. data/sig/discorb/voice_region.rbs +30 -0
  189. data/sig/discorb/voice_state.rbs +71 -0
  190. data/sig/discorb/webhook.rbs +327 -0
  191. data/sig/discorb/welcome_screen.rbs +78 -0
  192. data/sig/discorb.rbs +6 -7230
  193. data/sig/manifest.yaml +3 -0
  194. data/sig/override.rbs +19 -0
  195. data/template-replace/files/css/common.css +4 -0
  196. metadata +102 -6
  197. data/examples/commands/bookmarker.rb +0 -42
  198. data/examples/commands/hello.rb +0 -10
  199. data/examples/commands/inspect.rb +0 -25
@@ -0,0 +1,336 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Represents a text channel.
6
+ #
7
+ class TextChannel < GuildChannel
8
+ # @return [String] The topic of the channel.
9
+ attr_reader :topic
10
+ # @return [Boolean] Whether the channel is nsfw.
11
+ attr_reader :nsfw
12
+ # @return [Discorb::Snowflake] The id of the last message.
13
+ attr_reader :last_message_id
14
+ # @return [Integer] The rate limit per user (Slowmode) in the channel.
15
+ attr_reader :rate_limit_per_user
16
+ alias slowmode rate_limit_per_user
17
+ # @return [Time] The time when the last pinned message was pinned.
18
+ attr_reader :last_pin_timestamp
19
+ alias last_pinned_at last_pin_timestamp
20
+ # @return [Integer] The default value of duration of auto archive.
21
+ attr_reader :default_auto_archive_duration
22
+
23
+ include Messageable
24
+
25
+ @channel_type = 0
26
+
27
+ # @!attribute [r] threads
28
+ # @return [Array<Discorb::ThreadChannel>] The threads in the channel.
29
+ def threads
30
+ guild.threads.select { |thread| thread.parent == self }
31
+ end
32
+
33
+ #
34
+ # Edits the channel.
35
+ # @async
36
+ # @macro edit
37
+ #
38
+ # @param [String] name The name of the channel.
39
+ # @param [Integer] position The position of the channel.
40
+ # @param [Discorb::CategoryChannel, nil] category The parent of channel. Specify `nil` to remove the parent.
41
+ # @param [Discorb::CategoryChannel, nil] parent Alias of `category`.
42
+ # @param [String] topic The topic of the channel.
43
+ # @param [Boolean] nsfw Whether the channel is nsfw.
44
+ # @param [Boolean] announce Whether the channel is announce channel.
45
+ # @param [Integer] rate_limit_per_user The rate limit per user (Slowmode) in the channel.
46
+ # @param [Integer] slowmode Alias of `rate_limit_per_user`.
47
+ # @param [Integer] default_auto_archive_duration The default auto archive duration of the channel.
48
+ # @param [Integer] archive_in Alias of `default_auto_archive_duration`.
49
+ # @param [String] reason The reason of editing the channel.
50
+ #
51
+ # @return [Async::Task<self>] The edited channel.
52
+ #
53
+ def edit(
54
+ name: Discorb::Unset,
55
+ position: Discorb::Unset,
56
+ category: Discorb::Unset,
57
+ parent: Discorb::Unset,
58
+ topic: Discorb::Unset,
59
+ nsfw: Discorb::Unset,
60
+ announce: Discorb::Unset,
61
+ rate_limit_per_user: Discorb::Unset,
62
+ slowmode: Discorb::Unset,
63
+ default_auto_archive_duration: Discorb::Unset,
64
+ archive_in: Discorb::Unset,
65
+ reason: nil
66
+ )
67
+ Async do
68
+ payload = {}
69
+ payload[:name] = name if name != Discorb::Unset
70
+ payload[:announce] = announce ? 5 : 0 if announce != Discorb::Unset
71
+ payload[:position] = position if position != Discorb::Unset
72
+ payload[:topic] = topic || "" if topic != Discorb::Unset
73
+ payload[:nsfw] = nsfw if nsfw != Discorb::Unset
74
+
75
+ slowmode = rate_limit_per_user if slowmode == Discorb::Unset
76
+ payload[:rate_limit_per_user] = slowmode || 0 if slowmode != Discorb::Unset
77
+ parent = category if parent == Discorb::Unset
78
+ payload[:parent_id] = parent&.id if parent != Discorb::Unset
79
+
80
+ default_auto_archive_duration ||= archive_in
81
+ if default_auto_archive_duration != Discorb::Unset
82
+ payload[:default_auto_archive_duration] =
83
+ default_auto_archive_duration
84
+ end
85
+
86
+ @client.http.request(Route.new("/channels/#{@id}", "//channels/:channel_id", :patch), payload,
87
+ audit_log_reason: reason).wait
88
+ self
89
+ end
90
+ end
91
+
92
+ alias modify edit
93
+
94
+ #
95
+ # Create webhook in the channel.
96
+ # @async
97
+ #
98
+ # @param [String] name The name of the webhook.
99
+ # @param [Discorb::Image] avatar The avatar of the webhook.
100
+ #
101
+ # @return [Async::Task<Discorb::Webhook::IncomingWebhook>] The created webhook.
102
+ #
103
+ def create_webhook(name, avatar: nil)
104
+ Async do
105
+ payload = {}
106
+ payload[:name] = name
107
+ payload[:avatar] = avatar.to_s if avatar
108
+ _resp, data = @client.http.request(
109
+ Route.new("/channels/#{@id}/webhooks", "//channels/:channel_id/webhooks", :post), payload
110
+ ).wait
111
+ Webhook.from_data(@client, data)
112
+ end
113
+ end
114
+
115
+ #
116
+ # Fetch webhooks in the channel.
117
+ # @async
118
+ #
119
+ # @return [Async::Task<Array<Discorb::Webhook>>] The webhooks in the channel.
120
+ #
121
+ def fetch_webhooks
122
+ Async do
123
+ _resp, data = @client.http.request(Route.new("/channels/#{@id}/webhooks", "//channels/:channel_id/webhooks",
124
+ :get)).wait
125
+ data.map { |webhook| Webhook.from_data(@client, webhook) }
126
+ end
127
+ end
128
+
129
+ #
130
+ # Bulk delete messages in the channel.
131
+ # @async
132
+ #
133
+ # @param [Discorb::Message] messages The messages to delete.
134
+ # @param [Boolean] force Whether to ignore the validation for message (14 days limit).
135
+ #
136
+ # @return [Async::Task<void>] The task.
137
+ #
138
+ def delete_messages!(*messages, force: false)
139
+ Async do
140
+ messages = messages.flatten
141
+ unless force
142
+ time = Time.now
143
+ messages.delete_if do |message|
144
+ next false unless message.is_a?(Message)
145
+
146
+ time - message.created_at > 60 * 60 * 24 * 14
147
+ end
148
+ end
149
+
150
+ message_ids = messages.map { |m| Discorb::Utils.try(m, :id).to_s }
151
+
152
+ @client.http.request(
153
+ Route.new("/channels/#{@id}/messages/bulk-delete", "//channels/:channel_id/messages/bulk-delete",
154
+ :post), { messages: message_ids }
155
+ ).wait
156
+ end
157
+ end
158
+
159
+ alias bulk_delete! delete_messages!
160
+ alias destroy_messages! delete_messages!
161
+
162
+ #
163
+ # Follow the existing announcement channel.
164
+ # @async
165
+ #
166
+ # @param [Discorb::NewsChannel] target The channel to follow.
167
+ # @param [String] reason The reason of following the channel.
168
+ #
169
+ # @return [Async::Task<void>] The task.
170
+ #
171
+ def follow_from(target, reason: nil)
172
+ Async do
173
+ @client.http.request(Route.new("/channels/#{target.id}/followers", "//channels/:channel_id/followers", :post),
174
+ { webhook_channel_id: @id }, audit_log_reason: reason).wait
175
+ end
176
+ end
177
+
178
+ #
179
+ # Start thread in the channel.
180
+ # @async
181
+ #
182
+ # @param [String] name The name of the thread.
183
+ # @param [Discorb::Message] message The message to start the thread.
184
+ # @param [:hour, :day, :three_days, :week] auto_archive_duration The duration of auto-archiving.
185
+ # @param [Boolean] public Whether the thread is public.
186
+ # @param [Integer] rate_limit_per_user The rate limit per user.
187
+ # @param [Integer] slowmode Alias of `rate_limit_per_user`.
188
+ # @param [String] reason The reason of starting the thread.
189
+ #
190
+ # @return [Async::Task<Discorb::ThreadChannel>] The started thread.
191
+ #
192
+ def start_thread(
193
+ name,
194
+ message: nil,
195
+ auto_archive_duration: nil,
196
+ public: true,
197
+ rate_limit_per_user: nil,
198
+ slowmode: nil,
199
+ reason: nil
200
+ )
201
+ auto_archive_duration ||= @default_auto_archive_duration
202
+ Async do
203
+ _resp, data = if message.nil?
204
+ @client.http.request(
205
+ Route.new("/channels/#{@id}/threads", "//channels/:channel_id/threads", :post),
206
+ {
207
+ name: name,
208
+ auto_archive_duration: auto_archive_duration,
209
+ type: public ? 11 : 10,
210
+ rate_limit_per_user: rate_limit_per_user || slowmode,
211
+ },
212
+ audit_log_reason: reason,
213
+ ).wait
214
+ else
215
+ @client.http.request(
216
+ Route.new("/channels/#{@id}/messages/#{Utils.try(message, :id)}/threads",
217
+ "//channels/:channel_id/messages/:message_id/threads", :post),
218
+ {
219
+ name: name,
220
+ auto_archive_duration: auto_archive_duration,
221
+ },
222
+ audit_log_reason: reason,
223
+ ).wait
224
+ end
225
+ Channel.make_channel(@client, data)
226
+ end
227
+ end
228
+
229
+ alias create_thread start_thread
230
+
231
+ #
232
+ # Fetch archived threads in the channel.
233
+ # @async
234
+ #
235
+ # @return [Async::Task<Array<Discorb::ThreadChannel>>] The archived threads in the channel.
236
+ #
237
+ def fetch_archived_public_threads
238
+ Async do
239
+ _resp, data = @client.http.request(Route.new("/channels/#{@id}/threads/archived/public",
240
+ "//channels/:channel_id/threads/archived/public", :get)).wait
241
+ data.map { |thread| Channel.make_channel(@client, thread) }
242
+ end
243
+ end
244
+
245
+ #
246
+ # Fetch archived private threads in the channel.
247
+ # @async
248
+ #
249
+ # @return [Async::Task<Array<Discorb::ThreadChannel>>] The archived private threads in the channel.
250
+ #
251
+ def fetch_archived_private_threads
252
+ Async do
253
+ _resp, data = @client.http.request(Route.new("/channels/#{@id}/threads/archived/private",
254
+ "//channels/:channel_id/threads/archived/private", :get)).wait
255
+ data.map { |thread| Channel.make_channel(@client, thread) }
256
+ end
257
+ end
258
+
259
+ #
260
+ # Fetch joined archived private threads in the channel.
261
+ # @async
262
+ #
263
+ # @param [Integer] limit The limit of threads to fetch.
264
+ # @param [Time] before The time before which the threads are created.
265
+ #
266
+ # @return [Async::Task<Array<Discorb::ThreadChannel>>] The joined archived private threads in the channel.
267
+ #
268
+ def fetch_joined_archived_private_threads(limit: nil, before: nil)
269
+ Async do
270
+ if limit.nil?
271
+ before = Time.now
272
+ threads = []
273
+ loop do
274
+ _resp, data = @client.http.request(
275
+ Route.new(
276
+ "/channels/#{@id}/users/@me/threads/archived/private?before=#{before.iso8601}",
277
+ "//channels/:channel_id/users/@me/threads/archived/private",
278
+ :get
279
+ )
280
+ ).wait
281
+ threads += data[:threads].map { |thread| Channel.make_channel(@client, thread) }
282
+
283
+ break unless data[:has_more]
284
+
285
+ before = Snowflake.new(data[:threads][-1][:id]).timestamp
286
+ end
287
+ threads
288
+ else
289
+ _resp, data = @client.http.request(
290
+ Route.new(
291
+ "/channels/#{@id}/users/@me/threads/archived/private?limit=#{limit}&before=#{before.iso8601}",
292
+ "//channels/:channel_id/users/@me/threads/archived/private",
293
+ :get
294
+ )
295
+ ).wait
296
+ data.map { |thread| Channel.make_channel(@client, thread) }
297
+ end
298
+ end
299
+ end
300
+
301
+ private
302
+
303
+ def _set_data(data)
304
+ @topic = data[:topic]
305
+ @nsfw = data[:nsfw]
306
+ @last_message_id = data[:last_message_id]
307
+ @rate_limit_per_user = data[:rate_limit_per_user]
308
+ @last_pin_timestamp = data[:last_pin_timestamp] && Time.iso8601(data[:last_pin_timestamp])
309
+ @default_auto_archive_duration = data[:default_auto_archive_duration]
310
+ super
311
+ end
312
+ end
313
+
314
+ #
315
+ # Represents a news channel (announcement channel).
316
+ #
317
+ class NewsChannel < TextChannel
318
+ @channel_type = 5
319
+
320
+ #
321
+ # Follow the existing announcement channel from self.
322
+ # @async
323
+ #
324
+ # @param [Discorb::TextChannel] target The channel to follow to.
325
+ # @param [String] reason The reason of following the channel.
326
+ #
327
+ # @return [Async::Task<void>] The task.
328
+ #
329
+ def follow_to(target, reason: nil)
330
+ Async do
331
+ @client.http.request(Route.new("/channels/#{@id}/followers", "//channels/:channel_id/followers", :post),
332
+ { webhook_channel_id: target.id }, audit_log_reason: reason).wait
333
+ end
334
+ end
335
+ end
336
+ end
@@ -0,0 +1,325 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Represents a thread.
6
+ # @abstract
7
+ #
8
+ class ThreadChannel < Channel
9
+ # @return [Discorb::Snowflake] The ID of the channel.
10
+ # @note This ID is same as the starter message's ID
11
+ attr_reader :id
12
+ # @return [String] The name of the thread.
13
+ attr_reader :name
14
+ # @return [Integer] The number of messages in the thread.
15
+ # @note This will stop counting at 50.
16
+ attr_reader :message_count
17
+ # @return [Integer] The number of recipients in the thread.
18
+ # @note This will stop counting at 50.
19
+ attr_reader :member_count
20
+ alias recipient_count member_count
21
+ # @return [Integer] The rate limit per user (slowmode) in the thread.
22
+ attr_reader :rate_limit_per_user
23
+ alias slowmode rate_limit_per_user
24
+ # @return [Array<Discorb::ThreadChannel::Member>] The members of the thread.
25
+ attr_reader :members
26
+ # @return [Time] The time the thread was archived.
27
+ # @return [nil] If the thread is not archived.
28
+ attr_reader :archived_timestamp
29
+ alias archived_at archived_timestamp
30
+ # @return [Integer] Auto archive duration in seconds.
31
+ attr_reader :auto_archive_duration
32
+ alias archive_in auto_archive_duration
33
+ # @return [Boolean] Whether the thread is archived or not.
34
+ attr_reader :archived
35
+ alias archived? archived
36
+
37
+ # @!attribute [r] parent
38
+ # @macro client_cache
39
+ # @return [Discorb::GuildChannel] The parent channel of the thread.
40
+ # @!attribute [r] me
41
+ # @return [Discorb::ThreadChannel::Member] The bot's member in the thread.
42
+ # @return [nil] If the bot is not in the thread.
43
+ # @!attribute [r] joined?
44
+ # @return [Boolean] Whether the bot is in the thread or not.
45
+ # @!attribute [r] guild
46
+ # @macro client_cache
47
+ # @return [Discorb::Guild] The guild of the thread.
48
+ # @!attribute [r] owner
49
+ # @macro client_cache
50
+ # @macro members_intent
51
+ # @return [Discorb::Member] The owner of the thread.
52
+
53
+ include Messageable
54
+ @channel_type = nil
55
+
56
+ #
57
+ # Initialize a new thread channel.
58
+ # @private
59
+ #
60
+ # @param [Discorb::Client] client The client.
61
+ # @param [Hash] data The data of the thread channel.
62
+ # @param [Boolean] no_cache Whether to disable the cache.
63
+ #
64
+ def initialize(client, data, no_cache: false)
65
+ @members = Dictionary.new
66
+ super
67
+ @client.channels[@id] = self unless no_cache
68
+ end
69
+
70
+ #
71
+ # Edit the thread.
72
+ # @async
73
+ # @macro edit
74
+ #
75
+ # @param [String] name The name of the thread.
76
+ # @param [Boolean] archived Whether the thread is archived or not.
77
+ # @param [Integer] auto_archive_duration The auto archive duration in seconds.
78
+ # @param [Integer] archive_in Alias of `auto_archive_duration`.
79
+ # @param [Boolean] locked Whether the thread is locked or not.
80
+ # @param [String] reason The reason of editing the thread.
81
+ #
82
+ # @return [Async::Task<self>] The edited thread.
83
+ #
84
+ # @see #archive
85
+ # @see #lock
86
+ # @see #unarchive
87
+ # @see #unlock
88
+ #
89
+ def edit(
90
+ name: Discorb::Unset,
91
+ archived: Discorb::Unset,
92
+ auto_archive_duration: Discorb::Unset,
93
+ archive_in: Discorb::Unset,
94
+ locked: Discorb::Unset,
95
+ reason: nil
96
+ )
97
+ Async do
98
+ payload = {}
99
+ payload[:name] = name if name != Discorb::Unset
100
+ payload[:archived] = archived if archived != Discorb::Unset
101
+ auto_archive_duration ||= archive_in
102
+ payload[:auto_archive_duration] = auto_archive_duration if auto_archive_duration != Discorb::Unset
103
+ payload[:locked] = locked if locked != Discorb::Unset
104
+ @client.http.request(Route.new("/channels/#{@id}", "//channels/:channel_id", :patch), payload,
105
+ audit_log_reason: reason).wait
106
+ self
107
+ end
108
+ end
109
+
110
+ #
111
+ # Helper method to archive the thread.
112
+ #
113
+ # @param [String] reason The reason of archiving the thread.
114
+ #
115
+ # @return [Async::Task<self>] The archived thread.
116
+ #
117
+ def archive(reason: nil)
118
+ edit(archived: true, reason: reason)
119
+ end
120
+
121
+ #
122
+ # Helper method to lock the thread.
123
+ #
124
+ # @param [String] reason The reason of locking the thread.
125
+ #
126
+ # @return [Async::Task<self>] The locked thread.
127
+ #
128
+ def lock(reason: nil)
129
+ edit(archived: true, locked: true, reason: reason)
130
+ end
131
+
132
+ #
133
+ # Helper method to unarchive the thread.
134
+ #
135
+ # @param [String] reason The reason of unarchiving the thread.
136
+ #
137
+ # @return [Async::Task<self>] The unarchived thread.
138
+ #
139
+ def unarchive(reason: nil)
140
+ edit(archived: false, reason: reason)
141
+ end
142
+
143
+ #
144
+ # Helper method to unlock the thread.
145
+ #
146
+ # @param [String] reason The reason of unlocking the thread.
147
+ #
148
+ # @return [Async::Task<self>] The unlocked thread.
149
+ #
150
+ # @note This method won't unarchive the thread. Use {#unarchive} instead.
151
+ #
152
+ def unlock(reason: nil)
153
+ edit(archived: !unarchive, locked: false, reason: reason)
154
+ end
155
+
156
+ def parent
157
+ return nil unless @parent_id
158
+
159
+ @client.channels[@parent_id]
160
+ end
161
+
162
+ alias channel parent
163
+
164
+ def me
165
+ @members[@client.user.id]
166
+ end
167
+
168
+ def joined?
169
+ !!me
170
+ end
171
+
172
+ def guild
173
+ @client.guilds[@guild]
174
+ end
175
+
176
+ def owner
177
+ guild.members[@owner_id]
178
+ end
179
+
180
+ def inspect
181
+ "#<#{self.class} \"##{@name}\" id=#{@id}>"
182
+ end
183
+
184
+ #
185
+ # Add a member to the thread.
186
+ #
187
+ # @param [Discorb::Member, :me] member The member to add. If `:me` is given, the bot will be added.
188
+ #
189
+ # @return [Async::Task<void>] The task.
190
+ #
191
+ def add_member(member = :me)
192
+ Async do
193
+ if member == :me
194
+ @client.http.request(Route.new("/channels/#{@id}/thread-members/@me",
195
+ "//channels/:channel_id/thread-members/@me", :post)).wait
196
+ else
197
+ @client.http.request(Route.new("/channels/#{@id}/thread-members/#{Utils.try(member, :id)}",
198
+ "//channels/:channel_id/thread-members/:user_id", :post)).wait
199
+ end
200
+ end
201
+ end
202
+
203
+ alias join add_member
204
+
205
+ #
206
+ # Remove a member from the thread.
207
+ #
208
+ # @param [Discorb::Member, :me] member The member to remove. If `:me` is given, the bot will be removed.
209
+ #
210
+ # @return [Async::Task<void>] The task.
211
+ #
212
+ def remove_member(member = :me)
213
+ Async do
214
+ if member == :me
215
+ @client.http.request(Route.new("/channels/#{@id}/thread-members/@me",
216
+ "//channels/:channel_id/thread-members/@me", :delete)).wait
217
+ else
218
+ @client.http.request(Route.new("/channels/#{@id}/thread-members/#{Utils.try(member, :id)}",
219
+ "//channels/:channel_id/thread-members/:user_id", :delete)).wait
220
+ end
221
+ end
222
+ end
223
+
224
+ alias leave remove_member
225
+
226
+ #
227
+ # Fetch members in the thread.
228
+ #
229
+ # @return [Array<Discorb::ThreadChannel::Member>] The members in the thread.
230
+ #
231
+ def fetch_members
232
+ Async do
233
+ _resp, data = @client.http.request(Route.new("/channels/#{@id}/thread-members",
234
+ "//channels/:channel_id/thread-members", :get)).wait
235
+ data.map { |d| @members[d[:id]] = Member.new(@client, d, @guild_id) }
236
+ end
237
+ end
238
+
239
+ #
240
+ # Represents a thread in news channel(aka announcement channel).
241
+ #
242
+ class News < ThreadChannel
243
+ @channel_type = 10
244
+ end
245
+
246
+ #
247
+ # Represents a public thread in text channel.
248
+ #
249
+ class Public < ThreadChannel
250
+ @channel_type = 11
251
+ end
252
+
253
+ #
254
+ # Represents a private thread in text channel.
255
+ #
256
+ class Private < ThreadChannel
257
+ @channel_type = 12
258
+ end
259
+
260
+ class << self
261
+ attr_reader :channel_type
262
+ end
263
+
264
+ #
265
+ # Represents a member in a thread.
266
+ #
267
+ class Member < DiscordModel
268
+ attr_reader :joined_at
269
+
270
+ def initialize(client, data, guild_id)
271
+ @client = client
272
+ @thread_id = data[:id]
273
+ @user_id = data[:user_id]
274
+ @joined_at = Time.iso8601(data[:join_timestamp])
275
+ @guild_id = guild_id
276
+ end
277
+
278
+ def thread
279
+ @client.channels[@thread_id]
280
+ end
281
+
282
+ def member
283
+ @client.guilds[@guild_id].members[@user_id]
284
+ end
285
+
286
+ def id
287
+ @user_id
288
+ end
289
+
290
+ def user
291
+ @client.users[@user_id]
292
+ end
293
+
294
+ def inspect
295
+ "#<#{self.class} id=#{@id.inspect}>"
296
+ end
297
+ end
298
+
299
+ private
300
+
301
+ def _set_data(data)
302
+ @id = Snowflake.new(data[:id])
303
+ @name = data[:name]
304
+ @guild_id = data[:guild_id]
305
+ @parent_id = data[:parent_id]
306
+ @archived = data[:thread_metadata][:archived]
307
+ @owner_id = data[:owner_id]
308
+ @archived_timestamp =
309
+ data[:thread_metadata][:archived_timestamp] && Time.iso8601(data[:thread_metadata][:archived_timestamp])
310
+ @auto_archive_duration = data[:thread_metadata][:auto_archive_duration]
311
+ @locked = data[:thread_metadata][:locked]
312
+ @member_count = data[:member_count]
313
+ @message_count = data[:message_count]
314
+ if data[:member]
315
+ @members[@client.user.id] =
316
+ ThreadChannel::Member.new(
317
+ @client,
318
+ data[:member].merge({ id: data[:id], user_id: @client.user.id }),
319
+ @guild_id
320
+ )
321
+ end
322
+ @data.merge!(data)
323
+ end
324
+ end
325
+ end