discordrb 3.5.0 → 3.6.1
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.
- checksums.yaml +4 -4
 - data/.devcontainer/Dockerfile +13 -0
 - data/.devcontainer/devcontainer.json +29 -0
 - data/.devcontainer/postcreate.sh +4 -0
 - data/.github/workflows/ci.yml +78 -0
 - data/.github/workflows/codeql.yml +3 -3
 - data/.github/workflows/deploy.yml +54 -0
 - data/.github/workflows/release.yml +51 -0
 - data/.rubocop.yml +52 -2
 - data/CHANGELOG.md +95 -0
 - data/README.md +5 -5
 - data/discordrb-webhooks.gemspec +1 -1
 - data/discordrb.gemspec +16 -11
 - data/lib/discordrb/api/application.rb +84 -8
 - data/lib/discordrb/api/channel.rb +51 -13
 - data/lib/discordrb/api/interaction.rb +15 -6
 - data/lib/discordrb/api/invite.rb +1 -1
 - data/lib/discordrb/api/server.rb +96 -60
 - data/lib/discordrb/api/user.rb +12 -2
 - data/lib/discordrb/api/webhook.rb +20 -5
 - data/lib/discordrb/api.rb +16 -20
 - data/lib/discordrb/bot.rb +139 -53
 - data/lib/discordrb/cache.rb +15 -1
 - data/lib/discordrb/commands/command_bot.rb +7 -17
 - data/lib/discordrb/commands/parser.rb +7 -7
 - data/lib/discordrb/container.rb +46 -0
 - data/lib/discordrb/data/activity.rb +1 -1
 - data/lib/discordrb/data/application.rb +1 -0
 - data/lib/discordrb/data/attachment.rb +23 -3
 - data/lib/discordrb/data/avatar_decoration.rb +26 -0
 - data/lib/discordrb/data/call.rb +22 -0
 - data/lib/discordrb/data/channel.rb +140 -15
 - data/lib/discordrb/data/collectibles.rb +45 -0
 - data/lib/discordrb/data/embed.rb +10 -3
 - data/lib/discordrb/data/emoji.rb +20 -1
 - data/lib/discordrb/data/integration.rb +3 -0
 - data/lib/discordrb/data/interaction.rb +164 -27
 - data/lib/discordrb/data/member.rb +145 -28
 - data/lib/discordrb/data/message.rb +198 -51
 - data/lib/discordrb/data/overwrite.rb +2 -0
 - data/lib/discordrb/data/primary_server.rb +60 -0
 - data/lib/discordrb/data/profile.rb +2 -7
 - data/lib/discordrb/data/reaction.rb +2 -1
 - data/lib/discordrb/data/recipient.rb +1 -1
 - data/lib/discordrb/data/role.rb +151 -22
 - data/lib/discordrb/data/server.rb +115 -41
 - data/lib/discordrb/data/server_preview.rb +68 -0
 - data/lib/discordrb/data/snapshot.rb +110 -0
 - data/lib/discordrb/data/user.rb +68 -8
 - data/lib/discordrb/data/voice_region.rb +1 -0
 - data/lib/discordrb/data/webhook.rb +2 -5
 - data/lib/discordrb/data.rb +6 -0
 - data/lib/discordrb/errors.rb +5 -2
 - data/lib/discordrb/events/await.rb +1 -1
 - data/lib/discordrb/events/channels.rb +37 -0
 - data/lib/discordrb/events/generic.rb +2 -0
 - data/lib/discordrb/events/guilds.rb +6 -1
 - data/lib/discordrb/events/interactions.rb +135 -42
 - data/lib/discordrb/events/invites.rb +2 -0
 - data/lib/discordrb/events/members.rb +19 -2
 - data/lib/discordrb/events/message.rb +39 -8
 - data/lib/discordrb/events/presence.rb +2 -0
 - data/lib/discordrb/events/raw.rb +1 -0
 - data/lib/discordrb/events/reactions.rb +2 -0
 - data/lib/discordrb/events/roles.rb +2 -0
 - data/lib/discordrb/events/threads.rb +10 -6
 - data/lib/discordrb/events/typing.rb +1 -0
 - data/lib/discordrb/events/voice_server_update.rb +1 -0
 - data/lib/discordrb/events/voice_state_update.rb +1 -0
 - data/lib/discordrb/events/webhooks.rb +1 -0
 - data/lib/discordrb/gateway.rb +29 -13
 - data/lib/discordrb/paginator.rb +3 -3
 - data/lib/discordrb/permissions.rb +54 -43
 - data/lib/discordrb/version.rb +1 -1
 - data/lib/discordrb/websocket.rb +0 -10
 - data/lib/discordrb.rb +17 -1
 - metadata +53 -28
 - data/.circleci/config.yml +0 -152
 
    
        data/lib/discordrb/api.rb
    CHANGED
    
    | 
         @@ -203,6 +203,11 @@ module Discordrb::API 
     | 
|
| 
       203 
203 
     | 
    
         
             
                "#{cdn_url}/splashes/#{server_id}/#{splash_id}.#{format}"
         
     | 
| 
       204 
204 
     | 
    
         
             
              end
         
     | 
| 
       205 
205 
     | 
    
         | 
| 
      
 206 
     | 
    
         
            +
              # Make a discovery splash URL from server and splash IDs
         
     | 
| 
      
 207 
     | 
    
         
            +
              def discovery_splash_url(server_id, splash_id, format = 'webp')
         
     | 
| 
      
 208 
     | 
    
         
            +
                "#{cdn_url}/discovery-splashes/#{server_id}/#{splash_id}.#{format}"
         
     | 
| 
      
 209 
     | 
    
         
            +
              end
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
       206 
211 
     | 
    
         
             
              # Make a banner URL from server and banner IDs
         
     | 
| 
       207 
212 
     | 
    
         
             
              def banner_url(server_id, banner_id, format = 'webp')
         
     | 
| 
       208 
213 
     | 
    
         
             
                "#{cdn_url}/banners/#{server_id}/#{banner_id}.#{format}"
         
     | 
| 
         @@ -231,28 +236,19 @@ module Discordrb::API 
     | 
|
| 
       231 
236 
     | 
    
         
             
                "#{cdn_url}/role-icons/#{role_id}/#{icon_hash}.#{format}"
         
     | 
| 
       232 
237 
     | 
    
         
             
              end
         
     | 
| 
       233 
238 
     | 
    
         | 
| 
       234 
     | 
    
         
            -
              #  
     | 
| 
       235 
     | 
    
         
            -
              def  
     | 
| 
       236 
     | 
    
         
            -
                 
     | 
| 
       237 
     | 
    
         
            -
                  :auth_login,
         
     | 
| 
       238 
     | 
    
         
            -
                  nil,
         
     | 
| 
       239 
     | 
    
         
            -
                  :post,
         
     | 
| 
       240 
     | 
    
         
            -
                  "#{api_base}/auth/login",
         
     | 
| 
       241 
     | 
    
         
            -
                  email: email,
         
     | 
| 
       242 
     | 
    
         
            -
                  password: password
         
     | 
| 
       243 
     | 
    
         
            -
                )
         
     | 
| 
      
 239 
     | 
    
         
            +
              # make an avatar decoration URL from an avatar decoration ID.
         
     | 
| 
      
 240 
     | 
    
         
            +
              def avatar_decoration_url(avatar_decoration_id, format = 'png')
         
     | 
| 
      
 241 
     | 
    
         
            +
                "#{cdn_url}/avatar-decoration-presets/#{avatar_decoration_id}.#{format}"
         
     | 
| 
       244 
242 
     | 
    
         
             
              end
         
     | 
| 
       245 
243 
     | 
    
         | 
| 
       246 
     | 
    
         
            -
              #  
     | 
| 
       247 
     | 
    
         
            -
              def  
     | 
| 
       248 
     | 
    
         
            -
                 
     | 
| 
       249 
     | 
    
         
            -
             
     | 
| 
       250 
     | 
    
         
            -
             
     | 
| 
       251 
     | 
    
         
            -
             
     | 
| 
       252 
     | 
    
         
            -
             
     | 
| 
       253 
     | 
    
         
            -
             
     | 
| 
       254 
     | 
    
         
            -
                  Authorization: token
         
     | 
| 
       255 
     | 
    
         
            -
                )
         
     | 
| 
      
 244 
     | 
    
         
            +
              # make a nameplate URL from the nameplate asset.
         
     | 
| 
      
 245 
     | 
    
         
            +
              def nameplate_url(nameplate_asset, format = 'webm')
         
     | 
| 
      
 246 
     | 
    
         
            +
                "#{cdn_url}/assets/collectibles/#{nameplate_asset.delete_suffix('/')}/asset.#{format}"
         
     | 
| 
      
 247 
     | 
    
         
            +
              end
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
              # make a server tag badge URL from a server ID and badge ID.
         
     | 
| 
      
 250 
     | 
    
         
            +
              def server_tag_badge_url(server_id, badge_id, format = 'webp')
         
     | 
| 
      
 251 
     | 
    
         
            +
                "#{cdn_url}/guild-tag-badges/#{server_id}/#{badge_id}.#{format}"
         
     | 
| 
       256 
252 
     | 
    
         
             
              end
         
     | 
| 
       257 
253 
     | 
    
         | 
| 
       258 
254 
     | 
    
         
             
              # Create an OAuth application
         
     | 
    
        data/lib/discordrb/bot.rb
    CHANGED
    
    | 
         @@ -2,7 +2,6 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require 'rest-client'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'zlib'
         
     | 
| 
       5 
     | 
    
         
            -
            require 'set'
         
     | 
| 
       6 
5 
     | 
    
         | 
| 
       7 
6 
     | 
    
         
             
            require 'discordrb/events/message'
         
     | 
| 
       8 
7 
     | 
    
         
             
            require 'discordrb/events/typing'
         
     | 
| 
         @@ -107,9 +106,10 @@ module Discordrb 
     | 
|
| 
       107 
106 
     | 
    
         
             
                #   to Discord's gateway. `:none` will request that no payloads are received compressed (not recommended for
         
     | 
| 
       108 
107 
     | 
    
         
             
                #   production bots). `:large` will request that large payloads are received compressed. `:stream` will request
         
     | 
| 
       109 
108 
     | 
    
         
             
                #   that all data be received in a continuous compressed stream.
         
     | 
| 
       110 
     | 
    
         
            -
                # @param intents [:all, :unprivileged, Array<Symbol>, :none] Gateway intents that this bot requires. `:all` will
         
     | 
| 
      
 109 
     | 
    
         
            +
                # @param intents [:all, :unprivileged, Array<Symbol>, :none, Integer] Gateway intents that this bot requires. `:all` will
         
     | 
| 
       111 
110 
     | 
    
         
             
                #   request all intents. `:unprivileged` will request only intents that are not defined as "Privileged". `:none`
         
     | 
| 
       112 
     | 
    
         
            -
                #   will request no intents. An array of symbols will request only those intents specified.
         
     | 
| 
      
 111 
     | 
    
         
            +
                #   will request no intents. An array of symbols will request only those intents specified. An integer value will request
         
     | 
| 
      
 112 
     | 
    
         
            +
                #   exactly all the intents specified in the bitwise value.
         
     | 
| 
       113 
113 
     | 
    
         
             
                # @see Discordrb::INTENTS
         
     | 
| 
       114 
114 
     | 
    
         
             
                def initialize(
         
     | 
| 
       115 
115 
     | 
    
         
             
                  log_mode: :normal,
         
     | 
| 
         @@ -307,13 +307,21 @@ module Discordrb 
     | 
|
| 
       307 
307 
     | 
    
         
             
                # Creates an OAuth invite URL that can be used to invite this bot to a particular server.
         
     | 
| 
       308 
308 
     | 
    
         
             
                # @param server [Server, nil] The server the bot should be invited to, or nil if a general invite should be created.
         
     | 
| 
       309 
309 
     | 
    
         
             
                # @param permission_bits [String, Integer] Permission bits that should be appended to invite url.
         
     | 
| 
      
 310 
     | 
    
         
            +
                # @param redirect_uri [String] Redirect URI that should be appended to invite url.
         
     | 
| 
      
 311 
     | 
    
         
            +
                # @param scopes [Array<String>] Scopes that should be appended to invite url.
         
     | 
| 
       310 
312 
     | 
    
         
             
                # @return [String] the OAuth invite URL.
         
     | 
| 
       311 
     | 
    
         
            -
                def invite_url(server: nil, permission_bits: nil)
         
     | 
| 
      
 313 
     | 
    
         
            +
                def invite_url(server: nil, permission_bits: nil, redirect_uri: nil, scopes: ['bot'])
         
     | 
| 
       312 
314 
     | 
    
         
             
                  @client_id ||= bot_application.id
         
     | 
| 
       313 
315 
     | 
    
         | 
| 
       314 
     | 
    
         
            -
                   
     | 
| 
       315 
     | 
    
         
            -
             
     | 
| 
       316 
     | 
    
         
            -
             
     | 
| 
      
 316 
     | 
    
         
            +
                  query = URI.encode_www_form({
         
     | 
| 
      
 317 
     | 
    
         
            +
                    client_id: @client_id,
         
     | 
| 
      
 318 
     | 
    
         
            +
                    guild_id: server&.id,
         
     | 
| 
      
 319 
     | 
    
         
            +
                    permissions: permission_bits,
         
     | 
| 
      
 320 
     | 
    
         
            +
                    redirect_uri: redirect_uri,
         
     | 
| 
      
 321 
     | 
    
         
            +
                    scope: scopes.join(' ')
         
     | 
| 
      
 322 
     | 
    
         
            +
                  }.compact)
         
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
                  "https://discord.com/oauth2/authorize?#{query}"
         
     | 
| 
       317 
325 
     | 
    
         
             
                end
         
     | 
| 
       318 
326 
     | 
    
         | 
| 
       319 
327 
     | 
    
         
             
                # @return [Hash<Integer => VoiceBot>] the voice connections this bot currently has, by the server ID to which they are connected.
         
     | 
| 
         @@ -392,17 +400,20 @@ module Discordrb 
     | 
|
| 
       392 
400 
     | 
    
         
             
                # @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
         
     | 
| 
       393 
401 
     | 
    
         
             
                # @param embeds [Hash, Discordrb::Webhooks::Embed, Array<Hash>, Array<Discordrb::Webhooks::Embed> nil] The rich embed(s) to append to this message.
         
     | 
| 
       394 
402 
     | 
    
         
             
                # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
         
     | 
| 
       395 
     | 
    
         
            -
                # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
         
     | 
| 
      
 403 
     | 
    
         
            +
                # @param message_reference [Message, String, Integer, Hash, nil] The message, or message ID, to reply to if any.
         
     | 
| 
       396 
404 
     | 
    
         
             
                # @param components [View, Array<Hash>] Interaction components to associate with this message.
         
     | 
| 
      
 405 
     | 
    
         
            +
                # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
         
     | 
| 
      
 406 
     | 
    
         
            +
                # @param nonce [String, nil] A optional nonce in order to verify that a message was sent. Maximum of twenty-five characters.
         
     | 
| 
      
 407 
     | 
    
         
            +
                # @param enforce_nonce [true, false] whether the nonce should be enforced and used for message de-duplication.
         
     | 
| 
       397 
408 
     | 
    
         
             
                # @return [Message] The message that was sent.
         
     | 
| 
       398 
     | 
    
         
            -
                def send_message(channel, content, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
         
     | 
| 
      
 409 
     | 
    
         
            +
                def send_message(channel, content, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, nonce = nil, enforce_nonce = false)
         
     | 
| 
       399 
410 
     | 
    
         
             
                  channel = channel.resolve_id
         
     | 
| 
       400 
411 
     | 
    
         
             
                  debug("Sending message to #{channel} with content '#{content}'")
         
     | 
| 
       401 
412 
     | 
    
         
             
                  allowed_mentions = { parse: [] } if allowed_mentions == false
         
     | 
| 
       402 
     | 
    
         
            -
                  message_reference = { message_id: message_reference. 
     | 
| 
      
 413 
     | 
    
         
            +
                  message_reference = { message_id: message_reference.resolve_id } if message_reference.respond_to?(:resolve_id)
         
     | 
| 
       403 
414 
     | 
    
         
             
                  embeds = (embeds.instance_of?(Array) ? embeds.map(&:to_hash) : [embeds&.to_hash]).compact
         
     | 
| 
       404 
415 
     | 
    
         | 
| 
       405 
     | 
    
         
            -
                  response = API::Channel.create_message(token, channel, content, tts, embeds,  
     | 
| 
      
 416 
     | 
    
         
            +
                  response = API::Channel.create_message(token, channel, content, tts, embeds, nonce, attachments, allowed_mentions&.to_hash, message_reference, components, flags, enforce_nonce)
         
     | 
| 
       406 
417 
     | 
    
         
             
                  Message.new(JSON.parse(response), self)
         
     | 
| 
       407 
418 
     | 
    
         
             
                end
         
     | 
| 
       408 
419 
     | 
    
         | 
| 
         @@ -417,11 +428,14 @@ module Discordrb 
     | 
|
| 
       417 
428 
     | 
    
         
             
                # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
         
     | 
| 
       418 
429 
     | 
    
         
             
                # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
         
     | 
| 
       419 
430 
     | 
    
         
             
                # @param components [View, Array<Hash>] Interaction components to associate with this message.
         
     | 
| 
       420 
     | 
    
         
            -
                 
     | 
| 
      
 431 
     | 
    
         
            +
                # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
         
     | 
| 
      
 432 
     | 
    
         
            +
                # @param nonce [String, nil] A optional nonce in order to verify that a message was sent. Maximum of twenty-five characters.
         
     | 
| 
      
 433 
     | 
    
         
            +
                # @param enforce_nonce [true, false] whether the nonce should be enforced and used for message de-duplication.
         
     | 
| 
      
 434 
     | 
    
         
            +
                def send_temporary_message(channel, content, timeout, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, nonce = nil, enforce_nonce = false)
         
     | 
| 
       421 
435 
     | 
    
         
             
                  Thread.new do
         
     | 
| 
       422 
436 
     | 
    
         
             
                    Thread.current[:discordrb_name] = "#{@current_thread}-temp-msg"
         
     | 
| 
       423 
437 
     | 
    
         | 
| 
       424 
     | 
    
         
            -
                    message = send_message(channel, content, tts, embeds, attachments, allowed_mentions, message_reference, components)
         
     | 
| 
      
 438 
     | 
    
         
            +
                    message = send_message(channel, content, tts, embeds, attachments, allowed_mentions, message_reference, components, flags, nonce, enforce_nonce)
         
     | 
| 
       425 
439 
     | 
    
         
             
                    sleep(timeout)
         
     | 
| 
       426 
440 
     | 
    
         
             
                    message.delete
         
     | 
| 
       427 
441 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -455,20 +469,6 @@ module Discordrb 
     | 
|
| 
       455 
469 
     | 
    
         
             
                  Message.new(JSON.parse(response), self)
         
     | 
| 
       456 
470 
     | 
    
         
             
                end
         
     | 
| 
       457 
471 
     | 
    
         | 
| 
       458 
     | 
    
         
            -
                # Creates a server on Discord with a specified name and a region.
         
     | 
| 
       459 
     | 
    
         
            -
                # @note Discord's API doesn't directly return the server when creating it, so this method
         
     | 
| 
       460 
     | 
    
         
            -
                #   waits until the data has been received via the websocket. This may make the execution take a while.
         
     | 
| 
       461 
     | 
    
         
            -
                # @param name [String] The name the new server should have. Doesn't have to be alphanumeric.
         
     | 
| 
       462 
     | 
    
         
            -
                # @param region [Symbol] The region where the server should be created, for example 'eu-central' or 'hongkong'.
         
     | 
| 
       463 
     | 
    
         
            -
                # @return [Server] The server that was created.
         
     | 
| 
       464 
     | 
    
         
            -
                def create_server(name, region = :'eu-central')
         
     | 
| 
       465 
     | 
    
         
            -
                  response = API::Server.create(token, name, region)
         
     | 
| 
       466 
     | 
    
         
            -
                  id = JSON.parse(response)['id'].to_i
         
     | 
| 
       467 
     | 
    
         
            -
                  sleep 0.1 until (server = @servers[id])
         
     | 
| 
       468 
     | 
    
         
            -
                  debug "Successfully created server #{server.id} with name #{server.name}"
         
     | 
| 
       469 
     | 
    
         
            -
                  server
         
     | 
| 
       470 
     | 
    
         
            -
                end
         
     | 
| 
       471 
     | 
    
         
            -
             
     | 
| 
       472 
472 
     | 
    
         
             
                # Creates a new application to do OAuth authorization with. This allows you to use OAuth to authorize users using
         
     | 
| 
       473 
473 
     | 
    
         
             
                # Discord. For information how to use this, see the docs: https://discord.com/developers/docs/topics/oauth2
         
     | 
| 
       474 
474 
     | 
    
         
             
                # @param name [String] What your application should be called.
         
     | 
| 
         @@ -517,7 +517,7 @@ module Discordrb 
     | 
|
| 
       517 
517 
     | 
    
         
             
                        end
         
     | 
| 
       518 
518 
     | 
    
         
             
                      end
         
     | 
| 
       519 
519 
     | 
    
         
             
                    elsif /(?<animated>^a|^${0}):(?<name>\w+):(?<id>\d+)/ =~ mention
         
     | 
| 
       520 
     | 
    
         
            -
                      array_to_return << (emoji(id) || Emoji.new({ 'animated' =>  
     | 
| 
      
 520 
     | 
    
         
            +
                      array_to_return << (emoji(id) || Emoji.new({ 'animated' => animated != '', 'name' => name, 'id' => id }, self, nil))
         
     | 
| 
       521 
521 
     | 
    
         
             
                    end
         
     | 
| 
       522 
522 
     | 
    
         
             
                  end
         
     | 
| 
       523 
523 
     | 
    
         
             
                  array_to_return
         
     | 
| 
         @@ -824,7 +824,7 @@ module Discordrb 
     | 
|
| 
       824 
824 
     | 
    
         
             
                #       end
         
     | 
| 
       825 
825 
     | 
    
         
             
                #     end
         
     | 
| 
       826 
826 
     | 
    
         
             
                #   end
         
     | 
| 
       827 
     | 
    
         
            -
                def register_application_command(name, description, server_id: nil, default_permission: nil, type: :chat_input)
         
     | 
| 
      
 827 
     | 
    
         
            +
                def register_application_command(name, description, server_id: nil, default_permission: nil, type: :chat_input, default_member_permissions: nil, contexts: nil, nsfw: false)
         
     | 
| 
       828 
828 
     | 
    
         
             
                  type = ApplicationCommand::TYPES[type] || type
         
     | 
| 
       829 
829 
     | 
    
         | 
| 
       830 
830 
     | 
    
         
             
                  builder = Interactions::OptionBuilder.new
         
     | 
| 
         @@ -832,9 +832,9 @@ module Discordrb 
     | 
|
| 
       832 
832 
     | 
    
         
             
                  yield(builder, permission_builder) if block_given?
         
     | 
| 
       833 
833 
     | 
    
         | 
| 
       834 
834 
     | 
    
         
             
                  resp = if server_id
         
     | 
| 
       835 
     | 
    
         
            -
                           API::Application.create_guild_command(@token, profile.id, server_id, name, description, builder.to_a, default_permission, type)
         
     | 
| 
      
 835 
     | 
    
         
            +
                           API::Application.create_guild_command(@token, profile.id, server_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, nsfw)
         
     | 
| 
       836 
836 
     | 
    
         
             
                         else
         
     | 
| 
       837 
     | 
    
         
            -
                           API::Application.create_global_command(@token, profile.id, name, description, builder.to_a, default_permission, type)
         
     | 
| 
      
 837 
     | 
    
         
            +
                           API::Application.create_global_command(@token, profile.id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, nsfw)
         
     | 
| 
       838 
838 
     | 
    
         
             
                         end
         
     | 
| 
       839 
839 
     | 
    
         
             
                  cmd = ApplicationCommand.new(JSON.parse(resp), self, server_id)
         
     | 
| 
       840 
840 
     | 
    
         | 
| 
         @@ -849,7 +849,7 @@ module Discordrb 
     | 
|
| 
       849 
849 
     | 
    
         | 
| 
       850 
850 
     | 
    
         
             
                # @yieldparam [OptionBuilder]
         
     | 
| 
       851 
851 
     | 
    
         
             
                # @yieldparam [PermissionBuilder]
         
     | 
| 
       852 
     | 
    
         
            -
                def edit_application_command(command_id, server_id: nil, name: nil, description: nil, default_permission: nil, type: :chat_input)
         
     | 
| 
      
 852 
     | 
    
         
            +
                def edit_application_command(command_id, server_id: nil, name: nil, description: nil, default_permission: nil, type: :chat_input, default_member_permissions: nil, contexts: nil, nsfw: nil)
         
     | 
| 
       853 
853 
     | 
    
         
             
                  type = ApplicationCommand::TYPES[type] || type
         
     | 
| 
       854 
854 
     | 
    
         | 
| 
       855 
855 
     | 
    
         
             
                  builder = Interactions::OptionBuilder.new
         
     | 
| 
         @@ -858,9 +858,9 @@ module Discordrb 
     | 
|
| 
       858 
858 
     | 
    
         
             
                  yield(builder, permission_builder) if block_given?
         
     | 
| 
       859 
859 
     | 
    
         | 
| 
       860 
860 
     | 
    
         
             
                  resp = if server_id
         
     | 
| 
       861 
     | 
    
         
            -
                           API::Application.edit_guild_command(@token, profile.id, server_id, command_id, name, description, builder.to_a, default_permission, type)
         
     | 
| 
      
 861 
     | 
    
         
            +
                           API::Application.edit_guild_command(@token, profile.id, server_id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, nsfw)
         
     | 
| 
       862 
862 
     | 
    
         
             
                         else
         
     | 
| 
       863 
     | 
    
         
            -
                           API::Application. 
     | 
| 
      
 863 
     | 
    
         
            +
                           API::Application.edit_global_command(@token, profile.id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, nsfw)
         
     | 
| 
       864 
864 
     | 
    
         
             
                         end
         
     | 
| 
       865 
865 
     | 
    
         
             
                  cmd = ApplicationCommand.new(JSON.parse(resp), self, server_id)
         
     | 
| 
       866 
866 
     | 
    
         | 
| 
         @@ -895,6 +895,46 @@ module Discordrb 
     | 
|
| 
       895 
895 
     | 
    
         
             
                  API::Application.edit_guild_command_permissions(@token, profile.id, server_id, command_id, permissions)
         
     | 
| 
       896 
896 
     | 
    
         
             
                end
         
     | 
| 
       897 
897 
     | 
    
         | 
| 
      
 898 
     | 
    
         
            +
                # Fetches all the application emojis that the bot can use.
         
     | 
| 
      
 899 
     | 
    
         
            +
                # @return [Array<Emoji>] Returns an array of emoji objects.
         
     | 
| 
      
 900 
     | 
    
         
            +
                def application_emojis
         
     | 
| 
      
 901 
     | 
    
         
            +
                  response = API::Application.list_application_emojis(@token, profile.id)
         
     | 
| 
      
 902 
     | 
    
         
            +
                  JSON.parse(response)['items'].map { |emoji| Emoji.new(emoji, self) }
         
     | 
| 
      
 903 
     | 
    
         
            +
                end
         
     | 
| 
      
 904 
     | 
    
         
            +
             
     | 
| 
      
 905 
     | 
    
         
            +
                # Fetches a single application emoji from its ID.
         
     | 
| 
      
 906 
     | 
    
         
            +
                # @param emoji_id [Integer, String] ID of the application emoji.
         
     | 
| 
      
 907 
     | 
    
         
            +
                # @return [Emoji] The application emoji.
         
     | 
| 
      
 908 
     | 
    
         
            +
                def application_emoji(emoji_id)
         
     | 
| 
      
 909 
     | 
    
         
            +
                  response = API::Application.get_application_emoji(@token, profile.id, emoji_id.resolve_id)
         
     | 
| 
      
 910 
     | 
    
         
            +
                  Emoji.new(JSON.parse(response), self)
         
     | 
| 
      
 911 
     | 
    
         
            +
                end
         
     | 
| 
      
 912 
     | 
    
         
            +
             
     | 
| 
      
 913 
     | 
    
         
            +
                # Creates a new custom emoji that can be used by this application.
         
     | 
| 
      
 914 
     | 
    
         
            +
                # @param name [String] The name of emoji to create.
         
     | 
| 
      
 915 
     | 
    
         
            +
                # @param image [String, #read] Base64 string with the image data, or an object that responds to #read.
         
     | 
| 
      
 916 
     | 
    
         
            +
                # @return [Emoji] The emoji that has been created.
         
     | 
| 
      
 917 
     | 
    
         
            +
                def create_application_emoji(name:, image:)
         
     | 
| 
      
 918 
     | 
    
         
            +
                  image = image.respond_to?(:read) ? Discordrb.encode64(image) : image
         
     | 
| 
      
 919 
     | 
    
         
            +
                  response = API::Application.create_application_emoji(@token, profile.id, name, image)
         
     | 
| 
      
 920 
     | 
    
         
            +
                  Emoji.new(JSON.parse(response), self)
         
     | 
| 
      
 921 
     | 
    
         
            +
                end
         
     | 
| 
      
 922 
     | 
    
         
            +
             
     | 
| 
      
 923 
     | 
    
         
            +
                # Edits an existing application emoji.
         
     | 
| 
      
 924 
     | 
    
         
            +
                # @param emoji_id [Integer, String, Emoji] ID of the application emoji to edit.
         
     | 
| 
      
 925 
     | 
    
         
            +
                # @param name [String] The new name of the emoji.
         
     | 
| 
      
 926 
     | 
    
         
            +
                # @return [Emoji] Returns the updated emoji object on success.
         
     | 
| 
      
 927 
     | 
    
         
            +
                def edit_application_emoji(emoji_id, name:)
         
     | 
| 
      
 928 
     | 
    
         
            +
                  response = API::Application.edit_application_emoji(@token, profile.id, emoji_id.resolve_id, name)
         
     | 
| 
      
 929 
     | 
    
         
            +
                  Emoji.new(JSON.parse(response), self)
         
     | 
| 
      
 930 
     | 
    
         
            +
                end
         
     | 
| 
      
 931 
     | 
    
         
            +
             
     | 
| 
      
 932 
     | 
    
         
            +
                # Deletes an existing application emoji.
         
     | 
| 
      
 933 
     | 
    
         
            +
                # @param emoji_id [Integer, String, Emoji] ID of the application emoji to delete.
         
     | 
| 
      
 934 
     | 
    
         
            +
                def delete_application_emoji(emoji_id)
         
     | 
| 
      
 935 
     | 
    
         
            +
                  API::Application.delete_application_emoji(@token, profile.id, emoji_id.resolve_id)
         
     | 
| 
      
 936 
     | 
    
         
            +
                end
         
     | 
| 
      
 937 
     | 
    
         
            +
             
     | 
| 
       898 
938 
     | 
    
         
             
                private
         
     | 
| 
       899 
939 
     | 
    
         | 
| 
       900 
940 
     | 
    
         
             
                # Throws a useful exception if there's currently no gateway connection.
         
     | 
| 
         @@ -1091,12 +1131,12 @@ module Discordrb 
     | 
|
| 
       1091 
1131 
     | 
    
         
             
                  server_id = data['guild_id'].to_i
         
     | 
| 
       1092 
1132 
     | 
    
         
             
                  server = self.server(server_id)
         
     | 
| 
       1093 
1133 
     | 
    
         | 
| 
       1094 
     | 
    
         
            -
                   
     | 
| 
       1095 
     | 
    
         
            -
                  member. 
     | 
| 
       1096 
     | 
    
         
            -
             
     | 
| 
       1097 
     | 
    
         
            -
                   
     | 
| 
       1098 
     | 
    
         
            -
             
     | 
| 
       1099 
     | 
    
         
            -
                   
     | 
| 
      
 1134 
     | 
    
         
            +
                  # Only attempt to update members that're already cached
         
     | 
| 
      
 1135 
     | 
    
         
            +
                  if (member = server.member(data['user']['id'].to_i, false))
         
     | 
| 
      
 1136 
     | 
    
         
            +
                    member.update_data(data)
         
     | 
| 
      
 1137 
     | 
    
         
            +
                  else
         
     | 
| 
      
 1138 
     | 
    
         
            +
                    ensure_user(data['user'])
         
     | 
| 
      
 1139 
     | 
    
         
            +
                  end
         
     | 
| 
       1100 
1140 
     | 
    
         
             
                end
         
     | 
| 
       1101 
1141 
     | 
    
         | 
| 
       1102 
1142 
     | 
    
         
             
                # Internal handler for GUILD_MEMBER_DELETE
         
     | 
| 
         @@ -1212,7 +1252,7 @@ module Discordrb 
     | 
|
| 
       1212 
1252 
     | 
    
         | 
| 
       1213 
1253 
     | 
    
         
             
                def handle_dispatch(type, data)
         
     | 
| 
       1214 
1254 
     | 
    
         
             
                  # Check whether there are still unavailable servers and there have been more than 10 seconds since READY
         
     | 
| 
       1215 
     | 
    
         
            -
                  if @unavailable_servers&.positive? && (Time.now - @unavailable_timeout_time) > 10 && !( 
     | 
| 
      
 1255 
     | 
    
         
            +
                  if @unavailable_servers&.positive? && (Time.now - @unavailable_timeout_time) > 10 && !(@intents || 0).nobits?(INTENTS[:servers])
         
     | 
| 
       1216 
1256 
     | 
    
         
             
                    # The server streaming timed out!
         
     | 
| 
       1217 
1257 
     | 
    
         
             
                    LOGGER.debug("Server streaming timed out with #{@unavailable_servers} servers remaining")
         
     | 
| 
       1218 
1258 
     | 
    
         
             
                    LOGGER.debug('Calling ready now because server loading is taking a long time. Servers may be unavailable due to an outage, or your bot is on very large servers.')
         
     | 
| 
         @@ -1232,6 +1272,8 @@ module Discordrb 
     | 
|
| 
       1232 
1272 
     | 
    
         | 
| 
       1233 
1273 
     | 
    
         
             
                    @profile = Profile.new(data['user'], self)
         
     | 
| 
       1234 
1274 
     | 
    
         | 
| 
      
 1275 
     | 
    
         
            +
                    @client_id ||= data['application']['id']&.to_i
         
     | 
| 
      
 1276 
     | 
    
         
            +
             
     | 
| 
       1235 
1277 
     | 
    
         
             
                    # Initialize servers
         
     | 
| 
       1236 
1278 
     | 
    
         
             
                    @servers = {}
         
     | 
| 
       1237 
1279 
     | 
    
         | 
| 
         @@ -1274,6 +1316,8 @@ module Discordrb 
     | 
|
| 
       1274 
1316 
     | 
    
         
             
                    id = data['guild_id'].to_i
         
     | 
| 
       1275 
1317 
     | 
    
         
             
                    server = server(id)
         
     | 
| 
       1276 
1318 
     | 
    
         
             
                    server.process_chunk(data['members'], data['chunk_index'], data['chunk_count'])
         
     | 
| 
      
 1319 
     | 
    
         
            +
                  when :USER_UPDATE
         
     | 
| 
      
 1320 
     | 
    
         
            +
                    @profile = Profile.new(data, self)
         
     | 
| 
       1277 
1321 
     | 
    
         
             
                  when :INVITE_CREATE
         
     | 
| 
       1278 
1322 
     | 
    
         
             
                    invite = Invite.new(data, self)
         
     | 
| 
       1279 
1323 
     | 
    
         
             
                    raise_event(InviteCreateEvent.new(data, invite, self))
         
     | 
| 
         @@ -1290,12 +1334,22 @@ module Discordrb 
     | 
|
| 
       1290 
1334 
     | 
    
         
             
                      return
         
     | 
| 
       1291 
1335 
     | 
    
         
             
                    end
         
     | 
| 
       1292 
1336 
     | 
    
         | 
| 
      
 1337 
     | 
    
         
            +
                    if !should_parse_self && profile.id == data['author']['id'].to_i
         
     | 
| 
      
 1338 
     | 
    
         
            +
                      debug('Ignored message from the current bot')
         
     | 
| 
      
 1339 
     | 
    
         
            +
                      return
         
     | 
| 
      
 1340 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1341 
     | 
    
         
            +
             
     | 
| 
       1293 
1342 
     | 
    
         
             
                    # If create_message is overwritten with a method that returns the parsed message, use that instead, so we don't
         
     | 
| 
       1294 
1343 
     | 
    
         
             
                    # parse the message twice (which is just thrown away performance)
         
     | 
| 
       1295 
1344 
     | 
    
         
             
                    message = create_message(data)
         
     | 
| 
       1296 
1345 
     | 
    
         
             
                    message = Message.new(data, self) unless message.is_a? Message
         
     | 
| 
       1297 
1346 
     | 
    
         | 
| 
       1298 
     | 
    
         
            -
                     
     | 
| 
      
 1347 
     | 
    
         
            +
                    # Update the existing member if it exists in the cache.
         
     | 
| 
      
 1348 
     | 
    
         
            +
                    if data['member']
         
     | 
| 
      
 1349 
     | 
    
         
            +
                      member = message.channel.server&.member(data['author']['id'].to_i, false)
         
     | 
| 
      
 1350 
     | 
    
         
            +
                      data['member']['user'] = data['author']
         
     | 
| 
      
 1351 
     | 
    
         
            +
                      member&.update_data(data['member'])
         
     | 
| 
      
 1352 
     | 
    
         
            +
                    end
         
     | 
| 
       1299 
1353 
     | 
    
         | 
| 
       1300 
1354 
     | 
    
         
             
                    # Dispatch a ChannelCreateEvent for channels we don't have cached
         
     | 
| 
       1301 
1355 
     | 
    
         
             
                    if message.channel.private? && @pm_channels[message.channel.recipient.id].nil?
         
     | 
| 
         @@ -1319,18 +1373,28 @@ module Discordrb 
     | 
|
| 
       1319 
1373 
     | 
    
         
             
                  when :MESSAGE_UPDATE
         
     | 
| 
       1320 
1374 
     | 
    
         
             
                    update_message(data)
         
     | 
| 
       1321 
1375 
     | 
    
         | 
| 
      
 1376 
     | 
    
         
            +
                    if !should_parse_self && profile.id == data['author']['id'].to_i
         
     | 
| 
      
 1377 
     | 
    
         
            +
                      debug('Ignored message from the current bot')
         
     | 
| 
      
 1378 
     | 
    
         
            +
                      return
         
     | 
| 
      
 1379 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1380 
     | 
    
         
            +
             
     | 
| 
       1322 
1381 
     | 
    
         
             
                    message = Message.new(data, self)
         
     | 
| 
       1323 
1382 
     | 
    
         | 
| 
       1324 
1383 
     | 
    
         
             
                    event = MessageUpdateEvent.new(message, self)
         
     | 
| 
       1325 
1384 
     | 
    
         
             
                    raise_event(event)
         
     | 
| 
       1326 
1385 
     | 
    
         | 
| 
       1327 
     | 
    
         
            -
                     
     | 
| 
       1328 
     | 
    
         
            -
             
     | 
| 
       1329 
     | 
    
         
            -
                    unless message.author
         
     | 
| 
      
 1386 
     | 
    
         
            +
                    if data['author'].nil?
         
     | 
| 
       1330 
1387 
     | 
    
         
             
                      LOGGER.debug("Edited a message with nil author! Content: #{message.content.inspect}, channel: #{message.channel.inspect}")
         
     | 
| 
       1331 
1388 
     | 
    
         
             
                      return
         
     | 
| 
       1332 
1389 
     | 
    
         
             
                    end
         
     | 
| 
       1333 
1390 
     | 
    
         | 
| 
      
 1391 
     | 
    
         
            +
                    # Update the existing member if it exists in the cache.
         
     | 
| 
      
 1392 
     | 
    
         
            +
                    if data['member']
         
     | 
| 
      
 1393 
     | 
    
         
            +
                      member = message.channel.server&.member(data['author']['id'].to_i, false)
         
     | 
| 
      
 1394 
     | 
    
         
            +
                      data['member']['user'] = data['author']
         
     | 
| 
      
 1395 
     | 
    
         
            +
                      member&.update_data(data['member'])
         
     | 
| 
      
 1396 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1397 
     | 
    
         
            +
             
     | 
| 
       1334 
1398 
     | 
    
         
             
                    event = MessageEditEvent.new(message, self)
         
     | 
| 
       1335 
1399 
     | 
    
         
             
                    raise_event(event)
         
     | 
| 
       1336 
1400 
     | 
    
         
             
                  when :MESSAGE_DELETE
         
     | 
| 
         @@ -1368,6 +1432,12 @@ module Discordrb 
     | 
|
| 
       1368 
1432 
     | 
    
         | 
| 
       1369 
1433 
     | 
    
         
             
                    return if profile.id == data['user_id'].to_i && !should_parse_self
         
     | 
| 
       1370 
1434 
     | 
    
         | 
| 
      
 1435 
     | 
    
         
            +
                    if data['member']
         
     | 
| 
      
 1436 
     | 
    
         
            +
                      server = self.server(data['guild_id'].to_i)
         
     | 
| 
      
 1437 
     | 
    
         
            +
             
     | 
| 
      
 1438 
     | 
    
         
            +
                      server&.cache_member(Member.new(data['member'], server, self))
         
     | 
| 
      
 1439 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1440 
     | 
    
         
            +
             
     | 
| 
       1371 
1441 
     | 
    
         
             
                    event = ReactionAddEvent.new(data, self)
         
     | 
| 
       1372 
1442 
     | 
    
         
             
                    raise_event(event)
         
     | 
| 
       1373 
1443 
     | 
    
         
             
                  when :MESSAGE_REACTION_REMOVE
         
     | 
| 
         @@ -1442,6 +1512,12 @@ module Discordrb 
     | 
|
| 
       1442 
1512 
     | 
    
         
             
                    remove_recipient(data)
         
     | 
| 
       1443 
1513 
     | 
    
         | 
| 
       1444 
1514 
     | 
    
         
             
                    event = ChannelRecipientRemoveEvent.new(data, self)
         
     | 
| 
      
 1515 
     | 
    
         
            +
                    raise_event(event)
         
     | 
| 
      
 1516 
     | 
    
         
            +
                  when :CHANNEL_PINS_UPDATE
         
     | 
| 
      
 1517 
     | 
    
         
            +
                    event = ChannelPinsUpdateEvent.new(data, self)
         
     | 
| 
      
 1518 
     | 
    
         
            +
             
     | 
| 
      
 1519 
     | 
    
         
            +
                    event.channel.process_last_pin_timestamp(data['last_pin_timestamp']) if data.key?('last_pin_timestamp')
         
     | 
| 
      
 1520 
     | 
    
         
            +
             
     | 
| 
       1445 
1521 
     | 
    
         
             
                    raise_event(event)
         
     | 
| 
       1446 
1522 
     | 
    
         
             
                  when :GUILD_MEMBER_ADD
         
     | 
| 
       1447 
1523 
     | 
    
         
             
                    add_guild_member(data)
         
     | 
| 
         @@ -1544,6 +1620,10 @@ module Discordrb 
     | 
|
| 
       1544 
1620 
     | 
    
         
             
                      event = ServerEmojiUpdateEvent.new(server, old_emoji_data[e], new_emoji_data[e], self)
         
     | 
| 
       1545 
1621 
     | 
    
         
             
                      raise_event(event)
         
     | 
| 
       1546 
1622 
     | 
    
         
             
                    end
         
     | 
| 
      
 1623 
     | 
    
         
            +
                  when :APPLICATION_COMMAND_PERMISSIONS_UPDATE
         
     | 
| 
      
 1624 
     | 
    
         
            +
                    event = ApplicationCommandPermissionsUpdateEvent.new(data, self)
         
     | 
| 
      
 1625 
     | 
    
         
            +
             
     | 
| 
      
 1626 
     | 
    
         
            +
                    raise_event(event)
         
     | 
| 
       1547 
1627 
     | 
    
         
             
                  when :INTERACTION_CREATE
         
     | 
| 
       1548 
1628 
     | 
    
         
             
                    event = InteractionCreateEvent.new(data, self)
         
     | 
| 
       1549 
1629 
     | 
    
         
             
                    raise_event(event)
         
     | 
| 
         @@ -1552,13 +1632,13 @@ module Discordrb 
     | 
|
| 
       1552 
1632 
     | 
    
         
             
                    when Interaction::TYPES[:command]
         
     | 
| 
       1553 
1633 
     | 
    
         
             
                      event = ApplicationCommandEvent.new(data, self)
         
     | 
| 
       1554 
1634 
     | 
    
         | 
| 
       1555 
     | 
    
         
            -
                      Thread.new do
         
     | 
| 
       1556 
     | 
    
         
            -
                        Thread.current[:discordrb_name] = "it-#{ 
     | 
| 
      
 1635 
     | 
    
         
            +
                      Thread.new(event) do |evt|
         
     | 
| 
      
 1636 
     | 
    
         
            +
                        Thread.current[:discordrb_name] = "it-#{evt.interaction.id}"
         
     | 
| 
       1557 
1637 
     | 
    
         | 
| 
       1558 
1638 
     | 
    
         
             
                        begin
         
     | 
| 
       1559 
     | 
    
         
            -
                          debug("Executing application command #{ 
     | 
| 
      
 1639 
     | 
    
         
            +
                          debug("Executing application command #{evt.command_name}:#{evt.command_id}")
         
     | 
| 
       1560 
1640 
     | 
    
         | 
| 
       1561 
     | 
    
         
            -
                          @application_commands[ 
     | 
| 
      
 1641 
     | 
    
         
            +
                          @application_commands[evt.command_name]&.call(evt)
         
     | 
| 
       1562 
1642 
     | 
    
         
             
                        rescue StandardError => e
         
     | 
| 
       1563 
1643 
     | 
    
         
             
                          log_exception(e)
         
     | 
| 
       1564 
1644 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -1594,6 +1674,10 @@ module Discordrb 
     | 
|
| 
       1594 
1674 
     | 
    
         | 
| 
       1595 
1675 
     | 
    
         
             
                      event = ModalSubmitEvent.new(data, self)
         
     | 
| 
       1596 
1676 
     | 
    
         
             
                      raise_event(event)
         
     | 
| 
      
 1677 
     | 
    
         
            +
                    when Interaction::TYPES[:autocomplete]
         
     | 
| 
      
 1678 
     | 
    
         
            +
             
     | 
| 
      
 1679 
     | 
    
         
            +
                      event = AutocompleteEvent.new(data, self)
         
     | 
| 
      
 1680 
     | 
    
         
            +
                      raise_event(event)
         
     | 
| 
       1597 
1681 
     | 
    
         
             
                    end
         
     | 
| 
       1598 
1682 
     | 
    
         
             
                  when :WEBHOOKS_UPDATE
         
     | 
| 
       1599 
1683 
     | 
    
         
             
                    event = WebhookUpdateEvent.new(data, self)
         
     | 
| 
         @@ -1673,15 +1757,15 @@ module Discordrb 
     | 
|
| 
       1673 
1757 
     | 
    
         
             
                end
         
     | 
| 
       1674 
1758 
     | 
    
         | 
| 
       1675 
1759 
     | 
    
         
             
                def call_event(handler, event)
         
     | 
| 
       1676 
     | 
    
         
            -
                  t = Thread.new do
         
     | 
| 
      
 1760 
     | 
    
         
            +
                  t = Thread.new(event) do |evt|
         
     | 
| 
       1677 
1761 
     | 
    
         
             
                    @event_threads ||= []
         
     | 
| 
       1678 
1762 
     | 
    
         
             
                    @current_thread ||= 0
         
     | 
| 
       1679 
1763 
     | 
    
         | 
| 
       1680 
1764 
     | 
    
         
             
                    @event_threads << t
         
     | 
| 
       1681 
1765 
     | 
    
         
             
                    Thread.current[:discordrb_name] = "et-#{@current_thread += 1}"
         
     | 
| 
       1682 
1766 
     | 
    
         
             
                    begin
         
     | 
| 
       1683 
     | 
    
         
            -
                      handler.call( 
     | 
| 
       1684 
     | 
    
         
            -
                      handler.after_call( 
     | 
| 
      
 1767 
     | 
    
         
            +
                      handler.call(evt)
         
     | 
| 
      
 1768 
     | 
    
         
            +
                      handler.after_call(evt)
         
     | 
| 
       1685 
1769 
     | 
    
         
             
                    rescue StandardError => e
         
     | 
| 
       1686 
1770 
     | 
    
         
             
                      log_exception(e)
         
     | 
| 
       1687 
1771 
     | 
    
         
             
                    ensure
         
     | 
| 
         @@ -1692,7 +1776,7 @@ module Discordrb 
     | 
|
| 
       1692 
1776 
     | 
    
         | 
| 
       1693 
1777 
     | 
    
         
             
                def handle_awaits(event)
         
     | 
| 
       1694 
1778 
     | 
    
         
             
                  @awaits ||= {}
         
     | 
| 
       1695 
     | 
    
         
            -
                  @awaits. 
     | 
| 
      
 1779 
     | 
    
         
            +
                  @awaits.each_value do |await|
         
     | 
| 
       1696 
1780 
     | 
    
         
             
                    key, should_delete = await.match(event)
         
     | 
| 
       1697 
1781 
     | 
    
         
             
                    next unless key
         
     | 
| 
       1698 
1782 
     | 
    
         | 
| 
         @@ -1705,6 +1789,8 @@ module Discordrb 
     | 
|
| 
       1705 
1789 
     | 
    
         
             
                end
         
     | 
| 
       1706 
1790 
     | 
    
         | 
| 
       1707 
1791 
     | 
    
         
             
                def calculate_intents(intents)
         
     | 
| 
      
 1792 
     | 
    
         
            +
                  intents = [intents] unless intents.is_a? Array
         
     | 
| 
      
 1793 
     | 
    
         
            +
             
     | 
| 
       1708 
1794 
     | 
    
         
             
                  intents.reduce(0) do |sum, intent|
         
     | 
| 
       1709 
1795 
     | 
    
         
             
                    case intent
         
     | 
| 
       1710 
1796 
     | 
    
         
             
                    when Symbol
         
     | 
    
        data/lib/discordrb/cache.rb
    CHANGED
    
    | 
         @@ -22,6 +22,7 @@ module Discordrb 
     | 
|
| 
       22 
22 
     | 
    
         
             
                  @channels = {}
         
     | 
| 
       23 
23 
     | 
    
         
             
                  @pm_channels = {}
         
     | 
| 
       24 
24 
     | 
    
         
             
                  @thread_members = {}
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @server_previews = {}
         
     | 
| 
       25 
26 
     | 
    
         
             
                end
         
     | 
| 
       26 
27 
     | 
    
         | 
| 
       27 
28 
     | 
    
         
             
                # Returns or caches the available voice regions
         
     | 
| 
         @@ -134,6 +135,19 @@ module Discordrb 
     | 
|
| 
       134 
135 
     | 
    
         | 
| 
       135 
136 
     | 
    
         
             
                alias_method :private_channel, :pm_channel
         
     | 
| 
       136 
137 
     | 
    
         | 
| 
      
 138 
     | 
    
         
            +
                # Get a server preview. If the bot isn't a member of the server, the server must be discoverable.
         
     | 
| 
      
 139 
     | 
    
         
            +
                # @param id [Integer, String, Server] the ID of the server preview to get.
         
     | 
| 
      
 140 
     | 
    
         
            +
                # @return [ServerPreview, nil] the server preview, or `nil` if the server isn't accessible.
         
     | 
| 
      
 141 
     | 
    
         
            +
                def server_preview(id)
         
     | 
| 
      
 142 
     | 
    
         
            +
                  id = id.resolve_id
         
     | 
| 
      
 143 
     | 
    
         
            +
                  return @server_previews[id] if @server_previews[id]
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                  response = JSON.parse(API::Server.preview(token, id))
         
     | 
| 
      
 146 
     | 
    
         
            +
                  @server_previews[id] = ServerPreview.new(response, self)
         
     | 
| 
      
 147 
     | 
    
         
            +
                rescue StandardError
         
     | 
| 
      
 148 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 149 
     | 
    
         
            +
                end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
       137 
151 
     | 
    
         
             
                # Ensures a given user object is cached and if not, cache it from the given data hash.
         
     | 
| 
       138 
152 
     | 
    
         
             
                # @param data [Hash] A data hash representing a user.
         
     | 
| 
       139 
153 
     | 
    
         
             
                # @return [User] the user represented by the data hash.
         
     | 
| 
         @@ -199,7 +213,7 @@ module Discordrb 
     | 
|
| 
       199 
213 
     | 
    
         
             
                # @return [String] Only the code for the invite.
         
     | 
| 
       200 
214 
     | 
    
         
             
                def resolve_invite_code(invite)
         
     | 
| 
       201 
215 
     | 
    
         
             
                  invite = invite.code if invite.is_a? Discordrb::Invite
         
     | 
| 
       202 
     | 
    
         
            -
                  invite = invite[invite.rindex('/') + 1..] if invite.start_with?('http', 'discord.gg')
         
     | 
| 
      
 216 
     | 
    
         
            +
                  invite = invite[(invite.rindex('/') + 1)..] if invite.start_with?('http', 'discord.gg')
         
     | 
| 
       203 
217 
     | 
    
         
             
                  invite
         
     | 
| 
       204 
218 
     | 
    
         
             
                end
         
     | 
| 
       205 
219 
     | 
    
         | 
| 
         @@ -109,7 +109,7 @@ module Discordrb::Commands 
     | 
|
| 
       109 
109 
     | 
    
         
             
                    spaces_allowed: attributes[:spaces_allowed].nil? ? false : attributes[:spaces_allowed],
         
     | 
| 
       110 
110 
     | 
    
         | 
| 
       111 
111 
     | 
    
         
             
                    # Webhooks allowed to trigger commands
         
     | 
| 
       112 
     | 
    
         
            -
                    webhook_commands: attributes[:webhook_commands].nil?  
     | 
| 
      
 112 
     | 
    
         
            +
                    webhook_commands: attributes[:webhook_commands].nil? || attributes[:webhook_commands],
         
     | 
| 
       113 
113 
     | 
    
         | 
| 
       114 
114 
     | 
    
         
             
                    channels: attributes[:channels] || [],
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
         @@ -153,7 +153,9 @@ module Discordrb::Commands 
     | 
|
| 
       153 
153 
     | 
    
         
             
                        command = command.aliased_command
         
     | 
| 
       154 
154 
     | 
    
         
             
                        command_name = command.name
         
     | 
| 
       155 
155 
     | 
    
         
             
                      end
         
     | 
| 
      
 156 
     | 
    
         
            +
                      # rubocop:disable Lint/ReturnInVoidContext
         
     | 
| 
       156 
157 
     | 
    
         
             
                      return "The command `#{command_name}` does not exist!" unless command
         
     | 
| 
      
 158 
     | 
    
         
            +
                      # rubocop:enable Lint/ReturnInVoidContext
         
     | 
| 
       157 
159 
     | 
    
         | 
| 
       158 
160 
     | 
    
         
             
                      desc = command.attributes[:description] || '*No description available*'
         
     | 
| 
       159 
161 
     | 
    
         
             
                      usage = command.attributes[:usage]
         
     | 
| 
         @@ -257,24 +259,16 @@ module Discordrb::Commands 
     | 
|
| 
       257 
259 
     | 
    
         
             
                    next arg if types[i].nil? || types[i] == String
         
     | 
| 
       258 
260 
     | 
    
         | 
| 
       259 
261 
     | 
    
         
             
                    if types[i] == Integer
         
     | 
| 
       260 
     | 
    
         
            -
                       
     | 
| 
       261 
     | 
    
         
            -
                        Integer(arg, 10)
         
     | 
| 
       262 
     | 
    
         
            -
                      rescue ArgumentError
         
     | 
| 
       263 
     | 
    
         
            -
                        nil
         
     | 
| 
       264 
     | 
    
         
            -
                      end
         
     | 
| 
      
 262 
     | 
    
         
            +
                      Integer(arg, 10, exception: false)
         
     | 
| 
       265 
263 
     | 
    
         
             
                    elsif types[i] == Float
         
     | 
| 
       266 
     | 
    
         
            -
                       
     | 
| 
       267 
     | 
    
         
            -
                        Float(arg)
         
     | 
| 
       268 
     | 
    
         
            -
                      rescue ArgumentError
         
     | 
| 
       269 
     | 
    
         
            -
                        nil
         
     | 
| 
       270 
     | 
    
         
            -
                      end
         
     | 
| 
      
 264 
     | 
    
         
            +
                      Float(arg, exception: false)
         
     | 
| 
       271 
265 
     | 
    
         
             
                    elsif types[i] == Time
         
     | 
| 
       272 
266 
     | 
    
         
             
                      begin
         
     | 
| 
       273 
267 
     | 
    
         
             
                        Time.parse arg
         
     | 
| 
       274 
268 
     | 
    
         
             
                      rescue ArgumentError
         
     | 
| 
       275 
269 
     | 
    
         
             
                        nil
         
     | 
| 
       276 
270 
     | 
    
         
             
                      end
         
     | 
| 
       277 
     | 
    
         
            -
                    elsif  
     | 
| 
      
 271 
     | 
    
         
            +
                    elsif [TrueClass, FalseClass].include?(types[i])
         
     | 
| 
       278 
272 
     | 
    
         
             
                      if arg.casecmp('true').zero? || arg.downcase.start_with?('y')
         
     | 
| 
       279 
273 
     | 
    
         
             
                        true
         
     | 
| 
       280 
274 
     | 
    
         
             
                      elsif arg.casecmp('false').zero? || arg.downcase.start_with?('n')
         
     | 
| 
         @@ -295,11 +289,7 @@ module Discordrb::Commands 
     | 
|
| 
       295 
289 
     | 
    
         
             
                        nil
         
     | 
| 
       296 
290 
     | 
    
         
             
                      end
         
     | 
| 
       297 
291 
     | 
    
         
             
                    elsif types[i] == Rational
         
     | 
| 
       298 
     | 
    
         
            -
                       
     | 
| 
       299 
     | 
    
         
            -
                        Rational(arg)
         
     | 
| 
       300 
     | 
    
         
            -
                      rescue ArgumentError
         
     | 
| 
       301 
     | 
    
         
            -
                        nil
         
     | 
| 
       302 
     | 
    
         
            -
                      end
         
     | 
| 
      
 292 
     | 
    
         
            +
                      Rational(arg, exception: false)
         
     | 
| 
       303 
293 
     | 
    
         
             
                    elsif types[i] == Range
         
     | 
| 
       304 
294 
     | 
    
         
             
                      begin
         
     | 
| 
       305 
295 
     | 
    
         
             
                        if arg.include? '...'
         
     | 
| 
         @@ -32,10 +32,10 @@ module Discordrb::Commands 
     | 
|
| 
       32 
32 
     | 
    
         
             
                    channels: attributes[:channels] || nil,
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
                    # Whether this command is usable in a command chain
         
     | 
| 
       35 
     | 
    
         
            -
                    chain_usable: attributes[:chain_usable].nil?  
     | 
| 
      
 35 
     | 
    
         
            +
                    chain_usable: attributes[:chain_usable].nil? || attributes[:chain_usable],
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
                    # Whether this command should show up in the help command
         
     | 
| 
       38 
     | 
    
         
            -
                    help_available: attributes[:help_available].nil?  
     | 
| 
      
 38 
     | 
    
         
            +
                    help_available: attributes[:help_available].nil? || attributes[:help_available],
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
       40 
40 
     | 
    
         
             
                    # Description (for help command)
         
     | 
| 
       41 
41 
     | 
    
         
             
                    description: attributes[:description] || nil,
         
     | 
| 
         @@ -159,7 +159,7 @@ module Discordrb::Commands 
     | 
|
| 
       159 
159 
     | 
    
         
             
                  escaped = false
         
     | 
| 
       160 
160 
     | 
    
         
             
                  hacky_delim, hacky_space, hacky_prev, hacky_newline = [0xe001, 0xe002, 0xe003, 0xe004].pack('U*').chars
         
     | 
| 
       161 
161 
     | 
    
         | 
| 
       162 
     | 
    
         
            -
                  @chain.each_char. 
     | 
| 
      
 162 
     | 
    
         
            +
                  @chain.each_char.with_index do |char, index|
         
     | 
| 
       163 
163 
     | 
    
         
             
                    # Escape character
         
     | 
| 
       164 
164 
     | 
    
         
             
                    if char == '\\' && !escaped
         
     | 
| 
       165 
165 
     | 
    
         
             
                      escaped = true
         
     | 
| 
         @@ -211,7 +211,7 @@ module Discordrb::Commands 
     | 
|
| 
       211 
211 
     | 
    
         
             
                    b_level -= 1
         
     | 
| 
       212 
212 
     | 
    
         
             
                    next unless b_level.zero?
         
     | 
| 
       213 
213 
     | 
    
         | 
| 
       214 
     | 
    
         
            -
                    nested = @chain[b_start + 1..index - 1]
         
     | 
| 
      
 214 
     | 
    
         
            +
                    nested = @chain[(b_start + 1)..(index - 1)]
         
     | 
| 
       215 
215 
     | 
    
         
             
                    subchain = CommandChain.new(nested, @bot, true)
         
     | 
| 
       216 
216 
     | 
    
         
             
                    result += subchain.execute(event)
         
     | 
| 
       217 
217 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -245,8 +245,8 @@ module Discordrb::Commands 
     | 
|
| 
       245 
245 
     | 
    
         
             
                    command = command.gsub hacky_delim, @attributes[:chain_delimiter]
         
     | 
| 
       246 
246 
     | 
    
         | 
| 
       247 
247 
     | 
    
         
             
                    first_space = command.index ' '
         
     | 
| 
       248 
     | 
    
         
            -
                    command_name = first_space ? command[0..first_space - 1] : command
         
     | 
| 
       249 
     | 
    
         
            -
                    arguments = first_space ? command[first_space + 1..] : ''
         
     | 
| 
      
 248 
     | 
    
         
            +
                    command_name = first_space ? command[0..(first_space - 1)] : command
         
     | 
| 
      
 249 
     | 
    
         
            +
                    arguments = first_space ? command[(first_space + 1)..] : ''
         
     | 
| 
       250 
250 
     | 
    
         | 
| 
       251 
251 
     | 
    
         
             
                    # Append a previous sign if none is present
         
     | 
| 
       252 
252 
     | 
    
         
             
                    arguments += @attributes[:previous] unless arguments.include? @attributes[:previous]
         
     | 
| 
         @@ -318,7 +318,7 @@ module Discordrb::Commands 
     | 
|
| 
       318 
318 
     | 
    
         
             
                      arg.split ' '
         
     | 
| 
       319 
319 
     | 
    
         
             
                    end
         
     | 
| 
       320 
320 
     | 
    
         | 
| 
       321 
     | 
    
         
            -
                    chain = chain[chain_args_index + 1..]
         
     | 
| 
      
 321 
     | 
    
         
            +
                    chain = chain[(chain_args_index + 1)..]
         
     | 
| 
       322 
322 
     | 
    
         
             
                  end
         
     | 
| 
       323 
323 
     | 
    
         | 
| 
       324 
324 
     | 
    
         
             
                  [chain_args, chain]
         
     |