discordrb 3.4.3 → 3.5.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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +44 -18
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
  5. data/.github/workflows/codeql.yml +65 -0
  6. data/.markdownlint.json +4 -0
  7. data/.rubocop.yml +8 -2
  8. data/CHANGELOG.md +390 -225
  9. data/LICENSE.txt +1 -1
  10. data/README.md +37 -25
  11. data/discordrb-webhooks.gemspec +4 -1
  12. data/discordrb.gemspec +9 -6
  13. data/lib/discordrb/api/application.rb +202 -0
  14. data/lib/discordrb/api/channel.rb +177 -11
  15. data/lib/discordrb/api/interaction.rb +54 -0
  16. data/lib/discordrb/api/invite.rb +2 -2
  17. data/lib/discordrb/api/server.rb +40 -19
  18. data/lib/discordrb/api/user.rb +8 -3
  19. data/lib/discordrb/api/webhook.rb +57 -0
  20. data/lib/discordrb/api.rb +19 -5
  21. data/lib/discordrb/bot.rb +317 -32
  22. data/lib/discordrb/cache.rb +27 -22
  23. data/lib/discordrb/commands/command_bot.rb +6 -4
  24. data/lib/discordrb/commands/container.rb +1 -1
  25. data/lib/discordrb/commands/parser.rb +2 -2
  26. data/lib/discordrb/commands/rate_limiter.rb +1 -1
  27. data/lib/discordrb/container.rb +132 -3
  28. data/lib/discordrb/data/attachment.rb +15 -0
  29. data/lib/discordrb/data/audit_logs.rb +3 -3
  30. data/lib/discordrb/data/channel.rb +167 -23
  31. data/lib/discordrb/data/component.rb +229 -0
  32. data/lib/discordrb/data/integration.rb +42 -3
  33. data/lib/discordrb/data/interaction.rb +800 -0
  34. data/lib/discordrb/data/invite.rb +1 -1
  35. data/lib/discordrb/data/member.rb +108 -33
  36. data/lib/discordrb/data/message.rb +99 -19
  37. data/lib/discordrb/data/overwrite.rb +13 -7
  38. data/lib/discordrb/data/role.rb +58 -1
  39. data/lib/discordrb/data/server.rb +82 -80
  40. data/lib/discordrb/data/user.rb +69 -9
  41. data/lib/discordrb/data/webhook.rb +97 -4
  42. data/lib/discordrb/data.rb +3 -0
  43. data/lib/discordrb/errors.rb +44 -3
  44. data/lib/discordrb/events/channels.rb +1 -1
  45. data/lib/discordrb/events/interactions.rb +482 -0
  46. data/lib/discordrb/events/message.rb +9 -6
  47. data/lib/discordrb/events/presence.rb +21 -14
  48. data/lib/discordrb/events/reactions.rb +0 -1
  49. data/lib/discordrb/events/threads.rb +96 -0
  50. data/lib/discordrb/gateway.rb +30 -17
  51. data/lib/discordrb/permissions.rb +59 -34
  52. data/lib/discordrb/version.rb +1 -1
  53. data/lib/discordrb/voice/encoder.rb +2 -2
  54. data/lib/discordrb/voice/network.rb +18 -7
  55. data/lib/discordrb/voice/sodium.rb +3 -1
  56. data/lib/discordrb/voice/voice_bot.rb +3 -3
  57. data/lib/discordrb/webhooks.rb +2 -0
  58. data/lib/discordrb.rb +37 -4
  59. metadata +48 -14
  60. data/.codeclimate.yml +0 -16
  61. data/.travis.yml +0 -32
  62. data/bin/travis_build_docs.sh +0 -17
@@ -49,11 +49,12 @@ module Discordrb::API::Channel
49
49
  # Get a list of messages from a channel's history
50
50
  # https://discord.com/developers/docs/resources/channel#get-channel-messages
51
51
  def messages(token, channel_id, amount, before = nil, after = nil, around = nil)
52
+ query_string = URI.encode_www_form({ limit: amount, before: before, after: after, around: around }.compact)
52
53
  Discordrb::API.request(
53
54
  :channels_cid_messages,
54
55
  channel_id,
55
56
  :get,
56
- "#{Discordrb::API.api_base}/channels/#{channel_id}/messages?limit=#{amount}#{"&before=#{before}" if before}#{"&after=#{after}" if after}#{"&around=#{around}" if around}",
57
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/messages?#{query_string}",
57
58
  Authorization: token
58
59
  )
59
60
  end
@@ -71,11 +72,11 @@ module Discordrb::API::Channel
71
72
  end
72
73
 
73
74
  # Send a message to a channel
74
- # https://discordapp.com/developers/docs/resources/channel#create-message
75
+ # https://discord.com/developers/docs/resources/channel#create-message
75
76
  # @param attachments [Array<File>, nil] Attachments to use with `attachment://` in embeds. See
76
77
  # https://discord.com/developers/docs/resources/channel#create-message-using-attachments-within-embeds
77
- def create_message(token, channel_id, message, tts = false, embed = nil, nonce = nil, attachments = nil, allowed_mentions = nil, message_reference = nil)
78
- body = { content: message, tts: tts, embed: embed, nonce: nonce, allowed_mentions: allowed_mentions, message_reference: message_reference }
78
+ def create_message(token, channel_id, message, tts = false, embeds = nil, nonce = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
79
+ body = { content: message, tts: tts, embeds: embeds, nonce: nonce, allowed_mentions: allowed_mentions, message_reference: message_reference, components: components&.to_a }
79
80
  body = if attachments
80
81
  files = [*0...attachments.size].zip(attachments).to_h
81
82
  { **files, payload_json: body.to_json }
@@ -116,20 +117,20 @@ module Discordrb::API::Channel
116
117
 
117
118
  # Edit a message
118
119
  # https://discord.com/developers/docs/resources/channel#edit-message
119
- def edit_message(token, channel_id, message_id, message, mentions = [], embed = nil)
120
+ def edit_message(token, channel_id, message_id, message, mentions = [], embeds = nil, components = nil)
120
121
  Discordrb::API.request(
121
122
  :channels_cid_messages_mid,
122
123
  channel_id,
123
124
  :patch,
124
125
  "#{Discordrb::API.api_base}/channels/#{channel_id}/messages/#{message_id}",
125
- { content: message, mentions: mentions, embed: embed }.to_json,
126
+ { content: message, mentions: mentions, embeds: embeds, components: components }.to_json,
126
127
  Authorization: token,
127
128
  content_type: :json
128
129
  )
129
130
  end
130
131
 
131
132
  # Delete a message
132
- # https://discordapp.com/developers/docs/resources/channel#delete-message
133
+ # https://discord.com/developers/docs/resources/channel#delete-message
133
134
  def delete_message(token, channel_id, message_id, reason = nil)
134
135
  Discordrb::API.request(
135
136
  :channels_cid_messages_mid,
@@ -142,7 +143,7 @@ module Discordrb::API::Channel
142
143
  end
143
144
 
144
145
  # Delete messages in bulk
145
- # https://discordapp.com/developers/docs/resources/channel#bulk-delete-messages
146
+ # https://discord.com/developers/docs/resources/channel#bulk-delete-messages
146
147
  def bulk_delete_messages(token, channel_id, messages = [], reason = nil)
147
148
  Discordrb::API.request(
148
149
  :channels_cid_messages_bulk_delete,
@@ -201,7 +202,7 @@ module Discordrb::API::Channel
201
202
  # https://discord.com/developers/docs/resources/channel#get-reactions
202
203
  def get_reactions(token, channel_id, message_id, emoji, before_id, after_id, limit = 100)
203
204
  emoji = URI.encode_www_form_component(emoji) unless emoji.ascii_only?
204
- query_string = "limit=#{limit}#{"&before=#{before_id}" if before_id}#{"&after=#{after_id}" if after_id}"
205
+ query_string = URI.encode_www_form({ limit: limit || 100, before: before_id, after: after_id }.compact)
205
206
  Discordrb::API.request(
206
207
  :channels_cid_messages_mid_reactions_emoji,
207
208
  channel_id,
@@ -223,6 +224,20 @@ module Discordrb::API::Channel
223
224
  )
224
225
  end
225
226
 
227
+ # Deletes all the reactions for a given emoji on a message
228
+ # https://discord.com/developers/docs/resources/channel#delete-all-reactions-for-emoji
229
+ def delete_all_emoji_reactions(token, channel_id, message_id, emoji)
230
+ emoji = URI.encode_www_form_component(emoji) unless emoji.ascii_only?
231
+
232
+ Discordrb::API.request(
233
+ :channels_cid_messages_mid_reactions_emoji,
234
+ channel_id,
235
+ :delete,
236
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/messages/#{message_id}/reactions/#{emoji}",
237
+ Authorization: token
238
+ )
239
+ end
240
+
226
241
  # Update a channels permission for a role or member
227
242
  # https://discord.com/developers/docs/resources/channel#edit-channel-permissions
228
243
  def update_permission(token, channel_id, overwrite_id, allow, deny, type, reason = nil)
@@ -304,7 +319,7 @@ module Discordrb::API::Channel
304
319
  end
305
320
 
306
321
  # Pin a message
307
- # https://discordapp.com/developers/docs/resources/channel#add-pinned-channel-message
322
+ # https://discord.com/developers/docs/resources/channel#add-pinned-channel-message
308
323
  def pin_message(token, channel_id, message_id, reason = nil)
309
324
  Discordrb::API.request(
310
325
  :channels_cid_pins_mid,
@@ -318,7 +333,7 @@ module Discordrb::API::Channel
318
333
  end
319
334
 
320
335
  # Unpin a message
321
- # https://discordapp.com/developers/docs/resources/channel#delete-pinned-channel-message
336
+ # https://discord.com/developers/docs/resources/channel#delete-pinned-channel-message
322
337
  def unpin_message(token, channel_id, message_id, reason = nil)
323
338
  Discordrb::API.request(
324
339
  :channels_cid_pins_mid,
@@ -331,6 +346,7 @@ module Discordrb::API::Channel
331
346
  end
332
347
 
333
348
  # Create an empty group channel.
349
+ # @deprecated Discord no longer supports bots in group DMs, this endpoint was repurposed and no longer works as implemented here.
334
350
  # https://discord.com/developers/docs/resources/user#create-group-dm
335
351
  def create_empty_group(token, bot_user_id)
336
352
  Discordrb::API.request(
@@ -345,6 +361,7 @@ module Discordrb::API::Channel
345
361
  end
346
362
 
347
363
  # Create a group channel.
364
+ # @deprecated Discord no longer supports bots in group DMs, this endpoint was repurposed and no longer works as implemented here.
348
365
  # https://discord.com/developers/docs/resources/channel#group-dm-add-recipient
349
366
  def create_group(token, pm_channel_id, user_id)
350
367
  Discordrb::API.request(
@@ -365,6 +382,7 @@ module Discordrb::API::Channel
365
382
  end
366
383
 
367
384
  # Add a user to a group channel.
385
+ # @deprecated Discord no longer supports bots in group DMs, this endpoint was repurposed and no longer works as implemented here.
368
386
  # https://discord.com/developers/docs/resources/channel#group-dm-add-recipient
369
387
  def add_group_user(token, group_channel_id, user_id)
370
388
  Discordrb::API.request(
@@ -379,6 +397,7 @@ module Discordrb::API::Channel
379
397
  end
380
398
 
381
399
  # Remove a user from a group channel.
400
+ # @deprecated Discord no longer supports bots in group DMs, this endpoint was repurposed and no longer works as implemented here.
382
401
  # https://discord.com/developers/docs/resources/channel#group-dm-remove-recipient
383
402
  def remove_group_user(token, group_channel_id, user_id)
384
403
  Discordrb::API.request(
@@ -392,6 +411,7 @@ module Discordrb::API::Channel
392
411
  end
393
412
 
394
413
  # Leave a group channel.
414
+ # @deprecated Discord no longer supports bots in group DMs, this endpoint was repurposed and no longer works as implemented here.
395
415
  # https://discord.com/developers/docs/resources/channel#deleteclose-channel
396
416
  def leave_group(token, group_channel_id)
397
417
  Discordrb::API.request(
@@ -430,4 +450,150 @@ module Discordrb::API::Channel
430
450
  Authorization: token
431
451
  )
432
452
  end
453
+
454
+ # Start a thread based off a channel message.
455
+ # https://discord.com/developers/docs/resources/channel#start-thread-with-message
456
+ def start_thread_with_message(token, channel_id, message_id, name, auto_archive_duration)
457
+ Discordrb::API.request(
458
+ :channels_cid_messages_mid_threads,
459
+ channel_id,
460
+ :post,
461
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/messages/#{message_id}/threads",
462
+ { name: name, auto_archive_duration: auto_archive_duration }.to_json,
463
+ Authorization: token,
464
+ content_type: :json
465
+ )
466
+ end
467
+
468
+ # Start a thread without an associated message.
469
+ # https://discord.com/developers/docs/resources/channel#start-thread-without-message
470
+ def start_thread_without_message(token, channel_id, name, auto_archive_duration, type = 11)
471
+ Discordrb::API.request(
472
+ :channels_cid_threads,
473
+ channel_id,
474
+ :post,
475
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/threads",
476
+ { name: name, auto_archive_duration: auto_archive_duration, type: type },
477
+ Authorization: token,
478
+ content_type: :json
479
+ )
480
+ end
481
+
482
+ # Add the current user to a thread.
483
+ # https://discord.com/developers/docs/resources/channel#join-thread
484
+ def join_thread(token, channel_id)
485
+ Discordrb::API.request(
486
+ :channels_cid_thread_members_me,
487
+ channel_id,
488
+ :put,
489
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/thread-members/@me",
490
+ nil,
491
+ Authorization: token
492
+ )
493
+ end
494
+
495
+ # Add a user to a thread.
496
+ # https://discord.com/developers/docs/resources/channel#add-thread-member
497
+ def add_thread_member(token, channel_id, user_id)
498
+ Discordrb::API.request(
499
+ :channels_cid_thread_members_uid,
500
+ channel_id,
501
+ :put,
502
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/thread-members/#{user_id}",
503
+ nil,
504
+ Authorization: token
505
+ )
506
+ end
507
+
508
+ # Remove the current user from a thread.
509
+ # https://discord.com/developers/docs/resources/channel#leave-thread
510
+ def leave_thread(token, channel_id)
511
+ Discordrb::API.request(
512
+ :channels_cid_thread_members_me,
513
+ channel_id,
514
+ :delete,
515
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/thread-members/#{user_id}",
516
+ Authorization: token
517
+ )
518
+ end
519
+
520
+ # Remove a user from a thread.
521
+ # https://discord.com/developers/docs/resources/channel#remove-thread-member
522
+ def remove_thread_member(token, channel_id, user_id)
523
+ Discordrb::API.request(
524
+ :channels_cid_thread_members_uid,
525
+ channel_id,
526
+ :delete,
527
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/thread-members/#{user_id}",
528
+ Authorization: token
529
+ )
530
+ end
531
+
532
+ # Get the members of a thread.
533
+ # https://discord.com/developers/docs/resources/channel#list-thread-members
534
+ def list_thread_members(token, channel_id, before, limit)
535
+ query = URI.encode_www_form({ before: before, limit: limit }.compact)
536
+
537
+ Discordrb::API.request(
538
+ :channels_cid_thread_members,
539
+ channel_id,
540
+ :get,
541
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/thread-members?#{query}",
542
+ Authorization: token
543
+ )
544
+ end
545
+
546
+ # List active threads
547
+ # https://discord.com/developers/docs/resources/channel#list-active-threads
548
+ def list_active_threads(token, channel_id)
549
+ Discordrb::API.request(
550
+ :channels_cid_threads_active,
551
+ channel_id,
552
+ :get,
553
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/threads/active",
554
+ Authorization: token
555
+ )
556
+ end
557
+
558
+ # List public archived threads.
559
+ # https://discord.com/developers/docs/resources/channel#list-public-archived-threads
560
+ def list_public_archived_threads(token, channel_id, before = nil, limit = nil)
561
+ query = URI.encode_www_form({ before: before, limit: limit }.compact)
562
+
563
+ Discordrb::API.request(
564
+ :channels_cid_threads_archived_public,
565
+ channel_id,
566
+ :get,
567
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/threads/archived/public?#{query}",
568
+ Authorization: token
569
+ )
570
+ end
571
+
572
+ # List private archived threads.
573
+ # https://discord.com/developers/docs/resources/channel#list-private-archived-threads
574
+ def list_private_archived_threads(token, channel_id, before = nil, limit = nil)
575
+ query = URI.encode_www_form({ before: before, limit: limit }.compact)
576
+
577
+ Discordrb::API.request(
578
+ :channels_cid_threads_archived_private,
579
+ channel_id,
580
+ :get,
581
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/threads/archived/private?#{query}",
582
+ Authorization: token
583
+ )
584
+ end
585
+
586
+ # List joined private archived threads.
587
+ # https://discord.com/developers/docs/resources/channel#list-joined-private-archived-threads
588
+ def list_joined_private_archived_threads(token, channel_id, before = nil, limit = nil)
589
+ query = URI.encode_www_form({ before: before, limit: limit }.compact)
590
+
591
+ Discordrb::API.request(
592
+ :channels_cid_users_me_threads_archived_private,
593
+ channel_id,
594
+ :get,
595
+ "#{Discordrb::API.api_base}/channels/#{channel_id}/users/@me/threads/archived/private?#{query}",
596
+ Authorization: token
597
+ )
598
+ end
433
599
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # API calls for interactions.
4
+ module Discordrb::API::Interaction
5
+ module_function
6
+
7
+ # Respond to an interaction.
8
+ # https://discord.com/developers/docs/interactions/slash-commands#create-interaction-response
9
+ def create_interaction_response(interaction_token, interaction_id, type, content = nil, tts = nil, embeds = nil, allowed_mentions = nil, flags = nil, components = nil)
10
+ data = { tts: tts, content: content, embeds: embeds, allowed_mentions: allowed_mentions, flags: flags, components: components }.compact
11
+
12
+ Discordrb::API.request(
13
+ :interactions_iid_token_callback,
14
+ interaction_id,
15
+ :post,
16
+ "#{Discordrb::API.api_base}/interactions/#{interaction_id}/#{interaction_token}/callback",
17
+ { type: type, data: data }.to_json,
18
+ content_type: :json
19
+ )
20
+ end
21
+
22
+ # Create a response that results in a modal.
23
+ # https://discord.com/developers/docs/interactions/slash-commands#create-interaction-response
24
+ def create_interaction_modal_response(interaction_token, interaction_id, custom_id, title, components)
25
+ data = { custom_id: custom_id, title: title, components: components.to_a }.compact
26
+
27
+ Discordrb::API.request(
28
+ :interactions_iid_token_callback,
29
+ interaction_id,
30
+ :post,
31
+ "#{Discordrb::API.api_base}/interactions/#{interaction_id}/#{interaction_token}/callback",
32
+ { type: 9, data: data }.to_json,
33
+ content_type: :json
34
+ )
35
+ end
36
+
37
+ # Get the original response to an interaction.
38
+ # https://discord.com/developers/docs/interactions/slash-commands#get-original-interaction-response
39
+ def get_original_interaction_response(interaction_token, application_id)
40
+ Discordrb::API::Webhook.token_get_message(interaction_token, application_id, '@original')
41
+ end
42
+
43
+ # Edit the original response to an interaction.
44
+ # https://discord.com/developers/docs/interactions/slash-commands#edit-original-interaction-response
45
+ def edit_original_interaction_response(interaction_token, application_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil)
46
+ Discordrb::API::Webhook.token_edit_message(interaction_token, application_id, '@original', content, embeds, allowed_mentions, components)
47
+ end
48
+
49
+ # Delete the original response to an interaction.
50
+ # https://discord.com/developers/docs/interactions/slash-commands#delete-original-interaction-response
51
+ def delete_original_interaction_response(interaction_token, application_id)
52
+ Discordrb::API::Webhook.token_delete_message(interaction_token, application_id, '@original')
53
+ end
54
+ end
@@ -11,7 +11,7 @@ module Discordrb::API::Invite
11
11
  :invite_code,
12
12
  nil,
13
13
  :get,
14
- "#{Discordrb::API.api_base}/invite/#{invite_code}#{counts ? '?with_counts=true' : ''}",
14
+ "#{Discordrb::API.api_base}/invites/#{invite_code}#{counts ? '?with_counts=true' : ''}",
15
15
  Authorization: token
16
16
  )
17
17
  end
@@ -36,7 +36,7 @@ module Discordrb::API::Invite
36
36
  :invite_code,
37
37
  nil,
38
38
  :post,
39
- "#{Discordrb::API.api_base}/invite/#{invite_code}",
39
+ "#{Discordrb::API.api_base}/invites/#{invite_code}",
40
40
  nil,
41
41
  Authorization: token
42
42
  )
@@ -128,18 +128,20 @@ module Discordrb::API::Server
128
128
  # Gets members from the server
129
129
  # https://discord.com/developers/docs/resources/guild#list-guild-members
130
130
  def resolve_members(token, server_id, limit, after = nil)
131
+ query_string = URI.encode_www_form({ limit: limit, after: after }.compact)
131
132
  Discordrb::API.request(
132
133
  :guilds_sid_members,
133
134
  server_id,
134
135
  :get,
135
- "#{Discordrb::API.api_base}/guilds/#{server_id}/members?limit=#{limit}#{"&after=#{after}" if after}",
136
+ "#{Discordrb::API.api_base}/guilds/#{server_id}/members?#{query_string}",
136
137
  Authorization: token
137
138
  )
138
139
  end
139
140
 
140
141
  # Update a user properties
141
142
  # https://discord.com/developers/docs/resources/guild#modify-guild-member
142
- def update_member(token, server_id, user_id, nick: nil, roles: nil, mute: nil, deaf: nil, channel_id: nil, reason: nil)
143
+ def update_member(token, server_id, user_id, nick: :undef, roles: :undef, mute: :undef, deaf: :undef, channel_id: :undef,
144
+ communication_disabled_until: :undef, reason: nil)
143
145
  Discordrb::API.request(
144
146
  :guilds_sid_members_uid,
145
147
  server_id,
@@ -149,8 +151,9 @@ module Discordrb::API::Server
149
151
  nick: nick,
150
152
  mute: mute,
151
153
  deaf: deaf,
152
- channel_id: channel_id
153
- }.compact.to_json,
154
+ channel_id: channel_id,
155
+ communication_disabled_until: communication_disabled_until
156
+ }.reject { |_, v| v == :undef }.to_json,
154
157
  Authorization: token,
155
158
  content_type: :json,
156
159
  'X-Audit-Log-Reason': reason
@@ -173,12 +176,13 @@ module Discordrb::API::Server
173
176
 
174
177
  # Get a server's banned users
175
178
  # https://discord.com/developers/docs/resources/guild#get-guild-bans
176
- def bans(token, server_id)
179
+ def bans(token, server_id, limit = nil, before = nil, after = nil)
180
+ query_string = URI.encode_www_form({ limit: limit, before: before, after: after }.compact)
177
181
  Discordrb::API.request(
178
182
  :guilds_sid_bans,
179
183
  server_id,
180
184
  :get,
181
- "#{Discordrb::API.api_base}/guilds/#{server_id}/bans",
185
+ "#{Discordrb::API.api_base}/guilds/#{server_id}/bans?#{query_string}",
182
186
  Authorization: token
183
187
  )
184
188
  end
@@ -191,7 +195,7 @@ module Discordrb::API::Server
191
195
  :guilds_sid_bans_uid,
192
196
  server_id,
193
197
  :put,
194
- "#{Discordrb::API.api_base}/guilds/#{server_id}/bans/#{user_id}?delete-message-days=#{message_days}&reason=#{reason}",
198
+ "#{Discordrb::API.api_base}/guilds/#{server_id}/bans/#{user_id}?delete_message_days=#{message_days}&reason=#{reason}",
195
199
  nil,
196
200
  Authorization: token
197
201
  )
@@ -245,13 +249,28 @@ module Discordrb::API::Server
245
249
  # sending TTS messages, embedding links, sending files, reading the history, mentioning everybody,
246
250
  # connecting to voice, speaking and voice activity (push-to-talk isn't mandatory)
247
251
  # https://discord.com/developers/docs/resources/guild#batch-modify-guild-role
248
- def update_role(token, server_id, role_id, name, colour, hoist = false, mentionable = false, packed_permissions = 104_324_161, reason = nil)
252
+ # @param icon [:undef, File]
253
+ def update_role(token, server_id, role_id, name, colour, hoist = false, mentionable = false, packed_permissions = 104_324_161, reason = nil, icon = :undef)
254
+ data = { color: colour, name: name, hoist: hoist, mentionable: mentionable, permissions: packed_permissions }
255
+
256
+ if icon != :undef && icon
257
+ path_method = %i[original_filename path local_path].find { |meth| icon.respond_to?(meth) }
258
+
259
+ raise ArgumentError, 'File object must respond to original_filename, path, or local path.' unless path_method
260
+ raise ArgumentError, 'File must respond to read' unless icon.respond_to? :read
261
+
262
+ mime_type = MIME::Types.type_for(icon.__send__(path_method)).first&.to_s || 'image/jpeg'
263
+ data[:icon] = "data:#{mime_type};base64,#{Base64.encode64(icon.read).strip}"
264
+ elsif icon.nil?
265
+ data[:icon] = nil
266
+ end
267
+
249
268
  Discordrb::API.request(
250
269
  :guilds_sid_roles_rid,
251
270
  server_id,
252
271
  :patch,
253
272
  "#{Discordrb::API.api_base}/guilds/#{server_id}/roles/#{role_id}",
254
- { color: colour, name: name, hoist: hoist, mentionable: mentionable, permissions: packed_permissions }.to_json,
273
+ data.to_json,
255
274
  Authorization: token,
256
275
  content_type: :json,
257
276
  'X-Audit-Log-Reason': reason
@@ -375,7 +394,7 @@ module Discordrb::API::Server
375
394
  end
376
395
 
377
396
  # Create a server integration
378
- # https://discordapp.com/developers/docs/resources/guild#create-guild-integration
397
+ # https://discord.com/developers/docs/resources/guild#create-guild-integration
379
398
  def create_integration(token, server_id, type, id, reason = nil)
380
399
  Discordrb::API.request(
381
400
  :guilds_sid_integrations,
@@ -403,7 +422,7 @@ module Discordrb::API::Server
403
422
  end
404
423
 
405
424
  # Delete a server integration
406
- # https://discordapp.com/developers/docs/resources/guild#delete-guild-integration
425
+ # https://discord.com/developers/docs/resources/guild#delete-guild-integration
407
426
  def delete_integration(token, server_id, integration_id, reason = nil)
408
427
  Discordrb::API.request(
409
428
  :guilds_sid_integrations_iid,
@@ -428,32 +447,34 @@ module Discordrb::API::Server
428
447
  )
429
448
  end
430
449
 
431
- # Retrieves a server's embed information
432
- # https://discord.com/developers/docs/resources/guild#get-guild-embed
433
- def embed(token, server_id)
450
+ # Retrieves a server's widget information
451
+ # https://discord.com/developers/docs/resources/guild#get-guild-widget
452
+ def widget(token, server_id)
434
453
  Discordrb::API.request(
435
454
  :guilds_sid_embed,
436
455
  server_id,
437
456
  :get,
438
- "#{Discordrb::API.api_base}/guilds/#{server_id}/embed",
457
+ "#{Discordrb::API.api_base}/guilds/#{server_id}/widget",
439
458
  Authorization: token
440
459
  )
441
460
  end
461
+ alias embed widget
442
462
 
443
- # Modify a server's embed settings
444
- # https://discord.com/developers/docs/resources/guild#modify-guild-embed
445
- def modify_embed(token, server_id, enabled, channel_id, reason = nil)
463
+ # Modify a server's widget settings
464
+ # https://discord.com/developers/docs/resources/guild#modify-guild-widget
465
+ def modify_widget(token, server_id, enabled, channel_id, reason = nil)
446
466
  Discordrb::API.request(
447
467
  :guilds_sid_embed,
448
468
  server_id,
449
469
  :patch,
450
- "#{Discordrb::API.api_base}/guilds/#{server_id}/embed",
470
+ "#{Discordrb::API.api_base}/guilds/#{server_id}/widget",
451
471
  { enabled: enabled, channel_id: channel_id }.to_json,
452
472
  Authorization: token,
453
473
  'X-Audit-Log-Reason': reason,
454
474
  content_type: :json
455
475
  )
456
476
  end
477
+ alias modify_embed modify_widget
457
478
 
458
479
  # Adds a custom emoji.
459
480
  # https://discord.com/developers/docs/resources/emoji#create-guild-emoji
@@ -132,9 +132,14 @@ module Discordrb::API::User
132
132
  )
133
133
  end
134
134
 
135
- # Returns one of the "default" discord avatars from the CDN given a discriminator
136
- def default_avatar(discrim = 0)
137
- index = discrim.to_i % 5
135
+ # Returns one of the "default" discord avatars from the CDN given a discriminator or id since new usernames
136
+ # TODO: Maybe change this method again after discriminator removal ?
137
+ def default_avatar(discrim_id = 0, legacy: false)
138
+ index = if legacy
139
+ discrim_id.to_i % 5
140
+ else
141
+ (discrim_id.to_i >> 22) % 5
142
+ end
138
143
  "#{Discordrb::API.cdn_url}/embed/avatars/#{index}.png"
139
144
  end
140
145
 
@@ -27,6 +27,28 @@ module Discordrb::API::Webhook
27
27
  )
28
28
  end
29
29
 
30
+ # Execute a webhook via token.
31
+ # https://discord.com/developers/docs/resources/webhook#execute-webhook
32
+ def token_execute_webhook(webhook_token, webhook_id, wait = false, content = nil, username = nil, avatar_url = nil, tts = nil, file = nil, embeds = nil, allowed_mentions = nil, flags = nil, components = nil)
33
+ body = { content: content, username: username, avatar_url: avatar_url, tts: tts, embeds: embeds&.map(&:to_hash), allowed_mentions: allowed_mentions, flags: flags, components: components }
34
+ body = if file
35
+ { file: file, payload_json: body.to_json }
36
+ else
37
+ body.to_json
38
+ end
39
+
40
+ headers = { content_type: :json } unless file
41
+
42
+ Discordrb::API.request(
43
+ :webhooks_wid,
44
+ webhook_id,
45
+ :post,
46
+ "#{Discordrb::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}?wait=#{wait}",
47
+ body,
48
+ headers
49
+ )
50
+ end
51
+
30
52
  # Update a webhook
31
53
  # https://discord.com/developers/docs/resources/webhook#modify-webhook
32
54
  def update_webhook(token, webhook_id, data, reason = nil)
@@ -80,4 +102,39 @@ module Discordrb::API::Webhook
80
102
  'X-Audit-Log-Reason': reason
81
103
  )
82
104
  end
105
+
106
+ # Get a message that was created by the webhook corresponding to the provided token.
107
+ # https://discord.com/developers/docs/resources/webhook#get-webhook-message
108
+ def token_get_message(webhook_token, webhook_id, message_id)
109
+ Discordrb::API.request(
110
+ :webhooks_wid_messages_mid,
111
+ webhook_id,
112
+ :get,
113
+ "#{Discordrb::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}/messages/#{message_id}"
114
+ )
115
+ end
116
+
117
+ # Edit a webhook message via webhook token
118
+ # https://discord.com/developers/docs/resources/webhook#edit-webhook-message
119
+ def token_edit_message(webhook_token, webhook_id, message_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil)
120
+ Discordrb::API.request(
121
+ :webhooks_wid_messages,
122
+ webhook_id,
123
+ :patch,
124
+ "#{Discordrb::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}/messages/#{message_id}",
125
+ { content: content, embeds: embeds, allowed_mentions: allowed_mentions, components: components }.to_json,
126
+ content_type: :json
127
+ )
128
+ end
129
+
130
+ # Delete a webhook message via webhook token.
131
+ # https://discord.com/developers/docs/resources/webhook#delete-webhook-message
132
+ def token_delete_message(webhook_token, webhook_id, message_id)
133
+ Discordrb::API.request(
134
+ :webhooks_wid_messages,
135
+ webhook_id,
136
+ :delete,
137
+ "#{Discordrb::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}/messages/#{message_id}"
138
+ )
139
+ end
83
140
  end
data/lib/discordrb/api.rb CHANGED
@@ -9,7 +9,7 @@ require 'discordrb/errors'
9
9
  # List of methods representing endpoints in Discord's API
10
10
  module Discordrb::API
11
11
  # The base URL of the Discord REST API.
12
- APIBASE = 'https://discord.com/api/v6'
12
+ APIBASE = 'https://discord.com/api/v9'
13
13
 
14
14
  # The URL of Discord's CDN
15
15
  CDN_URL = 'https://cdn.discordapp.com'
@@ -94,9 +94,6 @@ module Discordrb::API
94
94
  # Add a custom user agent
95
95
  attributes.last[:user_agent] = user_agent if attributes.last.is_a? Hash
96
96
 
97
- # Specify RateLimit precision
98
- attributes.last[:x_ratelimit_precision] = 'millisecond' if attributes.last.is_a?(Hash)
99
-
100
97
  # The most recent Discord rate limit requirements require the support of major parameters, where a particular route
101
98
  # and major parameter combination (*not* the HTTP method) uniquely identifies a RL bucket.
102
99
  key = [key, major_parameter].freeze
@@ -115,6 +112,15 @@ module Discordrb::API
115
112
  response = raw_request(type, attributes)
116
113
  rescue RestClient::Exception => e
117
114
  response = e.response
115
+
116
+ if response.body && !e.is_a?(RestClient::TooManyRequests)
117
+ data = JSON.parse(response.body)
118
+ err_klass = Discordrb::Errors.error_class_for(data['code'] || 0)
119
+ e = err_klass.new(data['message'], data['errors'])
120
+
121
+ Discordrb::LOGGER.error(e.full_message)
122
+ end
123
+
118
124
  raise e
119
125
  rescue Discordrb::Errors::NoPermission => e
120
126
  if e.respond_to?(:_rc_response)
@@ -137,7 +143,7 @@ module Discordrb::API
137
143
 
138
144
  unless mutex.locked?
139
145
  response = JSON.parse(e.response)
140
- wait_seconds = response['retry_after'].to_i / 1000.0
146
+ wait_seconds = response['retry_after'] ? response['retry_after'].to_f : e.response.headers[:retry_after].to_i
141
147
  Discordrb::LOGGER.ratelimit("Locking RL mutex (key: #{key}) for #{wait_seconds} seconds due to Discord rate limiting")
142
148
  trace("429 #{key.join(' ')}")
143
149
 
@@ -217,6 +223,14 @@ module Discordrb::API
217
223
  "#{cdn_url}/app-assets/#{application_id}/achievements/#{achievement_id}/icons/#{icon_hash}.#{format}"
218
224
  end
219
225
 
226
+ # @param role_id [String, Integer]
227
+ # @param icon_hash [String]
228
+ # @param format ['webp', 'png', 'jpeg']
229
+ # @return [String]
230
+ def role_icon_url(role_id, icon_hash, format = 'webp')
231
+ "#{cdn_url}/role-icons/#{role_id}/#{icon_hash}.#{format}"
232
+ end
233
+
220
234
  # Login to the server
221
235
  def login(email, password)
222
236
  request(