discorb 0.0.1

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.
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,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ # @!visibility private
5
+ module Utils
6
+ def try(object, message, ...)
7
+ if object.respond_to?(message)
8
+ object.send(message, ...)
9
+ else
10
+ object
11
+ end
12
+ end
13
+
14
+ module_function :try
15
+ end
16
+ end
@@ -0,0 +1,251 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ class VoiceState < DiscordModel
5
+ # @return [Discorb::Member] The member associated with this voice state.
6
+ attr_reader :member
7
+ # @return [Discorb::Snowflake] The ID of the guild this voice state is for.
8
+ attr_reader :session_id
9
+ # @return [Time] The time at which the user requested to speak.
10
+ attr_reader :request_to_speak_timestamp
11
+ # @return [Boolean] Whether the user is deafened.
12
+ attr_reader :self_deaf
13
+ alias self_deaf? self_deaf
14
+ # @return [Boolean] Whether the user is muted.
15
+ attr_reader :self_mute
16
+ alias self_mute? self_mute
17
+ # @return [Boolean] Whether the user is streaming.
18
+ attr_reader :self_stream
19
+ alias stream? self_stream
20
+ alias live? stream?
21
+ # @return [Boolean] Whether the user is video-enabled.
22
+ attr_reader :self_video
23
+ alias video? self_video
24
+ # @return [Boolean] Whether the user is suppressed. (Is at audience)
25
+ attr_reader :suppress
26
+ alias suppress? suppress
27
+
28
+ # @!attribute [r] deaf?
29
+ # @return [Boolean] Whether the user is deafened.
30
+ # @!attribute [r] mute?
31
+ # @return [Boolean] Whether the user is muted.
32
+ # @!attribute [r] server_deaf?
33
+ # @return [Boolean] Whether the user is deafened on the server.
34
+ # @!attribute [r] server_mute?
35
+ # @return [Boolean] Whether the user is muted on the server.
36
+ # @!attribute [r] guild
37
+ # @macro client_cache
38
+ # @return [Discorb::Guild] The guild this voice state is for.
39
+ # @!attribute [r] channel
40
+ # @macro client_cache
41
+ # @return [Discorb::Channel] The channel this voice state is for.
42
+ # @!attribute [r] user
43
+ # @macro client_cache
44
+ # @return [Discorb::User] The user this voice state is for.
45
+
46
+ # @!visibility private
47
+ def initialize(client, data)
48
+ @client = client
49
+ _set_data(data)
50
+ end
51
+
52
+ def deaf?
53
+ @deaf || @self_deaf
54
+ end
55
+
56
+ def mute?
57
+ @mute || @self_mute
58
+ end
59
+
60
+ def server_deaf?
61
+ @deaf
62
+ end
63
+
64
+ def server_mute?
65
+ @mute
66
+ end
67
+
68
+ def guild
69
+ @guild_id && @client.guilds[@guild_id]
70
+ end
71
+
72
+ def channel
73
+ @channel_id && @client.channels[@channel_id]
74
+ end
75
+
76
+ def user
77
+ @client.users[@user_id]
78
+ end
79
+
80
+ private
81
+
82
+ def _set_data(data)
83
+ @data = data
84
+ @guild_id = data[:guild_id]
85
+ @channel_id = data[:channel_id]
86
+ @user_id = data[:user_id]
87
+ unless guild.nil?
88
+ @member = if data.key?(:member)
89
+ guild.members[data[:user_id]] || Member.new(@client, @guild_id, data[:member][:user], data[:member])
90
+ else
91
+ guild.members[data[:user_id]]
92
+ end
93
+ end
94
+ @session_id = data[:session_id]
95
+ @deaf = data[:deaf]
96
+ @mute = data[:mute]
97
+ @self_deaf = data[:self_deaf]
98
+ @self_mute = data[:self_mute]
99
+ @self_stream = data[:self_stream]
100
+ @self_video = data[:self_video]
101
+ @suppress = data[:suppress]
102
+ @request_to_speak_timestamp = data[:request_to_speak_timestamp] && Time.iso8601(data[:request_to_speak_timestamp])
103
+ end
104
+ end
105
+
106
+ #
107
+ # Represents a stage instance of a voice state.
108
+ #
109
+ class StageInstance < DiscordModel
110
+ # @return [Discorb::Snowflake] The ID of the guild this voice state is for.
111
+ attr_reader :id
112
+ # @return [String] The topic of the stage instance.
113
+ attr_reader :topic
114
+ # @return [:public, :guild_only] The privacy level of the stage instance.
115
+ attr_reader :privacy_level
116
+
117
+ # @!attribute [r] guild
118
+ # @macro client_cache
119
+ # @return [Discorb::Guild] The guild this voice state is for.
120
+ # @!attribute [r] channel
121
+ # @macro client_cache
122
+ # @return [Discorb::Channel] The channel this voice state is for.
123
+ # @!attribute [r] discoverable?
124
+ # @return [Boolean] Whether the stage instance is discoverable.
125
+ # @!attribute [r] public?
126
+ # @return [Boolean] Whether the stage instance is public.
127
+ # @!attribute [r] guild_only?
128
+ # @return [Boolean] Whether the stage instance is guild-only.
129
+
130
+ @privacy_level = {
131
+ 1 => :public,
132
+ 2 => :guild_only,
133
+ }
134
+
135
+ # @!visibility private
136
+ def initialize(client, data, no_cache: false)
137
+ @client = client
138
+ @data = data
139
+ _set_data(data)
140
+ channel.stage_instances[@id] = self unless no_cache
141
+ end
142
+
143
+ def guild
144
+ @client.guilds[@data[:guild_id]]
145
+ end
146
+
147
+ def channel
148
+ @client.channels[@data[:channel_id]]
149
+ end
150
+
151
+ def discoverable?
152
+ !@discoverable_disabled
153
+ end
154
+
155
+ def public?
156
+ @privacy_level == :public
157
+ end
158
+
159
+ def guild_only?
160
+ @privacy_level == :guild_only
161
+ end
162
+
163
+ def inspect
164
+ "#<#{self.class} topic=#{@topic.inspect}>"
165
+ end
166
+
167
+ #
168
+ # Edits the stage instance.
169
+ # @macro async
170
+ # @macro http
171
+ # @macro edit
172
+ #
173
+ # @param [String] topic The new topic of the stage instance.
174
+ # @param [:public, :guild_only] privacy_level The new privacy level of the stage instance.
175
+ # @param [String] reason The reason for editing the stage instance.
176
+ #
177
+ def edit(topic: :unset, privacy_level: :unset, reason: nil)
178
+ Async do
179
+ payload = {}
180
+ payload[:topic] = topic if topic != :unset
181
+ payload[:privacy_level] = self.class.privacy_level.key(privacy_level) if privacy_level != :unset
182
+ @client.internet.edit("/stage-instances/#{@channel_id}", payload, audit_log_reason: reason).wait
183
+ self
184
+ end
185
+ end
186
+
187
+ alias modify edit
188
+
189
+ #
190
+ # Deletes the stage instance.
191
+ #
192
+ # @param [String] reason The reason for deleting the stage instance.
193
+ #
194
+ def delete!(reason: nil)
195
+ Async do
196
+ @client.internet.delete("/stage-instances/#{@channel_id}", reason: reason).wait
197
+ self
198
+ end
199
+ end
200
+
201
+ alias destroy! delete!
202
+ alias end! delete!
203
+
204
+ private
205
+
206
+ def _set_data(data)
207
+ @id = Snowflake.new(data[:id])
208
+ @guild_id = Snowflake.new(data[:guild_id])
209
+ @channel_id = Snowflake.new(data[:channel_id])
210
+ @topic = data[:topic]
211
+ @privacy_level = self.class.privacy_level[data[:privacy_level]]
212
+ @discoverable_disabled = data[:discoverable_disabled]
213
+ end
214
+
215
+ class << self
216
+ attr_reader :privacy_level
217
+ end
218
+ end
219
+
220
+ #
221
+ # Represents a voice region.
222
+ #
223
+ class VoiceRegion < DiscordModel
224
+ # @return [Discorb::Snowflake] The ID of the voice region.
225
+ attr_reader :id
226
+ # @return [String] The name of the voice region.
227
+ attr_reader :name
228
+ # @return [Boolean] Whether the voice region is VIP.
229
+ attr_reader :vip
230
+ alias vip? vip
231
+ # @return [Boolean] Whether the voice region is optimal.
232
+ attr_reader :optimal
233
+ alias optimal? optimal
234
+ # @return [Boolean] Whether the voice region is deprecated.
235
+ attr_reader :deprecated
236
+ alias deprecated? deprecated
237
+ # @return [Boolean] Whether the voice region is custom.
238
+ attr_reader :custom
239
+ alias custom? custom
240
+
241
+ # @!visibility private
242
+ def initialize(data)
243
+ @id = data[:id]
244
+ @name = data[:name]
245
+ @vip = data[:vip]
246
+ @optimal = data[:optimal]
247
+ @deprecated = data[:deprecated]
248
+ @custom = data[:custom]
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,420 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "async/http/internet"
4
+
5
+ module Discorb
6
+ #
7
+ # Represents a webhook.
8
+ # @abstract
9
+ #
10
+ class Webhook
11
+ # @return [String] The name of the webhook.
12
+ attr_reader :name
13
+ # @return [Discorb::Snowflake] The ID of the guild this webhook belongs to.
14
+ attr_reader :guild_id
15
+ # @return [Discorb::Snowflake] The ID of the channel this webhook belongs to.
16
+ attr_reader :channel_id
17
+ # @return [Discorb::User] The user that created this webhook.
18
+ attr_reader :user
19
+ # @return [Discorb::Asset] The avatar of the webhook.
20
+ attr_reader :avatar
21
+ # @return [Discorb::Snowflake] The application ID of the webhook.
22
+ # @return [nil] If the webhook is not an application webhook.
23
+ attr_reader :application_id
24
+ # @return [String] The URL of the webhook.
25
+ attr_reader :token
26
+
27
+ # @!visibility private
28
+ def initialize(client, data)
29
+ @name = data[:name]
30
+ @guild_id = data[:guild_id] && Snowflake.new(data[:guild_id])
31
+ @channel_id = Snowflake.new(data[:channel_id])
32
+ @id = Snowflake.new(data[:id])
33
+ @user = data[:user]
34
+ @name = data[:name]
35
+ @avatar = Asset.new(self, data[:avatar])
36
+ @token = ""
37
+ @application_id = data[:application_id]
38
+ @client = client
39
+ @internet = Discorb::Internet.new(client)
40
+ end
41
+
42
+ def inspect
43
+ "#<#{self.class} #{@name.inspect} id=#{@id}>"
44
+ end
45
+
46
+ #
47
+ # Posts a message to the webhook.
48
+ # @macro async
49
+ # @macro http
50
+ #
51
+ # @param [String] content The content of the message.
52
+ # @param [Boolean] tts Whether the message should be sent as text-to-speech.
53
+ # @param [Discorb::Embed] embed The embed to send.
54
+ # @param [Array<Discorb::Embed>] embeds The embeds to send.
55
+ # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions to send.
56
+ # @param [Discorb::File] file The file to send.
57
+ # @param [Array<Discorb::File>] files The files to send.
58
+ # @param [String] username The username of the message.
59
+ # @param [String] avatar_url The avatar URL of the message.
60
+ # @param [Boolean] wait Whether to wait for the message to be sent.
61
+ #
62
+ # @return [Discorb::Webhook::Message] The message that was sent.
63
+ # @return [nil] If `wait` is false.
64
+ #
65
+ def post(content = nil, tts: false, embed: nil, embeds: nil, allowed_mentions: nil,
66
+ file: nil, files: nil, username: nil, avatar_url: :unset, wait: true)
67
+ Async do |_task|
68
+ payload = {}
69
+ payload[:content] = content if content
70
+ payload[:tts] = tts
71
+ tmp_embed = if embed
72
+ [embed]
73
+ elsif embeds
74
+ embeds
75
+ end
76
+ payload[:embeds] = tmp_embed.map(&:to_hash) if tmp_embed
77
+ payload[:allowed_mentions] = allowed_mentions&.to_hash
78
+ payload[:username] = username if username
79
+ payload[:avatar_url] = avatar_url if avatar_url != :unset
80
+ files = [file] if file
81
+ if files
82
+ headers, payload = Internet.multipart(payload, files)
83
+ else
84
+ headers = {
85
+ "Content-Type" => "application/json",
86
+ }
87
+ end
88
+ _resp, data = @internet.post("#{url}?wait=#{wait}", payload, headers: headers).wait
89
+
90
+ data && Webhook::Message.new(self, data)
91
+ end
92
+ end
93
+
94
+ alias execute post
95
+
96
+ #
97
+ # Edits the webhook.
98
+ # @macro async
99
+ # @macro http
100
+ # @macro edit
101
+ #
102
+ # @param [String] name The new name of the webhook.
103
+ # @param [Discorb::Image] avatar The new avatar of the webhook.
104
+ # @param [Discorb::GuildChannel] channel The new channel of the webhook.
105
+ #
106
+ def edit(name: :unset, avatar: :unset, channel: :unset)
107
+ Async do |_task|
108
+ payload = {}
109
+ payload[:name] = name if name != :unset
110
+ payload[:avatar] = avatar if avatar != :unset
111
+ payload[:channel_id] = Utils.try(channel, :id) if channel != :unset
112
+ @internet.patch(url.to_s, payload).wait
113
+ end
114
+ end
115
+
116
+ alias modify edit
117
+
118
+ #
119
+ # Deletes the webhook.
120
+ # @macro async
121
+ # @macro http
122
+ #
123
+ def delete!
124
+ Async do
125
+ @internet.delete(url).wait
126
+ self
127
+ end
128
+ end
129
+
130
+ alias destroy! delete!
131
+
132
+ #
133
+ # Edits the webhook's message.
134
+ # @macro async
135
+ # @macro http
136
+ # @macro edit
137
+ #
138
+ # @param [Discorb::Webhook::Message] message The message to edit.
139
+ # @param [String] content The new content of the message.
140
+ # @param [Discorb::Embed] embed The new embed of the message.
141
+ # @param [Array<Discorb::Embed>] embeds The new embeds of the message.
142
+ # @param [Array<Discorb::Attachment>] attachments The attachments to remain.
143
+ # @param [Discorb::File] file The file to send.
144
+ # @param [Array<Discorb::File>] files The files to send.
145
+ # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions to send.
146
+ #
147
+ def edit_message(
148
+ message, content = :unset,
149
+ embed: :unset, embeds: :unset,
150
+ file: :unset, files: :unset,
151
+ attachments: :unset,
152
+ allowed_mentions: :unset
153
+ )
154
+ Async do
155
+ payload = {}
156
+ payload[:content] = content if content != :unset
157
+ payload[:embeds] = embed ? [embed.to_hash] : [] if embed != :unset
158
+ payload[:embeds] = embeds.map(&:to_hash) if embeds != :unset
159
+ attachments = [attachment] if attachment != :unset
160
+ payload[:attachments] = attachments.map(&:to_hash) if attachments != :unset
161
+ payload[:allowed_mentions] = allowed_mentions if allowed_mentions != :unset
162
+ files = [file] if file != :unset
163
+ if files == :unset
164
+ headers = {
165
+ "Content-Type" => "application/json",
166
+ }
167
+ else
168
+ headers, payload = Internet.multipart(payload, files)
169
+ end
170
+ _resp, data = @internet.patch("#{url}/messages/#{Utils.try(message, :id)}", payload, headers: headers).wait
171
+ message.send(:_set_data, data)
172
+ message
173
+ end
174
+ end
175
+
176
+ #
177
+ # Deletes the webhook's message.
178
+ #
179
+ # @param [Discorb::Webhook::Message] message The message to delete.
180
+ #
181
+ def delete_message!(message)
182
+ Async do
183
+ @internet.delete("#{url}/messages/#{Utils.try(message, :id)}").wait
184
+ message
185
+ end
186
+ end
187
+
188
+ #
189
+ # Represents a webhook from URL.
190
+ #
191
+ class URLWebhook < Webhook
192
+ # @return [String] The URL of the webhook.
193
+ attr_reader :url
194
+
195
+ #
196
+ # Initializes the webhook from URL.
197
+ #
198
+ # @param [String] url The URL of the webhook.
199
+ #
200
+ def initialize(url)
201
+ @url = url
202
+ @token = ""
203
+ @internet = Discorb::Internet.new(self)
204
+ end
205
+ end
206
+
207
+ #
208
+ # Represents a bot created webhook.
209
+ #
210
+ class IncomingWebhook < Webhook
211
+ # @!attribute [r] url
212
+ # @return [String] The URL of the webhook.
213
+
214
+ # @!visibility private
215
+ def initialize(client, data)
216
+ super
217
+ @token = data[:token]
218
+ end
219
+
220
+ def url
221
+ "https://discord.com/api/v9/webhooks/#{@id}/#{@token}"
222
+ end
223
+ end
224
+
225
+ #
226
+ # Represents a webhook of channel following.
227
+ #
228
+ class FollowerWebhook < Webhook
229
+ # @!attribute [r] source_guild
230
+ # Represents a source guild of follower webhook.
231
+ # @return [Discorb::Guild, Discorb::Webhook::FollowerWebhook::Guild] The source guild of follower webhook.
232
+ # @!attribute [r] source_channel
233
+ # Represents a source channel of follower webhook.
234
+ # @return [Discorb::Channel, Discorb::Webhook::FollowerWebhook::Channel] The source channel of follower webhook.
235
+
236
+ # @!visibility private
237
+ def initialize(client, data)
238
+ super
239
+ @source_guild = FollowerWebhook::Guild.new(data[:source_guild])
240
+ @source_channel = FollowerWebhook::Channel.new(data[:source_channel])
241
+ end
242
+
243
+ def source_guild
244
+ @client.guilds[@source_guild.id] || @source_guild
245
+ end
246
+
247
+ def source_channel
248
+ @client.channels[@source_channel.id] || @source_channel
249
+ end
250
+
251
+ #
252
+ # Represents a guild of follower webhook.
253
+ #
254
+ class Guild < DiscordModel
255
+ # @return [Discorb::Snowflake] The ID of the guild.
256
+ attr_reader :id
257
+ # @return [String] The name of the guild.
258
+ attr_reader :name
259
+ # @return [Discorb::Asset] The icon of the guild.
260
+ attr_reader :icon
261
+
262
+ # @!visibility private
263
+ def initialize(data)
264
+ @id = Snowflake.new(data[:id])
265
+ @name = data[:name]
266
+ @icon = Asset.new(self, data[:icon])
267
+ end
268
+ end
269
+
270
+ #
271
+ # Represents a channel of follower webhook.
272
+ #
273
+ class Channel < DiscordModel
274
+ # @return [Discorb::Snowflake] The ID of the channel.
275
+ attr_reader :id
276
+ # @return [String] The name of the channel.
277
+ attr_reader :name
278
+
279
+ # @!visibility private
280
+ def initialize(data)
281
+ @id = Snowflake.new(data[:id])
282
+ @name = data[:name]
283
+ end
284
+ end
285
+ end
286
+
287
+ #
288
+ # Represents a webhook from oauth2.
289
+ #
290
+ class ApplicationWebhook < Webhook
291
+ end
292
+
293
+ # private
294
+
295
+ #
296
+ # Represents a webhook message.
297
+ #
298
+ class Message < Discorb::Message
299
+ # @return [Discorb::Snowflake] The ID of the channel.
300
+ attr_reader :channel_id
301
+ # @return [Discorb::Snowflake] The ID of the guild.
302
+ attr_reader :guild_id
303
+
304
+ # @!visibility private
305
+ def initialize(webhook, data, client = nil)
306
+ @client = client
307
+ @webhook = webhook
308
+ @data = data
309
+ _set_data(data)
310
+ end
311
+
312
+ #
313
+ # Edits the message.
314
+ # @macro async
315
+ # @macro http
316
+ # @macro edit
317
+ #
318
+ # @param (see Webhook#edit_message)
319
+ #
320
+ def edit(...)
321
+ Async do
322
+ @webhook.edit_message(self, ...).wait
323
+ end
324
+ end
325
+
326
+ #
327
+ # Deletes the message.
328
+ # @macro async
329
+ # @macro http
330
+ #
331
+ def delete!
332
+ Async do
333
+ @webhook.delete_message!(self).wait
334
+ end
335
+ end
336
+
337
+ private
338
+
339
+ def _set_data(data)
340
+ @id = Snowflake.new(data[:id])
341
+ @type = Discorb::Message.message_type[data[:type]]
342
+ @content = data[:content]
343
+ @channel_id = Snowflake.new(data[:channel_id])
344
+ @author = Author.new(data[:author])
345
+ @attachments = data[:attachments].map { |a| Attachment.new(a) }
346
+ @embeds = data[:embeds] ? data[:embeds].map { |e| Embed.new(data: e) } : []
347
+ @mentions = data[:mentions].map { |m| Mention.new(m) }
348
+ @mention_roles = data[:mention_roles].map { |m| Snowflake.new(m) }
349
+ @mention_everyone = data[:mention_everyone]
350
+ @pinned = data[:pinned]
351
+ @tts = data[:tts]
352
+ @created_at = data[:edited_timestamp] && Time.iso8601(data[:timestamp])
353
+ @updated_at = data[:edited_timestamp] && Time.iso8601(data[:edited_timestamp])
354
+ @flags = Message::Flag.new(data[:flags])
355
+ @webhook_id = Snowflake.new(data[:webhook_id])
356
+ end
357
+
358
+ #
359
+ # Represents an author of webhook message.
360
+ #
361
+ class Author < DiscordModel
362
+ # @return [Boolean] Whether the author is a bot.
363
+ # @note This will be always `true`.
364
+ attr_reader :bot
365
+ # @return [Discorb::Snowflake] The ID of the author.
366
+ attr_reader :id
367
+ # @return [String] The name of the author.
368
+ attr_reader :username
369
+ alias name username
370
+ # @return [Discorb::Asset] The avatar of the author.
371
+ attr_reader :avatar
372
+ # @return [String] The discriminator of the author.
373
+ attr_reader :discriminator
374
+
375
+ # @!visibility private
376
+ def initialize(data)
377
+ @data = data
378
+ @bot = data[:bot]
379
+ @id = Snowflake.new(data[:id])
380
+ @username = data[:username]
381
+ @avatar = data[:avatar]
382
+ @discriminator = data[:discriminator]
383
+ end
384
+ end
385
+ end
386
+
387
+ class << self
388
+ #
389
+ # Creates URLWebhook.
390
+ #
391
+ # @param [String] url The URL of the webhook.
392
+ #
393
+ # @return [Discorb::Webhook::URLWebhook] The URLWebhook.
394
+ #
395
+ def new(url)
396
+ if self != Webhook
397
+ return super(*url) if url.is_a?(Array)
398
+
399
+ return super
400
+ end
401
+ if url.is_a?(String)
402
+ URLWebhook.new(url)
403
+ else
404
+ case url[1][:type]
405
+ when 1
406
+ IncomingWebhook
407
+ when 2
408
+ FollowerWebhook
409
+ when 3
410
+ ApplicationWebhook
411
+ end.new(url)
412
+ end
413
+ end
414
+
415
+ def from_url(url)
416
+ URLWebhook.new(url)
417
+ end
418
+ end
419
+ end
420
+ end