discorb 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.github/workflows/build_version.yml +3 -3
  4. data/.github/workflows/codeql-analysis.yml +70 -0
  5. data/.github/workflows/lint-push.yml +18 -0
  6. data/.github/workflows/lint.yml +16 -0
  7. data/.rubocop.yml +70 -0
  8. data/CODE_OF_CONDUCT.md +128 -0
  9. data/Changelog.md +33 -0
  10. data/Gemfile +7 -3
  11. data/README.md +1 -1
  12. data/Rakefile +35 -35
  13. data/discorb.gemspec +13 -1
  14. data/examples/commands/bookmarker.rb +2 -1
  15. data/examples/commands/hello.rb +1 -0
  16. data/examples/commands/inspect.rb +3 -2
  17. data/examples/components/authorization_button.rb +2 -1
  18. data/examples/components/select_menu.rb +2 -1
  19. data/examples/extension/main.rb +1 -0
  20. data/examples/extension/message_expander.rb +1 -0
  21. data/examples/simple/eval.rb +3 -2
  22. data/examples/simple/ping_pong.rb +1 -0
  23. data/examples/simple/rolepanel.rb +1 -0
  24. data/examples/simple/wait_for_message.rb +4 -3
  25. data/exe/discorb +8 -7
  26. data/lib/discorb/allowed_mentions.rb +64 -0
  27. data/lib/discorb/app_command/command.rb +274 -0
  28. data/lib/discorb/app_command/handler.rb +168 -0
  29. data/lib/discorb/app_command.rb +2 -404
  30. data/lib/discorb/asset.rb +3 -1
  31. data/lib/discorb/audit_logs.rb +3 -3
  32. data/lib/discorb/channel.rb +89 -53
  33. data/lib/discorb/client.rb +36 -33
  34. data/lib/discorb/common.rb +28 -21
  35. data/lib/discorb/components/button.rb +106 -0
  36. data/lib/discorb/components/select_menu.rb +157 -0
  37. data/lib/discorb/components/text_input.rb +96 -0
  38. data/lib/discorb/components.rb +11 -276
  39. data/lib/discorb/dictionary.rb +13 -2
  40. data/lib/discorb/embed.rb +2 -2
  41. data/lib/discorb/emoji.rb +21 -5
  42. data/lib/discorb/emoji_table.rb +1 -1
  43. data/lib/discorb/error.rb +4 -6
  44. data/lib/discorb/event.rb +13 -11
  45. data/lib/discorb/exe/about.rb +1 -0
  46. data/lib/discorb/exe/irb.rb +4 -3
  47. data/lib/discorb/exe/new.rb +6 -7
  48. data/lib/discorb/exe/run.rb +2 -1
  49. data/lib/discorb/exe/setup.rb +8 -5
  50. data/lib/discorb/exe/show.rb +1 -0
  51. data/lib/discorb/extend.rb +19 -14
  52. data/lib/discorb/extension.rb +5 -1
  53. data/lib/discorb/gateway.rb +75 -27
  54. data/lib/discorb/guild.rb +58 -80
  55. data/lib/discorb/guild_template.rb +5 -5
  56. data/lib/discorb/http.rb +34 -169
  57. data/lib/discorb/integration.rb +32 -3
  58. data/lib/discorb/intents.rb +1 -1
  59. data/lib/discorb/interaction/autocomplete.rb +5 -4
  60. data/lib/discorb/interaction/command.rb +34 -9
  61. data/lib/discorb/interaction/components.rb +5 -2
  62. data/lib/discorb/interaction/modal.rb +33 -0
  63. data/lib/discorb/interaction/response.rb +41 -12
  64. data/lib/discorb/interaction/root.rb +1 -0
  65. data/lib/discorb/interaction.rb +2 -1
  66. data/lib/discorb/invite.rb +1 -1
  67. data/lib/discorb/log.rb +4 -3
  68. data/lib/discorb/member.rb +4 -6
  69. data/lib/discorb/message.rb +31 -282
  70. data/lib/discorb/message_meta.rb +205 -0
  71. data/lib/discorb/modules.rb +11 -11
  72. data/lib/discorb/permission.rb +2 -2
  73. data/lib/discorb/presence.rb +6 -3
  74. data/lib/discorb/rate_limit.rb +15 -21
  75. data/lib/discorb/role.rb +3 -3
  76. data/lib/discorb/sticker.rb +2 -2
  77. data/lib/discorb/user.rb +3 -3
  78. data/lib/discorb/utils/colored_puts.rb +1 -0
  79. data/lib/discorb/voice_state.rb +7 -2
  80. data/lib/discorb/webhook.rb +8 -5
  81. data/lib/discorb.rb +1 -0
  82. data/template-replace/scripts/arrow.rb +1 -0
  83. data/template-replace/scripts/favicon.rb +1 -0
  84. data/template-replace/scripts/index.rb +2 -1
  85. data/template-replace/scripts/locale_ja.rb +5 -4
  86. data/template-replace/scripts/sidebar.rb +1 -0
  87. data/template-replace/scripts/version.rb +7 -10
  88. data/template-replace/scripts/yard_replace.rb +5 -4
  89. metadata +29 -4
data/lib/discorb/log.rb CHANGED
@@ -64,17 +64,18 @@ module Discorb
64
64
 
65
65
  def write_output(name, color, message, fallback)
66
66
  unless @out
67
- fallback.puts(message) if fallback
67
+ fallback&.puts(message)
68
68
 
69
69
  return
70
70
  end
71
71
 
72
72
  time = Time.now.iso8601
73
73
  if @colorize_log
74
- @out.puts("\e[90m#{time}\e[0m #{color}#{name.ljust(5)}\e[0m #{message}")
74
+ @out.write("\e[90m#{time}\e[0m #{color}#{name.ljust(5)}\e[0m #{message}\n")
75
75
  else
76
- @out.puts("#{time} #{name.ljust(5)} #{message}")
76
+ @out.write("#{time} #{name.ljust(5)} #{message}\n")
77
77
  end
78
+ @out.flush
78
79
  end
79
80
  end
80
81
  end
@@ -105,9 +105,7 @@ module Discorb
105
105
  end
106
106
 
107
107
  def permissions
108
- if owner?
109
- return Permission.new((1 << 38) - 1)
110
- end
108
+ return Permission.new((1 << 38) - 1) if owner?
111
109
  roles.map(&:permissions).sum(Permission.new(0))
112
110
  end
113
111
 
@@ -152,7 +150,7 @@ module Discorb
152
150
  #
153
151
  def add_role(role, reason: nil)
154
152
  Async do
155
- @client.http.put("/guilds/#{@guild_id}/members/#{@id}/roles/#{role.is_a?(Role) ? role.id : role}", nil, audit_log_reason: reason).wait
153
+ @client.http.request(Route.new("/guilds/#{@guild_id}/members/#{@id}/roles/#{role.is_a?(Role) ? role.id : role}", "//guilds/:guild_id/members/:user_id/roles/:role_id", :put), nil, audit_log_reason: reason).wait
156
154
  end
157
155
  end
158
156
 
@@ -167,7 +165,7 @@ module Discorb
167
165
  #
168
166
  def remove_role(role, reason: nil)
169
167
  Async do
170
- @client.http.delete("/guilds/#{@guild_id}/members/#{@id}/roles/#{role.is_a?(Role) ? role.id : role}", audit_log_reason: reason).wait
168
+ @client.http.request(Route.new("/guilds/#{@guild_id}/members/#{@id}/roles/#{role.is_a?(Role) ? role.id : role}", "//guilds/:guild_id/members/:user_id/roles/:role_id", :delete), audit_log_reason: reason).wait
171
169
  end
172
170
  end
173
171
 
@@ -200,7 +198,7 @@ module Discorb
200
198
  communication_disabled_until = timeout_until if timeout_until != Discorb::Unset
201
199
  payload[:communication_disabled_until] = communication_disabled_until&.iso8601 if communication_disabled_until != Discorb::Unset
202
200
  payload[:channel_id] = channel&.id if channel != Discorb::Unset
203
- @client.http.patch("/guilds/#{@guild_id}/members/#{@id}", payload, audit_log_reason: reason).wait
201
+ @client.http.request(Route.new("/guilds/#{@guild_id}/members/#{@id}", "//guilds/:guild_id/members/:user_id", :patch), payload, audit_log_reason: reason).wait
204
202
  end
205
203
  end
206
204
 
@@ -1,68 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Discorb
4
- #
5
- # Represents a allowed mentions in a message.
6
- #
7
- class AllowedMentions
8
- # @return [Boolean] Whether to allow @everyone or @here.
9
- attr_accessor :everyone
10
- # @return [Boolean, Array<Discorb::Role>] The roles to allow, or false to disable.
11
- attr_accessor :roles
12
- # @return [Boolean, Array<Discorb::User>] The users to allow, or false to disable.
13
- attr_accessor :users
14
- # @return [Boolean] Whether to ping the user that sent the message to reply.
15
- attr_accessor :replied_user
16
-
17
- #
18
- # Initializes a new instance of the AllowedMentions class.
19
- #
20
- # @param [Boolean] everyone Whether to allow @everyone or @here.
21
- # @param [Boolean, Array<Discorb::Role>] roles The roles to allow, or false to disable.
22
- # @param [Boolean, Array<Discorb::User>] users The users to allow, or false to disable.
23
- # @param [Boolean] replied_user Whether to ping the user that sent the message to reply.
24
- #
25
- def initialize(everyone: nil, roles: nil, users: nil, replied_user: nil)
26
- @everyone = everyone
27
- @roles = roles
28
- @users = users
29
- @replied_user = replied_user
30
- end
31
-
32
- def inspect
33
- "#<#{self.class} @everyone=#{@everyone} @roles=#{@roles} @users=#{@users} @replied_user=#{@replied_user}>"
34
- end
35
-
36
- # @private
37
- def to_hash(other = nil)
38
- payload = {
39
- parse: %w[everyone roles users],
40
- }
41
- replied_user = nil_merge(@replied_user, other&.replied_user)
42
- everyone = nil_merge(@everyone, other&.everyone)
43
- roles = nil_merge(@roles, other&.roles)
44
- users = nil_merge(@users, other&.users)
45
- payload[:replied_user] = replied_user
46
- payload[:parse].delete("everyone") if everyone == false
47
- if (roles == false) || roles.is_a?(Array)
48
- payload[:roles] = roles.map { |u| u.id.to_s } if roles.is_a? Array
49
- payload[:parse].delete("roles")
50
- end
51
- if (users == false) || users.is_a?(Array)
52
- payload[:users] = users.map { |u| u.id.to_s } if users.is_a? Array
53
- payload[:parse].delete("users")
54
- end
55
- payload
56
- end
57
-
58
- def nil_merge(*args)
59
- args.each do |a|
60
- return a unless a.nil?
61
- end
62
- nil
63
- end
64
- end
65
-
66
4
  #
67
5
  # Represents a message.
68
6
  #
@@ -257,38 +195,44 @@ module Discorb
257
195
  #
258
196
  def clean_content(user: true, channel: true, role: true, emoji: true, everyone: true, codeblock: false)
259
197
  ret = @content.dup
260
- ret.gsub!(/<@!?(\d+)>/) do |match|
261
- member = guild&.members&.[]($1)
262
- member ||= @client.users[$1]
263
- member ? "@#{member.name}" : "@Unknown User"
264
- end if user
265
- ret.gsub!(/<#(\d+)>/) do |match|
198
+ if user
199
+ ret.gsub!(/<@!?(\d+)>/) do |_match|
200
+ member = guild&.members&.[]($1)
201
+ member ||= @client.users[$1]
202
+ member ? "@#{member.name}" : "@Unknown User"
203
+ end
204
+ end
205
+ ret.gsub!(/<#(\d+)>/) do |_match|
266
206
  channel = @client.channels[$1]
267
207
  channel ? "<##{channel.id}>" : "#Unknown Channel"
268
208
  end
269
- ret.gsub!(/<@&(\d+)>/) do |match|
270
- role = guild&.roles&.[]($1)
271
- role ? "@#{role.name}" : "@Unknown Role"
272
- end if role
273
- ret.gsub!(/<a?:([a-zA-Z0-9_]+):\d+>/) do |match|
274
- $1
275
- end if emoji
209
+ if role
210
+ ret.gsub!(/<@&(\d+)>/) do |_match|
211
+ role = guild&.roles&.[]($1)
212
+ role ? "@#{role.name}" : "@Unknown Role"
213
+ end
214
+ end
215
+ if emoji
216
+ ret.gsub!(/<a?:([a-zA-Z0-9_]+):\d+>/) do |_match|
217
+ $1
218
+ end
219
+ end
276
220
  ret.gsub!(/@(everyone|here)/, "@\u200b\\1") if everyone
277
- unless codeblock
221
+ if codeblock
222
+ ret
223
+ else
278
224
  codeblocks = ret.split("```", -1)
279
225
  original_codeblocks = @content.scan(/```(.+?)```/m)
280
226
  res = []
281
227
  max = codeblocks.length
282
- codeblocks.each_with_index do |codeblock, i|
283
- if max % 2 == 0 && i == max - 1 or i.even?
284
- res << codeblock
228
+ codeblocks.each_with_index do |single_codeblock, i|
229
+ res << if max.even? && i == max - 1 || i.even?
230
+ single_codeblock
285
231
  else
286
- res << original_codeblocks[i / 2]
232
+ original_codeblocks[i / 2]
287
233
  end
288
234
  end
289
235
  res.join("```")
290
- else
291
- ret
292
236
  end
293
237
  end
294
238
 
@@ -379,7 +323,7 @@ module Discorb
379
323
  #
380
324
  def add_reaction(emoji)
381
325
  Async do
382
- @client.http.put("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}/@me", nil).wait
326
+ @client.http.request(Route.new("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}/@me", "//channels/:channel_id/messages/:message_id/reactions/:emoji/@me", :put), nil).wait
383
327
  end
384
328
  end
385
329
 
@@ -395,7 +339,7 @@ module Discorb
395
339
  #
396
340
  def remove_reaction(emoji)
397
341
  Async do
398
- @client.http.delete("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}/@me").wait
342
+ @client.http.request(Route.new("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}/@me", "//channels/:channel_id/messages/:message_id/reactions/:emoji/@me", :delete)).wait
399
343
  end
400
344
  end
401
345
 
@@ -412,7 +356,7 @@ module Discorb
412
356
  #
413
357
  def remove_reaction_of(emoji, member)
414
358
  Async do
415
- @client.http.delete("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}/#{member.is_a?(Member) ? member.id : member}").wait
359
+ @client.http.request(Route.new("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}/#{member.is_a?(Member) ? member.id : member}", "//channels/:channel_id/messages/:message_id/reactions/:emoji/:user_id", :delete)).wait
416
360
  end
417
361
  end
418
362
 
@@ -434,7 +378,7 @@ module Discorb
434
378
  after = 0
435
379
  users = []
436
380
  loop do
437
- _resp, data = @client.http.get("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}?limit=100&after=#{after}").wait
381
+ _resp, data = @client.http.request(Route.new("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}?limit=100&after=#{after}", "//channels/:channel_id/messages/:message_id/reactions/:emoji", :get)).wait
438
382
  break if data.empty?
439
383
 
440
384
  users += data.map { |r| guild&.members&.[](r[:id]) || @client.users[r[:id]] || User.new(@client, r) }
@@ -445,7 +389,7 @@ module Discorb
445
389
  end
446
390
  next users
447
391
  else
448
- _resp, data = @client.http.get("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}?limit=#{limit}&after=#{after}").wait
392
+ _resp, data = @client.http.request(Route.new("/channels/#{@channel_id}/messages/#{@id}/reactions/#{emoji.to_uri}?limit=#{limit}&after=#{after}", "//channels/:channel_id/messages/:message_id/reactions/:emoji", :get)).wait
449
393
  next data.map { |r| guild&.members&.[](r[:id]) || @client.users[r[:id]] || User.new(@client, r) }
450
394
  end
451
395
  end
@@ -501,201 +445,6 @@ module Discorb
501
445
  "#<#{self.class} #{@content.inspect} id=#{@id}>"
502
446
  end
503
447
 
504
- #
505
- # Represents message flag.
506
- # ## Flag fields
507
- # |Field|Value|
508
- # |-|-|
509
- # |`1 << 0`|`:crossposted`|
510
- # |`1 << 1`|`:crosspost`|
511
- # |`1 << 2`|`:supress_embeds`|
512
- # |`1 << 3`|`:source_message_deleted`|
513
- # |`1 << 4`|`:urgent`|
514
- # |`1 << 5`|`:has_thread`|
515
- # |`1 << 6`|`:ephemeral`|
516
- # |`1 << 7`|`:loading`|
517
- #
518
- class Flag < Discorb::Flag
519
- @bits = {
520
- crossposted: 0,
521
- crosspost: 1,
522
- supress_embeds: 2,
523
- source_message_deleted: 3,
524
- urgent: 4,
525
- has_thread: 5,
526
- ephemeral: 6,
527
- loading: 7,
528
- }.freeze
529
- end
530
-
531
- #
532
- # Represents reference of message.
533
- #
534
- class Reference
535
- # @return [Discorb::Snowflake] The guild ID.
536
- attr_accessor :guild_id
537
- # @return [Discorb::Snowflake] The channel ID.
538
- attr_accessor :channel_id
539
- # @return [Discorb::Snowflake] The message ID.
540
- attr_accessor :message_id
541
- # @return [Boolean] Whether fail the request if the message is not found.
542
- attr_accessor :fail_if_not_exists
543
-
544
- alias fail_if_not_exists? fail_if_not_exists
545
-
546
- #
547
- # Initialize a new reference.
548
- #
549
- # @param [Discorb::Snowflake] guild_id The guild ID.
550
- # @param [Discorb::Snowflake] channel_id The channel ID.
551
- # @param [Discorb::Snowflake] message_id The message ID.
552
- # @param [Boolean] fail_if_not_exists Whether fail the request if the message is not found.
553
- #
554
- def initialize(guild_id, channel_id, message_id, fail_if_not_exists: true)
555
- @guild_id = guild_id
556
- @channel_id = channel_id
557
- @message_id = message_id
558
- @fail_if_not_exists = fail_if_not_exists
559
- end
560
-
561
- #
562
- # Convert the reference to a hash.
563
- #
564
- # @return [Hash] The hash.
565
- #
566
- def to_hash
567
- {
568
- message_id: @message_id,
569
- channel_id: @channel_id,
570
- guild_id: @guild_id,
571
- fail_if_not_exists: @fail_if_not_exists,
572
- }
573
- end
574
-
575
- alias to_reference to_hash
576
-
577
- #
578
- # Initialize a new reference from a hash.
579
- #
580
- # @param [Hash] data The hash.
581
- #
582
- # @return [Discorb::Message::Reference] The reference.
583
- # @see https://discord.com/developers/docs/resources/channel#message-reference-object
584
- #
585
- def self.from_hash(data)
586
- new(data[:guild_id], data[:channel_id], data[:message_id], fail_if_not_exists: data[:fail_if_not_exists])
587
- end
588
- end
589
-
590
- class Sticker
591
- attr_reader :id, :name, :format
592
-
593
- def initialize(data)
594
- @id = Snowflake.new(data[:id])
595
- @name = data[:name]
596
- @format = Discorb::Sticker.sticker_format[data[:format]]
597
- end
598
- end
599
-
600
- private
601
-
602
- def _set_data(data)
603
- @id = Snowflake.new(data[:id])
604
- @channel_id = data[:channel_id]
605
-
606
- if data[:guild_id]
607
- @guild_id = data[:guild_id]
608
- @dm = nil
609
- else
610
- @dm = Discorb::DMChannel.new(@client, data[:channel_id])
611
- @guild_id = nil
612
- end
613
-
614
- if data[:member].nil? && data[:webhook_id]
615
- @webhook_id = Snowflake.new(data[:webhook_id])
616
- @author = Webhook::Message::Author.new(data[:author])
617
- elsif data[:guild_id].nil? || data[:guild_id].empty? || data[:member].nil?
618
- @author = @client.users[data[:author][:id]] || User.new(@client, data[:author])
619
- else
620
- @author = guild&.members&.get(data[:author][:id]) || Member.new(@client,
621
- @guild_id, data[:author], data[:member])
622
- end
623
- @content = data[:content]
624
- @created_at = Time.iso8601(data[:timestamp])
625
- @updated_at = data[:edited_timestamp].nil? ? nil : Time.iso8601(data[:edited_timestamp])
626
-
627
- @tts = data[:tts]
628
- @mention_everyone = data[:mention_everyone]
629
- @mention_roles = data[:mention_roles].map { |r| guild.roles[r] }
630
- @attachments = data[:attachments].map { |a| Attachment.new(a) }
631
- @embeds = data[:embeds] ? data[:embeds].map { |e| Embed.new(data: e) } : []
632
- @reactions = data[:reactions] ? data[:reactions].map { |r| Reaction.new(self, r) } : []
633
- @pinned = data[:pinned]
634
- @type = self.class.message_type[data[:type]]
635
- @activity = data[:activity] && Activity.new(data[:activity])
636
- @application_id = data[:application_id]
637
- @message_reference = data[:message_reference] && Reference.from_hash(data[:message_reference])
638
- @flag = Flag.new(0b111 - data[:flags])
639
- @sticker_items = data[:sticker_items] ? data[:sticker_items].map { |s| Message::Sticker.new(s) } : []
640
- # @referenced_message = data[:referenced_message] && Message.new(@client, data[:referenced_message])
641
- @interaction = data[:interaction] && Message::Interaction.new(@client, data[:interaction])
642
- @thread = data[:thread] && Channel.make_channel(@client, data[:thread])
643
- @components = data[:components].map { |c| c[:components].map { |co| Component.from_hash(co) } }
644
- @data.update(data)
645
- @deleted = false
646
- end
647
-
648
- #
649
- # Represents a interaction of message.
650
- #
651
- class Interaction < DiscordModel
652
- # @return [Discorb::Snowflake] The user ID.
653
- attr_reader :id
654
- # @return [String] The name of command.
655
- # @return [nil] If the message is not a command.
656
- attr_reader :name
657
- # @return [Class] The type of interaction.
658
- attr_reader :type
659
- # @return [Discorb::User] The user.
660
- attr_reader :user
661
-
662
- # @private
663
- def initialize(client, data)
664
- @id = Snowflake.new(data[:id])
665
- @name = data[:name]
666
- @type = Discorb::Interaction.descendants.find { |c| c.interaction_type == data[:type] }
667
- @user = client.users[data[:user][:id]] || User.new(client, data[:user])
668
- end
669
- end
670
-
671
- #
672
- # Represents a activity of message.
673
- #
674
- class Activity < DiscordModel
675
- # @return [String] The name of activity.
676
- attr_reader :name
677
- # @return [Symbol] The type of activity.
678
- attr_reader :type
679
-
680
- @type = {
681
- 1 => :join,
682
- 2 => :spectate,
683
- 3 => :listen,
684
- 5 => :join_request,
685
- }
686
-
687
- # @private
688
- def initialize(data)
689
- @name = data[:name]
690
- @type = self.class.type(data[:type])
691
- end
692
-
693
- class << self
694
- # @private
695
- attr_reader :type
696
- end
697
- end
698
-
699
448
  class << self
700
449
  # @private
701
450
  attr_reader :message_type
@@ -0,0 +1,205 @@
1
+ # frozen_string_literal: true
2
+ module Discorb
3
+ #
4
+ # Represents a message in Discord.
5
+ #
6
+ class Message < DiscordModel
7
+ #
8
+ # Represents message flag.
9
+ # ## Flag fields
10
+ # |Field|Value|
11
+ # |-|-|
12
+ # |`1 << 0`|`:crossposted`|
13
+ # |`1 << 1`|`:crosspost`|
14
+ # |`1 << 2`|`:supress_embeds`|
15
+ # |`1 << 3`|`:source_message_deleted`|
16
+ # |`1 << 4`|`:urgent`|
17
+ # |`1 << 5`|`:has_thread`|
18
+ # |`1 << 6`|`:ephemeral`|
19
+ # |`1 << 7`|`:loading`|
20
+ #
21
+ class Flag < Discorb::Flag
22
+ @bits = {
23
+ crossposted: 0,
24
+ crosspost: 1,
25
+ supress_embeds: 2,
26
+ source_message_deleted: 3,
27
+ urgent: 4,
28
+ has_thread: 5,
29
+ ephemeral: 6,
30
+ loading: 7,
31
+ }.freeze
32
+ end
33
+
34
+ #
35
+ # Represents reference of message.
36
+ #
37
+ class Reference
38
+ # @return [Discorb::Snowflake] The guild ID.
39
+ attr_accessor :guild_id
40
+ # @return [Discorb::Snowflake] The channel ID.
41
+ attr_accessor :channel_id
42
+ # @return [Discorb::Snowflake] The message ID.
43
+ attr_accessor :message_id
44
+ # @return [Boolean] Whether fail the request if the message is not found.
45
+ attr_accessor :fail_if_not_exists
46
+
47
+ alias fail_if_not_exists? fail_if_not_exists
48
+
49
+ #
50
+ # Initialize a new reference.
51
+ #
52
+ # @param [Discorb::Snowflake] guild_id The guild ID.
53
+ # @param [Discorb::Snowflake] channel_id The channel ID.
54
+ # @param [Discorb::Snowflake] message_id The message ID.
55
+ # @param [Boolean] fail_if_not_exists Whether fail the request if the message is not found.
56
+ #
57
+ def initialize(guild_id, channel_id, message_id, fail_if_not_exists: true)
58
+ @guild_id = guild_id
59
+ @channel_id = channel_id
60
+ @message_id = message_id
61
+ @fail_if_not_exists = fail_if_not_exists
62
+ end
63
+
64
+ #
65
+ # Convert the reference to a hash.
66
+ #
67
+ # @return [Hash] The hash.
68
+ #
69
+ def to_hash
70
+ {
71
+ message_id: @message_id,
72
+ channel_id: @channel_id,
73
+ guild_id: @guild_id,
74
+ fail_if_not_exists: @fail_if_not_exists,
75
+ }
76
+ end
77
+
78
+ alias to_reference to_hash
79
+
80
+ #
81
+ # Initialize a new reference from a hash.
82
+ #
83
+ # @param [Hash] data The hash.
84
+ #
85
+ # @return [Discorb::Message::Reference] The reference.
86
+ # @see https://discord.com/developers/docs/resources/channel#message-reference-object
87
+ #
88
+ def self.from_hash(data)
89
+ new(data[:guild_id], data[:channel_id], data[:message_id], fail_if_not_exists: data[:fail_if_not_exists])
90
+ end
91
+ end
92
+
93
+ #
94
+ # Represents a sticker.
95
+ #
96
+ class Sticker
97
+ attr_reader :id, :name, :format
98
+
99
+ def initialize(data)
100
+ @id = Snowflake.new(data[:id])
101
+ @name = data[:name]
102
+ @format = Discorb::Sticker.sticker_format[data[:format]]
103
+ end
104
+ end
105
+
106
+ private
107
+
108
+ def _set_data(data)
109
+ @id = Snowflake.new(data[:id])
110
+ @channel_id = data[:channel_id]
111
+
112
+ if data[:guild_id]
113
+ @guild_id = data[:guild_id]
114
+ @dm = nil
115
+ else
116
+ @dm = Discorb::DMChannel.new(@client, data[:channel_id])
117
+ @guild_id = nil
118
+ end
119
+
120
+ if data[:member].nil? && data[:webhook_id]
121
+ @webhook_id = Snowflake.new(data[:webhook_id])
122
+ @author = Webhook::Message::Author.new(data[:author])
123
+ elsif data[:guild_id].nil? || data[:guild_id].empty? || data[:member].nil?
124
+ @author = @client.users[data[:author][:id]] || User.new(@client, data[:author])
125
+ else
126
+ @author = guild&.members&.get(data[:author][:id]) || Member.new(@client,
127
+ @guild_id, data[:author], data[:member])
128
+ end
129
+ @content = data[:content]
130
+ @created_at = Time.iso8601(data[:timestamp])
131
+ @updated_at = data[:edited_timestamp].nil? ? nil : Time.iso8601(data[:edited_timestamp])
132
+
133
+ @tts = data[:tts]
134
+ @mention_everyone = data[:mention_everyone]
135
+ @mention_roles = data[:mention_roles].map { |r| guild.roles[r] }
136
+ @attachments = data[:attachments].map { |a| Attachment.new(a) }
137
+ @embeds = data[:embeds] ? data[:embeds].map { |e| Embed.new(data: e) } : []
138
+ @reactions = data[:reactions] ? data[:reactions].map { |r| Reaction.new(self, r) } : []
139
+ @pinned = data[:pinned]
140
+ @type = self.class.message_type[data[:type]]
141
+ @activity = data[:activity] && Activity.new(data[:activity])
142
+ @application_id = data[:application_id]
143
+ @message_reference = data[:message_reference] && Reference.from_hash(data[:message_reference])
144
+ @flag = Flag.new(0b111 - data[:flags])
145
+ @sticker_items = data[:sticker_items] ? data[:sticker_items].map { |s| Message::Sticker.new(s) } : []
146
+ # @referenced_message = data[:referenced_message] && Message.new(@client, data[:referenced_message])
147
+ @interaction = data[:interaction] && Message::Interaction.new(@client, data[:interaction])
148
+ @thread = data[:thread] && Channel.make_channel(@client, data[:thread])
149
+ @components = data[:components].map { |c| c[:components].map { |co| Component.from_hash(co) } }
150
+ @data.update(data)
151
+ @deleted = false
152
+ end
153
+
154
+ #
155
+ # Represents a interaction of message.
156
+ #
157
+ class Interaction < DiscordModel
158
+ # @return [Discorb::Snowflake] The user ID.
159
+ attr_reader :id
160
+ # @return [String] The name of command.
161
+ # @return [nil] If the message is not a command.
162
+ attr_reader :name
163
+ # @return [Class] The type of interaction.
164
+ attr_reader :type
165
+ # @return [Discorb::User] The user.
166
+ attr_reader :user
167
+
168
+ # @private
169
+ def initialize(client, data)
170
+ @id = Snowflake.new(data[:id])
171
+ @name = data[:name]
172
+ @type = Discorb::Interaction.descendants.find { |c| c.interaction_type == data[:type] }
173
+ @user = client.users[data[:user][:id]] || User.new(client, data[:user])
174
+ end
175
+ end
176
+
177
+ #
178
+ # Represents a activity of message.
179
+ #
180
+ class Activity < DiscordModel
181
+ # @return [String] The name of activity.
182
+ attr_reader :name
183
+ # @return [Symbol] The type of activity.
184
+ attr_reader :type
185
+
186
+ @type = {
187
+ 1 => :join,
188
+ 2 => :spectate,
189
+ 3 => :listen,
190
+ 5 => :join_request,
191
+ }
192
+
193
+ # @private
194
+ def initialize(data)
195
+ @name = data[:name]
196
+ @type = self.class.type(data[:type])
197
+ end
198
+
199
+ class << self
200
+ # @private
201
+ attr_reader :type
202
+ end
203
+ end
204
+ end
205
+ end