discordrb 3.3.0 → 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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +152 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  5. data/.github/pull_request_template.md +37 -0
  6. data/.github/workflows/codeql.yml +65 -0
  7. data/.markdownlint.json +4 -0
  8. data/.rubocop.yml +39 -36
  9. data/CHANGELOG.md +874 -552
  10. data/Gemfile +2 -0
  11. data/LICENSE.txt +1 -1
  12. data/README.md +80 -86
  13. data/Rakefile +2 -0
  14. data/bin/console +1 -0
  15. data/discordrb-webhooks.gemspec +9 -6
  16. data/discordrb.gemspec +21 -18
  17. data/lib/discordrb/allowed_mentions.rb +36 -0
  18. data/lib/discordrb/api/application.rb +202 -0
  19. data/lib/discordrb/api/channel.rb +236 -47
  20. data/lib/discordrb/api/interaction.rb +54 -0
  21. data/lib/discordrb/api/invite.rb +5 -5
  22. data/lib/discordrb/api/server.rb +94 -66
  23. data/lib/discordrb/api/user.rb +17 -11
  24. data/lib/discordrb/api/webhook.rb +63 -6
  25. data/lib/discordrb/api.rb +55 -16
  26. data/lib/discordrb/await.rb +0 -1
  27. data/lib/discordrb/bot.rb +480 -93
  28. data/lib/discordrb/cache.rb +31 -24
  29. data/lib/discordrb/colour_rgb.rb +43 -0
  30. data/lib/discordrb/commands/command_bot.rb +35 -12
  31. data/lib/discordrb/commands/container.rb +21 -24
  32. data/lib/discordrb/commands/parser.rb +20 -20
  33. data/lib/discordrb/commands/rate_limiter.rb +4 -3
  34. data/lib/discordrb/container.rb +209 -20
  35. data/lib/discordrb/data/activity.rb +271 -0
  36. data/lib/discordrb/data/application.rb +50 -0
  37. data/lib/discordrb/data/attachment.rb +71 -0
  38. data/lib/discordrb/data/audit_logs.rb +345 -0
  39. data/lib/discordrb/data/channel.rb +993 -0
  40. data/lib/discordrb/data/component.rb +229 -0
  41. data/lib/discordrb/data/embed.rb +251 -0
  42. data/lib/discordrb/data/emoji.rb +82 -0
  43. data/lib/discordrb/data/integration.rb +122 -0
  44. data/lib/discordrb/data/interaction.rb +800 -0
  45. data/lib/discordrb/data/invite.rb +137 -0
  46. data/lib/discordrb/data/member.rb +372 -0
  47. data/lib/discordrb/data/message.rb +414 -0
  48. data/lib/discordrb/data/overwrite.rb +108 -0
  49. data/lib/discordrb/data/profile.rb +91 -0
  50. data/lib/discordrb/data/reaction.rb +33 -0
  51. data/lib/discordrb/data/recipient.rb +34 -0
  52. data/lib/discordrb/data/role.rb +248 -0
  53. data/lib/discordrb/data/server.rb +1004 -0
  54. data/lib/discordrb/data/user.rb +264 -0
  55. data/lib/discordrb/data/voice_region.rb +45 -0
  56. data/lib/discordrb/data/voice_state.rb +41 -0
  57. data/lib/discordrb/data/webhook.rb +238 -0
  58. data/lib/discordrb/data.rb +28 -4180
  59. data/lib/discordrb/errors.rb +46 -4
  60. data/lib/discordrb/events/bans.rb +7 -5
  61. data/lib/discordrb/events/channels.rb +3 -1
  62. data/lib/discordrb/events/guilds.rb +16 -9
  63. data/lib/discordrb/events/interactions.rb +482 -0
  64. data/lib/discordrb/events/invites.rb +125 -0
  65. data/lib/discordrb/events/members.rb +6 -2
  66. data/lib/discordrb/events/message.rb +72 -27
  67. data/lib/discordrb/events/presence.rb +35 -18
  68. data/lib/discordrb/events/raw.rb +1 -3
  69. data/lib/discordrb/events/reactions.rb +49 -4
  70. data/lib/discordrb/events/threads.rb +96 -0
  71. data/lib/discordrb/events/typing.rb +6 -4
  72. data/lib/discordrb/events/voice_server_update.rb +47 -0
  73. data/lib/discordrb/events/voice_state_update.rb +15 -10
  74. data/lib/discordrb/events/webhooks.rb +9 -6
  75. data/lib/discordrb/gateway.rb +99 -71
  76. data/lib/discordrb/id_object.rb +39 -0
  77. data/lib/discordrb/light/integrations.rb +1 -1
  78. data/lib/discordrb/light/light_bot.rb +1 -1
  79. data/lib/discordrb/logger.rb +4 -4
  80. data/lib/discordrb/paginator.rb +57 -0
  81. data/lib/discordrb/permissions.rb +159 -39
  82. data/lib/discordrb/version.rb +1 -1
  83. data/lib/discordrb/voice/encoder.rb +16 -7
  84. data/lib/discordrb/voice/network.rb +99 -47
  85. data/lib/discordrb/voice/sodium.rb +98 -0
  86. data/lib/discordrb/voice/voice_bot.rb +33 -25
  87. data/lib/discordrb/webhooks.rb +2 -0
  88. data/lib/discordrb.rb +107 -1
  89. metadata +126 -54
  90. data/.codeclimate.yml +0 -16
  91. data/.travis.yml +0 -33
  92. data/bin/travis_build_docs.sh +0 -17
  93. /data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +0 -0
@@ -5,7 +5,7 @@ module Discordrb::API::Webhook
5
5
  module_function
6
6
 
7
7
  # Get a webhook
8
- # https://discordapp.com/developers/docs/resources/webhook#get-webhook
8
+ # https://discord.com/developers/docs/resources/webhook#get-webhook
9
9
  def webhook(token, webhook_id)
10
10
  Discordrb::API.request(
11
11
  :webhooks_wid,
@@ -17,7 +17,7 @@ module Discordrb::API::Webhook
17
17
  end
18
18
 
19
19
  # Get a webhook via webhook token
20
- # https://discordapp.com/developers/docs/resources/webhook#get-webhook-with-token
20
+ # https://discord.com/developers/docs/resources/webhook#get-webhook-with-token
21
21
  def token_webhook(webhook_token, webhook_id)
22
22
  Discordrb::API.request(
23
23
  :webhooks_wid,
@@ -27,8 +27,30 @@ 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
- # https://discordapp.com/developers/docs/resources/webhook#modify-webhook
53
+ # https://discord.com/developers/docs/resources/webhook#modify-webhook
32
54
  def update_webhook(token, webhook_id, data, reason = nil)
33
55
  Discordrb::API.request(
34
56
  :webhooks_wid,
@@ -43,7 +65,7 @@ module Discordrb::API::Webhook
43
65
  end
44
66
 
45
67
  # Update a webhook via webhook token
46
- # https://discordapp.com/developers/docs/resources/webhook#modify-webhook-with-token
68
+ # https://discord.com/developers/docs/resources/webhook#modify-webhook-with-token
47
69
  def token_update_webhook(webhook_token, webhook_id, data, reason = nil)
48
70
  Discordrb::API.request(
49
71
  :webhooks_wid,
@@ -57,7 +79,7 @@ module Discordrb::API::Webhook
57
79
  end
58
80
 
59
81
  # Deletes a webhook
60
- # https://discordapp.com/developers/docs/resources/webhook#delete-webhook
82
+ # https://discord.com/developers/docs/resources/webhook#delete-webhook
61
83
  def delete_webhook(token, webhook_id, reason = nil)
62
84
  Discordrb::API.request(
63
85
  :webhooks_wid,
@@ -70,7 +92,7 @@ module Discordrb::API::Webhook
70
92
  end
71
93
 
72
94
  # Deletes a webhook via webhook token
73
- # https://discordapp.com/developers/docs/resources/webhook#delete-webhook-with-token
95
+ # https://discord.com/developers/docs/resources/webhook#delete-webhook-with-token
74
96
  def token_delete_webhook(webhook_token, webhook_id, reason = nil)
75
97
  Discordrb::API.request(
76
98
  :webhooks_wid,
@@ -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,10 +9,10 @@ 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://discordapp.com/api/v6'.freeze
12
+ APIBASE = 'https://discord.com/api/v9'
13
13
 
14
14
  # The URL of Discord's CDN
15
- CDN_URL = 'https://cdn.discordapp.com'.freeze
15
+ CDN_URL = 'https://cdn.discordapp.com'
16
16
 
17
17
  module_function
18
18
 
@@ -31,12 +31,12 @@ module Discordrb::API
31
31
  @cdn_url || CDN_URL
32
32
  end
33
33
 
34
- # @return [String] the bot name, previously specified using #bot_name=.
34
+ # @return [String] the bot name, previously specified using {.bot_name=}.
35
35
  def bot_name
36
36
  @bot_name
37
37
  end
38
38
 
39
- # Sets the bot name to something.
39
+ # Sets the bot name to something. Used in {.user_agent}. For the bot's username, see {Profile#username=}.
40
40
  def bot_name=(value)
41
41
  @bot_name = value
42
42
  end
@@ -51,7 +51,7 @@ module Discordrb::API
51
51
  # Generate a user agent identifying this requester as discordrb.
52
52
  def user_agent
53
53
  # This particular string is required by the Discord devs.
54
- required = "DiscordBot (https://github.com/meew0/discordrb, v#{Discordrb::VERSION})"
54
+ required = "DiscordBot (https://github.com/shardlab/discordrb, v#{Discordrb::VERSION})"
55
55
  @bot_name ||= ''
56
56
 
57
57
  "#{required} rest-client/#{RestClient::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} discordrb/#{Discordrb::VERSION} #{@bot_name}"
@@ -80,7 +80,7 @@ module Discordrb::API
80
80
  def raw_request(type, attributes)
81
81
  RestClient.send(type, *attributes)
82
82
  rescue RestClient::Forbidden => e
83
- # HACK: for #request, dynamically inject restclient's response into NoPermission - this allows us to ratelimit
83
+ # HACK: for #request, dynamically inject restclient's response into NoPermission - this allows us to rate limit
84
84
  noprm = Discordrb::Errors::NoPermission.new
85
85
  noprm.define_singleton_method(:_rc_response) { e.response }
86
86
  raise noprm, "The bot doesn't have the required permission to do this!"
@@ -112,6 +112,15 @@ module Discordrb::API
112
112
  response = raw_request(type, attributes)
113
113
  rescue RestClient::Exception => e
114
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
+
115
124
  raise e
116
125
  rescue Discordrb::Errors::NoPermission => e
117
126
  if e.respond_to?(:_rc_response)
@@ -134,7 +143,7 @@ module Discordrb::API
134
143
 
135
144
  unless mutex.locked?
136
145
  response = JSON.parse(e.response)
137
- 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
138
147
  Discordrb::LOGGER.ratelimit("Locking RL mutex (key: #{key}) for #{wait_seconds} seconds due to Discord rate limiting")
139
148
  trace("429 #{key.join(' ')}")
140
149
 
@@ -149,17 +158,12 @@ module Discordrb::API
149
158
  response
150
159
  end
151
160
 
152
- # Handles premeptive ratelimiting by waiting the given mutex by the difference of the Date header to the
161
+ # Handles pre-emptive rate limiting by waiting the given mutex by the difference of the Date header to the
153
162
  # X-Ratelimit-Reset header, thus making sure we don't get 429'd in any subsequent requests.
154
163
  def handle_preemptive_rl(headers, mutex, key)
155
164
  Discordrb::LOGGER.ratelimit "RL bucket depletion detected! Date: #{headers[:date]} Reset: #{headers[:x_ratelimit_reset]}"
156
-
157
- now = Time.rfc2822(headers[:date])
158
- reset = Time.at(headers[:x_ratelimit_reset].to_i)
159
-
160
- delta = reset - now
161
-
162
- Discordrb::LOGGER.warn("Locking RL mutex (key: #{key}) for #{delta} seconds preemptively")
165
+ delta = headers[:x_ratelimit_reset_after].to_f
166
+ Discordrb::LOGGER.warn("Locking RL mutex (key: #{key}) for #{delta} seconds pre-emptively")
163
167
  sync_wait(delta, mutex)
164
168
  end
165
169
 
@@ -175,7 +179,7 @@ module Discordrb::API
175
179
  Discordrb::LOGGER.ratelimit("Trace (#{reason}):")
176
180
 
177
181
  caller.each do |str|
178
- Discordrb::LOGGER.ratelimit(' ' + str)
182
+ Discordrb::LOGGER.ratelimit(" #{str}")
179
183
  end
180
184
  end
181
185
 
@@ -199,11 +203,34 @@ module Discordrb::API
199
203
  "#{cdn_url}/splashes/#{server_id}/#{splash_id}.#{format}"
200
204
  end
201
205
 
206
+ # Make a banner URL from server and banner IDs
207
+ def banner_url(server_id, banner_id, format = 'webp')
208
+ "#{cdn_url}/banners/#{server_id}/#{banner_id}.#{format}"
209
+ end
210
+
202
211
  # Make an emoji icon URL from emoji ID
203
212
  def emoji_icon_url(emoji_id, format = 'webp')
204
213
  "#{cdn_url}/emojis/#{emoji_id}.#{format}"
205
214
  end
206
215
 
216
+ # Make an asset URL from application and asset IDs
217
+ def asset_url(application_id, asset_id, format = 'webp')
218
+ "#{cdn_url}/app-assets/#{application_id}/#{asset_id}.#{format}"
219
+ end
220
+
221
+ # Make an achievement icon URL from application ID, achievement ID, and icon hash
222
+ def achievement_icon_url(application_id, achievement_id, icon_hash, format = 'webp')
223
+ "#{cdn_url}/app-assets/#{application_id}/achievements/#{achievement_id}/icons/#{icon_hash}.#{format}"
224
+ end
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
+
207
234
  # Login to the server
208
235
  def login(email, password)
209
236
  request(
@@ -290,6 +317,18 @@ module Discordrb::API
290
317
  )
291
318
  end
292
319
 
320
+ # Get the gateway to be used, with additional information for sharding and
321
+ # session start limits
322
+ def gateway_bot(token)
323
+ request(
324
+ :gateway_bot,
325
+ nil,
326
+ :get,
327
+ "#{api_base}/gateway/bot",
328
+ Authorization: token
329
+ )
330
+ end
331
+
293
332
  # Validate a token (this request will fail if the token is invalid)
294
333
  def validate_token(token)
295
334
  request(
@@ -43,7 +43,6 @@ module Discordrb
43
43
  dummy_handler = EventContainer.handler_class(@type).new(@attributes, @bot)
44
44
  return [nil, nil] unless event.instance_of?(@type) && dummy_handler.matches?(event)
45
45
 
46
- should_delete = nil
47
46
  should_delete = true if (@block && @block.call(event) != false) || !@block
48
47
 
49
48
  [@key, should_delete]