discorb 0.17.1 → 0.18.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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +1 -3
  3. data/.github/workflows/validate.yml +21 -0
  4. data/Changelog.md +10 -0
  5. data/Gemfile +6 -0
  6. data/Rakefile +210 -98
  7. data/Steepfile +28 -0
  8. data/docs/events.md +42 -6
  9. data/docs/tutorial.md +7 -7
  10. data/docs/voice_events.md +2 -2
  11. data/examples/commands/message.rb +12 -7
  12. data/examples/commands/permission.rb +2 -1
  13. data/examples/commands/slash.rb +23 -19
  14. data/examples/commands/user.rb +15 -12
  15. data/examples/components/authorization_button.rb +2 -1
  16. data/examples/components/select_menu.rb +4 -1
  17. data/examples/extension/main.rb +1 -0
  18. data/examples/extension/message_expander.rb +1 -0
  19. data/examples/sig/commands/message.rbs +5 -0
  20. data/examples/simple/eval.rb +1 -0
  21. data/examples/simple/ping_pong.rb +1 -0
  22. data/examples/simple/rolepanel.rb +16 -5
  23. data/examples/simple/shard.rb +2 -1
  24. data/examples/simple/wait_for_message.rb +3 -0
  25. data/exe/discorb +3 -3
  26. data/lib/discorb/allowed_mentions.rb +1 -1
  27. data/lib/discorb/app_command/command.rb +12 -13
  28. data/lib/discorb/app_command/handler.rb +20 -6
  29. data/lib/discorb/audit_logs.rb +6 -2
  30. data/lib/discorb/automod.rb +269 -0
  31. data/lib/discorb/channel/guild.rb +2 -1
  32. data/lib/discorb/channel/stage.rb +1 -1
  33. data/lib/discorb/channel/text.rb +11 -20
  34. data/lib/discorb/channel/thread.rb +15 -11
  35. data/lib/discorb/client.rb +12 -10
  36. data/lib/discorb/color.rb +37 -60
  37. data/lib/discorb/common.rb +1 -1
  38. data/lib/discorb/dictionary.rb +1 -1
  39. data/lib/discorb/embed.rb +4 -3
  40. data/lib/discorb/emoji.rb +2 -2
  41. data/lib/discorb/exe/about.rb +1 -1
  42. data/lib/discorb/exe/new.rb +1 -5
  43. data/lib/discorb/extension.rb +0 -4
  44. data/lib/discorb/flag.rb +2 -2
  45. data/lib/discorb/gateway.rb +21 -582
  46. data/lib/discorb/gateway_events.rb +638 -0
  47. data/lib/discorb/guild.rb +136 -17
  48. data/lib/discorb/guild_template.rb +1 -1
  49. data/lib/discorb/http.rb +47 -25
  50. data/lib/discorb/intents.rb +27 -18
  51. data/lib/discorb/interaction/command.rb +14 -10
  52. data/lib/discorb/interaction/response.rb +74 -14
  53. data/lib/discorb/member.rb +3 -3
  54. data/lib/discorb/message.rb +13 -11
  55. data/lib/discorb/message_meta.rb +2 -3
  56. data/lib/discorb/modules.rb +3 -2
  57. data/lib/discorb/presence.rb +4 -2
  58. data/lib/discorb/reaction.rb +2 -2
  59. data/lib/discorb/role.rb +1 -1
  60. data/lib/discorb/sticker.rb +3 -3
  61. data/lib/discorb/user.rb +2 -2
  62. data/lib/discorb/voice_state.rb +5 -5
  63. data/lib/discorb/webhook.rb +15 -6
  64. data/lib/discorb.rb +2 -2
  65. data/rbs_collection.lock.yaml +88 -96
  66. data/rbs_collection.yaml +21 -17
  67. data/sig/async.rbs +11 -5
  68. data/sig/discorb/activity.rbs +23 -0
  69. data/sig/discorb/allowed_mentions.rbs +44 -0
  70. data/sig/discorb/app_command/base.rbs +282 -0
  71. data/sig/discorb/app_command/handler.rbs +171 -0
  72. data/sig/discorb/application.rbs +142 -0
  73. data/sig/discorb/asset.rbs +32 -0
  74. data/sig/discorb/attachment.rbs +91 -0
  75. data/sig/discorb/audit_log.rbs +231 -0
  76. data/sig/discorb/automod.rbs +128 -0
  77. data/sig/discorb/avatar.rbs +26 -0
  78. data/sig/discorb/channel/base.rbs +179 -0
  79. data/sig/discorb/channel/category.rbs +56 -0
  80. data/sig/discorb/channel/container.rbs +29 -0
  81. data/sig/discorb/channel/dm.rbs +14 -0
  82. data/sig/discorb/channel/news.rbs +20 -0
  83. data/sig/discorb/channel/stage.rbs +77 -0
  84. data/sig/discorb/channel/text.rbs +158 -0
  85. data/sig/discorb/channel/thread.rbs +185 -0
  86. data/sig/discorb/channel/voice.rbs +41 -0
  87. data/sig/discorb/client.rbs +2495 -0
  88. data/sig/discorb/color.rbs +142 -0
  89. data/sig/discorb/component/base.rbs +28 -0
  90. data/sig/discorb/component/button.rbs +65 -0
  91. data/sig/discorb/component/select_menu.rbs +107 -0
  92. data/sig/discorb/component/text_input.rbs +69 -0
  93. data/sig/discorb/connectable.rbs +8 -0
  94. data/sig/discorb/custom_emoji.rbs +90 -0
  95. data/sig/discorb/dictionary.rbs +85 -0
  96. data/sig/discorb/discord_model.rbs +15 -0
  97. data/sig/discorb/embed.rbs +279 -0
  98. data/sig/discorb/emoji.rbs +13 -0
  99. data/sig/discorb/error.rbs +73 -0
  100. data/sig/discorb/event_handler.rbs +27 -0
  101. data/sig/discorb/extension.rbs +1734 -0
  102. data/sig/discorb/flag.rbs +72 -0
  103. data/sig/discorb/gateway.rbs +481 -0
  104. data/sig/discorb/guild.rbs +870 -0
  105. data/sig/discorb/guild_template.rbs +174 -0
  106. data/sig/discorb/http.rbs +147 -0
  107. data/sig/discorb/image.rbs +20 -0
  108. data/sig/discorb/integration.rbs +118 -0
  109. data/sig/discorb/intents.rbs +97 -0
  110. data/sig/discorb/interaction/autocomplete.rbs +9 -0
  111. data/sig/discorb/interaction/base.rbs +66 -0
  112. data/sig/discorb/interaction/command.rbs +66 -0
  113. data/sig/discorb/interaction/message_component.rbs +140 -0
  114. data/sig/discorb/interaction/modal.rbs +50 -0
  115. data/sig/discorb/interaction/responder.rbs +157 -0
  116. data/sig/discorb/invite.rbs +86 -0
  117. data/sig/discorb/member.rbs +187 -0
  118. data/sig/discorb/message.rbs +469 -0
  119. data/sig/discorb/messageable.rbs +153 -0
  120. data/sig/discorb/partial_emoji.rbs +35 -0
  121. data/sig/discorb/permissions.rbs +149 -0
  122. data/sig/discorb/presence.rbs +237 -0
  123. data/sig/discorb/reaction.rbs +33 -0
  124. data/sig/discorb/role.rbs +145 -0
  125. data/sig/discorb/scheduled_event.rbs +148 -0
  126. data/sig/discorb/shard.rbs +62 -0
  127. data/sig/discorb/snowflake.rbs +56 -0
  128. data/sig/discorb/stage_instance.rbs +63 -0
  129. data/sig/discorb/sticker.rbs +116 -0
  130. data/sig/discorb/system_channel_flag.rbs +17 -0
  131. data/sig/discorb/unicode_emoji.rbs +49 -0
  132. data/sig/discorb/user.rbs +93 -0
  133. data/sig/discorb/utils.rbs +8 -0
  134. data/sig/discorb/voice_region.rbs +30 -0
  135. data/sig/discorb/voice_state.rbs +71 -0
  136. data/sig/discorb/webhook.rbs +327 -0
  137. data/sig/discorb/welcome_screen.rbs +78 -0
  138. data/sig/discorb.rbs +5 -8661
  139. data/sig/manifest.yaml +3 -0
  140. data/sig/override.rbs +19 -0
  141. metadata +80 -3
data/lib/discorb/guild.rb CHANGED
@@ -226,9 +226,6 @@ module Discorb
226
226
  :get
227
227
  )
228
228
  ).wait
229
- rescue Discorb::NotFoundError
230
- return nil
231
- else
232
229
  ScheduledEvent.new(@client, event)
233
230
  end
234
231
  end
@@ -343,9 +340,16 @@ module Discorb
343
340
  # @return [Async::Task<Discorb::CustomEmoji>] The emoji with the given id.
344
341
  #
345
342
  def fetch_emoji(id)
346
- _resp, data = @client.http.request(Route.new("/guilds/#{@id}/emojis/#{id}",
347
- "//guilds/:guild_id/emojis/:emoji_id", :get)).wait
348
- @emojis[e[:id]] = CustomEmoji.new(@client, self, data)
343
+ Async do
344
+ _resp, data = @client.http.request(
345
+ Route.new(
346
+ "/guilds/#{@id}/emojis/#{id}",
347
+ "//guilds/:guild_id/emojis/:emoji_id",
348
+ :get
349
+ )
350
+ ).wait
351
+ @emojis[e[:id]] = CustomEmoji.new(@client, self, data)
352
+ end
349
353
  end
350
354
 
351
355
  #
@@ -359,13 +363,17 @@ module Discorb
359
363
  # @return [Async::Task<Discorb::CustomEmoji>] The created emoji.
360
364
  #
361
365
  def create_emoji(name, image, roles: [])
362
- _resp, data = @client.http.request(Route.new("/guilds/#{@id}/emojis", "//guilds/:guild_id/emojis", :post),
363
- {
364
- name: name,
365
- image: image.to_s,
366
- roles: roles.map { |r| Discorb::Utils.try(r, :id) },
367
- }).wait
368
- @emojis[data[:id]] = CustomEmoji.new(@client, self, data)
366
+ Async do
367
+ _resp, data = @client.http.request(
368
+ Route.new("/guilds/#{@id}/emojis", "//guilds/:guild_id/emojis", :post),
369
+ {
370
+ name: name,
371
+ image: image.to_s,
372
+ roles: roles.map { |r| Discorb::Utils.try(r, :id) },
373
+ }
374
+ ).wait
375
+ @emojis[data[:id]] = CustomEmoji.new(@client, self, data)
376
+ end
369
377
  end
370
378
 
371
379
  #
@@ -378,7 +386,7 @@ module Discorb
378
386
  Async do
379
387
  _resp, data = @client.http.request(Route.new("/guilds/#{@id}/webhooks", "//guilds/:guild_id/webhooks",
380
388
  :get)).wait
381
- data.map { |webhook| Webhook.new([@client, webhook]) }
389
+ data.map { |webhook| Webhook.from_data(@client, webhook) }
382
390
  end
383
391
  end
384
392
 
@@ -698,7 +706,7 @@ module Discorb
698
706
  "//guilds/:guild_id/members", :get)).wait
699
707
  ret += data.map { |m| Member.new(@client, @id, m[:user], m) }
700
708
  after = data.last[:user][:id]
701
- break if data.length != 1000
709
+ break if data.length != 100
702
710
  end
703
711
  ret
704
712
  end
@@ -1122,6 +1130,100 @@ module Discorb
1122
1130
  end
1123
1131
  end
1124
1132
 
1133
+ #
1134
+ # Fetch the automod rules in the guild.
1135
+ # @async
1136
+ #
1137
+ # @return [Async::Task<Array<Discorb::AutoModRule>>] The automod rules.
1138
+ #
1139
+ def fetch_automod_rules
1140
+ Async do
1141
+ _resp, data = @client.http.request(
1142
+ Route.new("/guilds/#{@id}/auto-moderation/rules", "//guilds/:guild_id/auto-moderation/rules", :get)
1143
+ )
1144
+ data.map { |d| AutoModRule.new(@client, d) }
1145
+ end
1146
+ end
1147
+
1148
+ alias fetch_automod_rule_list fetch_automod_rules
1149
+
1150
+ #
1151
+ # Fetch the automod rule by ID.
1152
+ #
1153
+ # @param [#to_s] id The ID of the automod rule.
1154
+ #
1155
+ # @return [Async::Task<Array<Discord::AutoModRule>>] The automod rule.
1156
+ #
1157
+ def fetch_automod_rule(id)
1158
+ Async do
1159
+ _resp, data = @client.http.request(
1160
+ Route.new(
1161
+ "/guilds/#{@id}/auto-moderation/rules/#{id}",
1162
+ "//guilds/:guild_id/auto-moderation/rules/:rule_id",
1163
+ :get
1164
+ )
1165
+ ).wait
1166
+ AutoModRule.new(@client, data)
1167
+ end
1168
+ end
1169
+
1170
+ #
1171
+ # Create a new automod rule in the guild.
1172
+ # @async
1173
+ #
1174
+ # @param [String] name The name of the rule.
1175
+ # @param [Symbol] trigger_type The trigger type of the rule. See {Discorb::AutoModRule::TRIGGER_TYPES}.
1176
+ # @param [Array<Discorb::AutoModRule::Action>] actions The actions of the rule.
1177
+ # @param [Symbol] event_type The event type of the rule. See {Discorb::AutoModRule::EVENT_TYPES}.
1178
+ # @param [Boolean] enabled Whether the rule is enabled or not.
1179
+ # @param [Array<Discorb::Role>] exempt_roles The roles that are exempt from the rule.
1180
+ # @param [Array<Discorb::Channel>] exempt_channels The channels that are exempt from the rule.
1181
+ # @param [Array<String>] keyword_filter The keywords to filter.
1182
+ # @param [Symbol] presets The preset of the rule. See {Discorb::AutoModRule::PRESET_TYPES}.
1183
+ # @param [String] reason The reason for creating the rule.
1184
+ #
1185
+ # @return [Async::Task<Discorb::AutoModRule>] The automod rule.
1186
+ #
1187
+ def create_automod_rule(
1188
+ name,
1189
+ trigger_type,
1190
+ actions,
1191
+ event_type = :send_message,
1192
+ enabled: false,
1193
+ exempt_roles: [],
1194
+ exempt_channels: [],
1195
+ keyword_filter: nil,
1196
+ presets: nil,
1197
+ reason: nil
1198
+ )
1199
+ Async do
1200
+ payload = {
1201
+ name: name,
1202
+ event_type: Discorb::AutoModRule::EVENT_TYPES.key(event_type),
1203
+ trigger_type: Discorb::AutoModRule::TRIGGER_TYPES.key(trigger_type),
1204
+ metadata: {
1205
+ keyword_filter: keyword_filter,
1206
+ presets: Discorb::AutoModRule::PRESET_TYPES.key(presets),
1207
+ },
1208
+ actions: actions.map(&:to_hash),
1209
+ enabled: enabled,
1210
+ exempt_roles: exempt_roles.map(&:id),
1211
+ exempt_channels: exempt_channels.map(&:id),
1212
+ }
1213
+
1214
+ _resp, data = @client.http.request(
1215
+ Route.new(
1216
+ "/guilds/#{@id}/auto-moderation/rules",
1217
+ "//guilds/:guild_id/auto-moderation/rules",
1218
+ :post
1219
+ ),
1220
+ payload,
1221
+ audit_log_reason: reason
1222
+ )
1223
+ Discorb::AutoModRule.new(@client, data)
1224
+ end
1225
+ end
1226
+
1125
1227
  #
1126
1228
  # Represents a vanity invite.
1127
1229
  #
@@ -1339,7 +1441,7 @@ module Discorb
1339
1441
  @nsfw_level = NSFW_LEVELS[data[:nsfw_level]]
1340
1442
  return unless is_create_event
1341
1443
 
1342
- @stickers = data[:stickers].nil? ? [] : data[:stickers].map { |s| Sticker::GuildSticker.new(self, s) }
1444
+ @stickers = data[:stickers].nil? ? [] : data[:stickers].map { |s| Sticker::GuildSticker.new(@client, s) }
1343
1445
  @joined_at = Time.iso8601(data[:joined_at])
1344
1446
  @large = data[:large]
1345
1447
  @member_count = data[:member_count]
@@ -1407,7 +1509,24 @@ module Discorb
1407
1509
  @client = client
1408
1510
  @description = data[:description]
1409
1511
  @guild = guild
1410
- @channels = data[:channels].map { |c| WelcomeScreen::Channel.new(client, c, nil) }
1512
+ @channels = data[:channels].map do |c|
1513
+ WelcomeScreen::Channel.new(
1514
+ client.channels[c[:channel_id]],
1515
+ c,
1516
+ c[:emoji_name] &&
1517
+ if c[:emoji_id]
1518
+ (client.emojis[c[:emoji_id]] ||
1519
+ Discorb::PartialEmoji.new(
1520
+ {
1521
+ name: c[:emoji_name],
1522
+ id: c[:emoji_id],
1523
+ }
1524
+ ))
1525
+ else
1526
+ Discorb::UnicodeEmoji.new(c[:emoji_name])
1527
+ end
1528
+ )
1529
+ end
1411
1530
  end
1412
1531
 
1413
1532
  #
@@ -19,7 +19,7 @@ module Discorb
19
19
  attr_reader :created_at
20
20
  # @return [Time] The time this template was last updated.
21
21
  attr_reader :updated_at
22
- # @return [Discorb::Guild] The guild where the template was created.
22
+ # @return [Discorb::Snowflake] The ID of guild where the template was created.
23
23
  attr_reader :source_guild_id
24
24
  # @return [Discorb::GuildTemplate::TemplateGuild] The guild where the template was created.
25
25
  attr_reader :serialized_source_guild
data/lib/discorb/http.rb CHANGED
@@ -27,7 +27,6 @@ module Discorb
27
27
  #
28
28
  # @param [Discorb::Route] path The path to the resource.
29
29
  # @param [String, Hash] body The body of the request. Defaults to an empty string.
30
- # @param [Hash] headers The headers to send with the request.
31
30
  # @param [String] audit_log_reason The audit log reason to send with the request.
32
31
  # @param [Hash] kwargs The keyword arguments.
33
32
  #
@@ -36,18 +35,28 @@ module Discorb
36
35
  #
37
36
  # @raise [Discorb::HTTPError] The request was failed.
38
37
  #
39
- def request(path, body = "", headers: nil, audit_log_reason: nil, **kwargs)
38
+ def request(path, body = "", audit_log_reason: nil, **kwargs)
40
39
  Async do |_task|
41
40
  @ratelimit_handler.wait(path)
42
41
  resp = if %i[post patch put].include? path.method
43
- http.send(path.method, get_path(path), get_body(body), get_headers(headers, body, audit_log_reason),
44
- **kwargs)
42
+ http.send(
43
+ path.method,
44
+ get_path(path),
45
+ get_body(body),
46
+ get_headers(body, audit_log_reason),
47
+ **kwargs,
48
+ )
45
49
  else
46
- http.send(path.method, get_path(path), get_headers(headers, body, audit_log_reason), **kwargs)
50
+ http.send(
51
+ path.method,
52
+ get_path(path),
53
+ get_headers(body, audit_log_reason),
54
+ **kwargs,
55
+ )
47
56
  end
48
57
  data = get_response_data(resp)
49
58
  @ratelimit_handler.save(path, resp)
50
- handle_response(resp, data, path, body, headers, audit_log_reason, kwargs)
59
+ handle_response(resp, data, path, body, nil, audit_log_reason, kwargs)
51
60
  end
52
61
  end
53
62
 
@@ -58,7 +67,6 @@ module Discorb
58
67
  # @param [Discorb::Route] path The path to the resource.
59
68
  # @param [String, Hash] body The body of the request.
60
69
  # @param [Array<Discorb::Attachment>] files The files to upload.
61
- # @param [Hash] headers The headers to send with the request.
62
70
  # @param [String] audit_log_reason The audit log reason to send with the request.
63
71
  # @param [Hash] kwargs The keyword arguments.
64
72
  #
@@ -67,14 +75,15 @@ module Discorb
67
75
  #
68
76
  # @raise [Discorb::HTTPError] The request was failed.
69
77
  #
70
- def multipart_request(path, body, files, headers: nil, audit_log_reason: nil, **kwargs)
78
+ def multipart_request(path, body, files, audit_log_reason: nil, **kwargs)
71
79
  Async do |_task|
72
80
  @ratelimit_handler.wait(path)
73
81
  req = Net::HTTP.const_get(path.method.to_s.capitalize).new(
74
82
  get_path(path),
75
- get_headers(headers, body, audit_log_reason),
83
+ get_headers(body, audit_log_reason),
76
84
  **kwargs,
77
85
  )
86
+ # @type var data: Array[untyped]
78
87
  data = [
79
88
  ["payload_json", get_body(body)],
80
89
  ]
@@ -83,10 +92,13 @@ module Discorb
83
92
 
84
93
  if file.created_by == :discord
85
94
  request_io = StringIO.new(
86
- cdn_http.get(URI.parse(file.url).path, {
87
- "Content-Type" => nil,
88
- "User-Agent" => Discorb::USER_AGENT,
89
- }).body
95
+ cdn_http.get(
96
+ (URI.parse(file.url).path || raise("Could not parse url")),
97
+ {
98
+ "Content-Type" => nil,
99
+ "User-Agent" => Discorb::USER_AGENT,
100
+ }
101
+ ).body
90
102
  )
91
103
  data << ["files[#{i}]", request_io, { filename: file.filename, content_type: file.content_type }]
92
104
  else
@@ -97,10 +109,11 @@ module Discorb
97
109
  session = Net::HTTP.new("discord.com", 443)
98
110
  session.use_ssl = true
99
111
  resp = session.request(req)
100
- files&.then { _1.filter(&:will_close).each { |f| f.io.close } }
101
- data = get_response_data(resp)
112
+ resp_data = get_response_data(resp)
102
113
  @ratelimit_handler.save(path, resp)
103
- handle_response(resp, data, path, body, headers, audit_log_reason, kwargs)
114
+ response = handle_response(resp, resp_data, path, body, files, audit_log_reason, kwargs)
115
+ files&.then { _1.filter(&:will_close).each { |f| f.io.close } }
116
+ response
104
117
  end
105
118
  end
106
119
 
@@ -110,12 +123,16 @@ module Discorb
110
123
 
111
124
  private
112
125
 
113
- def handle_response(resp, data, path, body, headers, audit_log_reason, kwargs)
126
+ def handle_response(resp, data, path, body, files, audit_log_reason, kwargs)
114
127
  case resp.code
115
128
  when "429"
116
129
  @client.logger.info("Rate limit exceeded for #{path.method} #{path.url}, waiting #{data[:retry_after]} seconds")
117
130
  sleep(data[:retry_after])
118
- request(path, body, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
131
+ if files
132
+ multipart_request(path, body, files, audit_log_reason: audit_log_reason, **kwargs).wait
133
+ else
134
+ request(path, body, audit_log_reason: audit_log_reason, **kwargs).wait
135
+ end
119
136
  when "400"
120
137
  raise BadRequestError.new(resp, data)
121
138
  when "401"
@@ -129,14 +146,19 @@ module Discorb
129
146
  end
130
147
  end
131
148
 
132
- def get_headers(headers, body = "", audit_log_reason = nil)
149
+ def get_headers(body = "", audit_log_reason = nil)
133
150
  ret = if body.nil? || body == ""
134
- { "User-Agent" => USER_AGENT, "authorization" => "Bot #{@client.token}" }
151
+ {
152
+ "User-Agent" => USER_AGENT,
153
+ "authorization" => "Bot #{@client.token}",
154
+ }
135
155
  else
136
- { "User-Agent" => USER_AGENT, "authorization" => "Bot #{@client.token}",
137
- "content-type" => "application/json", }
156
+ {
157
+ "User-Agent" => USER_AGENT,
158
+ "authorization" => "Bot #{@client.token}",
159
+ "content-type" => "application/json",
160
+ }
138
161
  end
139
- ret.merge!(headers) if !headers.nil? && headers.length.positive?
140
162
  ret["X-Audit-Log-Reason"] = audit_log_reason unless audit_log_reason.nil?
141
163
  ret
142
164
  end
@@ -153,7 +175,7 @@ module Discorb
153
175
 
154
176
  def get_path(path)
155
177
  full_path = if path.url.start_with?("https://")
156
- path.url
178
+ path.url
157
179
  else
158
180
  API_BASE_URL + path.url
159
181
  end
@@ -166,7 +188,7 @@ module Discorb
166
188
  data = JSON.parse(resp.body, symbolize_names: true)
167
189
  rescue JSON::ParserError, TypeError
168
190
  data = if resp.body.nil? || resp.body.empty?
169
- nil
191
+ {}
170
192
  else
171
193
  resp.body
172
194
  end
@@ -23,6 +23,8 @@ module Discorb
23
23
  dm_typing: 1 << 14,
24
24
  message_content: 1 << 15,
25
25
  scheduled_events: 1 << 16,
26
+ automod_configuration: 1 << 20,
27
+ automod_execution: 1 << 21,
26
28
  }.freeze
27
29
 
28
30
  #
@@ -44,29 +46,34 @@ module Discorb
44
46
  # @param dm_typing [Boolean] Whether dm typing related events are enabled.
45
47
  # @param message_content [Boolean] Whether message content will be sent with events.
46
48
  # @param scheduled_events [Boolean] Whether events related scheduled events are enabled.
47
- #
49
+ # @param automod_configuration [Boolean] Whether automod configuration related events are enabled.
50
+ # @param automod_execution [Boolean] Whether automod execution related events are enabled.
48
51
  # @note You must enable privileged intents to use `members` and/or `presences` intents.
49
52
  # @note Message Content Intent is not required to use `message_content` intents for now,
50
53
  # this will be required in September 1, 2022. [Learn More](https://support-dev.discord.com/hc/en-us/articles/4404772028055).
51
54
  # You should specify `message_content` intent for preventing unexpected changes in the future.
52
55
  #
53
- def initialize(guilds: true,
54
- members: false,
55
- bans: true,
56
- emojis: true,
57
- integrations: true,
58
- webhooks: true,
59
- invites: true,
60
- voice_states: true,
61
- presences: false,
62
- messages: true,
63
- reactions: true,
64
- typing: true,
65
- dm_messages: true,
66
- dm_reactions: true,
67
- dm_typing: true,
68
- message_content: nil,
69
- scheduled_events: true)
56
+ def initialize(
57
+ guilds: true,
58
+ members: false,
59
+ bans: true,
60
+ emojis: true,
61
+ integrations: true,
62
+ webhooks: true,
63
+ invites: true,
64
+ voice_states: true,
65
+ presences: false,
66
+ messages: true,
67
+ reactions: true,
68
+ typing: true,
69
+ dm_messages: true,
70
+ dm_reactions: true,
71
+ dm_typing: true,
72
+ message_content: nil,
73
+ scheduled_events: true,
74
+ automod_configuration: true,
75
+ automod_execution: true
76
+ )
70
77
  @raw_value = {
71
78
  guilds: guilds,
72
79
  members: members,
@@ -85,6 +92,8 @@ module Discorb
85
92
  dm_typing: dm_typing,
86
93
  message_content: message_content,
87
94
  scheduled_events: scheduled_events,
95
+ automod_configuration: automod_configuration,
96
+ automod_execution: automod_execution,
88
97
  }
89
98
  end
90
99
 
@@ -83,21 +83,25 @@ module Discorb
83
83
  when 3, 4, 5, 10
84
84
  option[:value]
85
85
  when 6
86
- members[option[:value]] || guild.members[option[:value]] || guild.fetch_member(option[:value]).wait
86
+ members[option[:value]] || guild && (guild.members[option[:value]] ||
87
+ guild.fetch_member(option[:value]).wait)
87
88
  when 7
88
- guild.channels[option[:value]] || guild.fetch_channels.wait.find do |channel|
89
- channel.id == option[:value]
89
+ if guild
90
+ guild.channels[option[:value]] || guild.fetch_channels.wait.find do |channel|
91
+ channel.id == option[:value]
92
+ end
90
93
  end
91
94
  when 8
92
- guild.roles[option[:value]] || guild.fetch_roles.wait.find { |role| role.id == option[:value] }
95
+ guild && (guild.roles[option[:value]] ||
96
+ guild.fetch_roles.wait.find { |role| role.id == option[:value] })
93
97
  when 9
94
98
  members[option[:value]] ||
95
- guild.members[option[:value]] ||
96
- guild.roles[option[:value]] ||
97
- guild.fetch_member(option[:value]).wait ||
98
- guild.fetch_roles.wait.find do |role|
99
- role.id == option[:value]
100
- end
99
+ guild && (guild.members[option[:value]] ||
100
+ guild.roles[option[:value]] ||
101
+ guild.fetch_member(option[:value]).wait ||
102
+ guild.fetch_roles.wait.find do |role|
103
+ role.id == option[:value]
104
+ end)
101
105
  when 11
102
106
  attachments[option[:value]]
103
107
  end
@@ -9,6 +9,8 @@ module Discorb
9
9
  # A module for response with source.
10
10
  #
11
11
  module SourceResponder
12
+ # @type instance: Discorb::Interaction
13
+
12
14
  #
13
15
  # Response with `DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE`(`5`).
14
16
  #
@@ -46,6 +48,8 @@ module Discorb
46
48
  # @param [Discorb::Embed] embed The embed to send.
47
49
  # @param [Array<Discorb::Embed>] embeds The embeds to send. (max: 10)
48
50
  # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions to send.
51
+ # @param [Discorb::Attachment] attachment The attachment to send.
52
+ # @param [Array<Discorb::Attachment>] attachments The attachments to send. (max: 10)
49
53
  # @param [Array<Discorb::Component>, Array<Array<Discorb::Component>>] components The components to send.
50
54
  # @param [Boolean] ephemeral Whether to make the response ephemeral.
51
55
  #
@@ -58,6 +62,8 @@ module Discorb
58
62
  embed: nil,
59
63
  embeds: nil,
60
64
  allowed_mentions: nil,
65
+ attachment: nil,
66
+ attachments: nil,
61
67
  components: nil,
62
68
  ephemeral: false
63
69
  )
@@ -70,23 +76,48 @@ module Discorb
70
76
  allowed_mentions&.to_hash(@client.allowed_mentions) || @client.allowed_mentions.to_hash
71
77
  payload[:components] = Component.to_payload(components) if components
72
78
  payload[:flags] = (ephemeral ? 1 << 6 : 0)
79
+ attachments ||= attachment ? [attachment] : []
80
+
81
+ payload[:attachments] = attachments.map.with_index do |a, i|
82
+ {
83
+ id: i,
84
+ filename: a.filename,
85
+ description: a.description,
86
+ }
87
+ end
73
88
 
74
89
  ret = if @responded
75
- _resp, data = @client.http.request(
76
- Route.new("/webhooks/#{@application_id}/#{@token}", "//webhooks/:webhook_id/:token", :post), payload
90
+ _resp, data = @client.http.multipart_request(
91
+ Route.new(
92
+ "/webhooks/#{@application_id}/#{@token}",
93
+ "//webhooks/:webhook_id/:token",
94
+ :post
95
+ ),
96
+ payload,
97
+ attachments
77
98
  ).wait
78
99
  webhook = Webhook::URLWebhook.new("/webhooks/#{@application_id}/#{@token}")
79
100
  Webhook::Message.new(webhook, data, @client)
80
101
  elsif @defered
81
- @client.http.request(
82
- Route.new("/webhooks/#{@application_id}/#{@token}/messages/@original",
83
- "//webhooks/:webhook_id/:token/messages/@original", :patch), payload
102
+ @client.http.multipart_request(
103
+ Route.new(
104
+ "/webhooks/#{@application_id}/#{@token}/messages/@original",
105
+ "//webhooks/:webhook_id/:token/messages/@original",
106
+ :patch
107
+ ),
108
+ payload,
109
+ attachments
84
110
  ).wait
85
111
  CallbackMessage.new(@client, payload, @application_id, @token)
86
112
  else
87
- @client.http.request(
88
- Route.new("/interactions/#{@id}/#{@token}/callback", "//interactions/:interaction_id/:token/callback",
89
- :post), { type: 4, data: payload }
113
+ @client.http.multipart_request(
114
+ Route.new(
115
+ "/interactions/#{@id}/#{@token}/callback",
116
+ "//interactions/:interaction_id/:token/callback",
117
+ :post
118
+ ),
119
+ { type: 4, data: payload },
120
+ attachments
90
121
  ).wait
91
122
  CallbackMessage.new(@client, payload, @application_id, @token)
92
123
  end
@@ -144,8 +175,13 @@ module Discorb
144
175
  files = [file] if file != Discorb::Unset
145
176
  files = [] if files == Discorb::Unset
146
177
  @client.http.multipart_request(
147
- Route.new("/webhooks/#{@application_id}/#{@token}/messages/@original",
148
- "//webhooks/:webhook_id/:token/messages/@original", :patch), payload, files, headers: headers,
178
+ Route.new(
179
+ "/webhooks/#{@application_id}/#{@token}/messages/@original",
180
+ "//webhooks/:webhook_id/:token/messages/@original",
181
+ :patch
182
+ ),
183
+ payload,
184
+ files,
149
185
  ).wait
150
186
  end
151
187
  end
@@ -176,6 +212,8 @@ module Discorb
176
212
  # A module for response with update.
177
213
  #
178
214
  module UpdateResponder
215
+ # @type instance: Discorb::Interaction
216
+
179
217
  #
180
218
  # Response with `DEFERRED_UPDATE_MESSAGE`(`6`).
181
219
  # @async
@@ -211,12 +249,24 @@ module Discorb
211
249
  # @param [Discorb::Embed] embed The embed to send.
212
250
  # @param [Array<Discorb::Embed>] embeds The embeds to send. (max: 10)
213
251
  # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions to send.
252
+ # @param [Discorb::Attachment] attachment The attachment to send.
253
+ # @param [Array<Discorb::Attachment>] attachments The attachments to send. (max: 10)
214
254
  # @param [Array<Discorb::Component>, Array<Array<Discorb::Component>>] components The components to send.
215
255
  # @param [Boolean] ephemeral Whether to make the response ephemeral.
216
256
  #
217
257
  # @return [Async::Task<void>] The task.
218
258
  #
219
- def edit(content, tts: false, embed: nil, embeds: nil, allowed_mentions: nil, components: nil, ephemeral: false)
259
+ def edit(
260
+ content,
261
+ tts: false,
262
+ embed: nil,
263
+ embeds: nil,
264
+ allowed_mentions: nil,
265
+ attachment: nil,
266
+ attachments: nil,
267
+ components: nil,
268
+ ephemeral: false
269
+ )
220
270
  Async do
221
271
  payload = {}
222
272
  payload[:content] = content if content
@@ -231,9 +281,17 @@ module Discorb
231
281
  allowed_mentions ? allowed_mentions.to_hash(@client.allowed_mentions) : @client.allowed_mentions.to_hash
232
282
  payload[:components] = Component.to_payload(components) if components
233
283
  payload[:flags] = (ephemeral ? 1 << 6 : 0)
234
- @client.http.request(
284
+ attachments ||= [attachment] if attachment
285
+ payload[:attachments] = attachments.map.with_index do |a, i|
286
+ {
287
+ id: i,
288
+ filename: a.filename,
289
+ description: a.description,
290
+ }
291
+ end
292
+ @client.http.multipart_request(
235
293
  Route.new("/interactions/#{@id}/#{@token}/callback", "//interactions/:interaction_id/:token/callback",
236
- :post), { type: 7, data: payload }
294
+ :post), { type: 7, data: payload }, attachments
237
295
  ).wait
238
296
  end
239
297
  end
@@ -243,6 +301,8 @@ module Discorb
243
301
  # A module for response with modal.
244
302
  #
245
303
  module ModalResponder
304
+ # @type instance: Discorb::Interaction
305
+
246
306
  #
247
307
  # Response with `MODAL`(`9`).
248
308
  #
@@ -263,7 +323,7 @@ module Discorb
263
323
 
264
324
  private
265
325
 
266
- def _set_data(*)
326
+ def _set_data(_)
267
327
  nil
268
328
  end
269
329
  end
@@ -52,10 +52,10 @@ module Discorb
52
52
  # @return [Discorb::Presence] The presence of the member.
53
53
  # @!attribute [r] activity
54
54
  # @macro client_cache
55
- # @return [Discorb::Activity] The activity of the member. It's from the {#presence}.
55
+ # @return [Discorb::Presence::Activity] The activity of the member. It's from the {#presence}.
56
56
  # @!attribute [r] activities
57
57
  # @macro client_cache
58
- # @return [Array<Discorb::Activity>] The activities of the member. It's from the {#presence}.
58
+ # @return [Array<Discorb::Presence::Activity>] The activities of the member. It's from the {#presence}.
59
59
  # @!attribute [r] status
60
60
  # @macro client_cache
61
61
  # @return [Symbol] The status of the member. It's from the {#presence}.
@@ -303,7 +303,7 @@ module Discorb
303
303
  @deaf = member_data[:deaf]
304
304
  @custom_avatar = member_data[:avatar] && Asset.new(self, member_data[:avatar])
305
305
  super(user_data)
306
- @display_avatar = @avatar || @custom_avatar
306
+ @display_avatar = @custom_avatar || @avatar
307
307
  @client.guilds[@guild_id].members[@id] = self unless @guild_id.nil? || @client.guilds[@guild_id].nil?
308
308
  @_member_data.update(member_data)
309
309
  end