discordrb 3.3.0 → 3.5.0

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