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,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