discordrb 3.4.3 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
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(