discordrb 3.4.3 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +44 -18
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
- data/.github/workflows/codeql.yml +65 -0
- data/.markdownlint.json +4 -0
- data/.rubocop.yml +8 -2
- data/CHANGELOG.md +390 -225
- data/LICENSE.txt +1 -1
- data/README.md +37 -25
- data/discordrb-webhooks.gemspec +4 -1
- data/discordrb.gemspec +9 -6
- data/lib/discordrb/api/application.rb +202 -0
- data/lib/discordrb/api/channel.rb +177 -11
- data/lib/discordrb/api/interaction.rb +54 -0
- data/lib/discordrb/api/invite.rb +2 -2
- data/lib/discordrb/api/server.rb +40 -19
- data/lib/discordrb/api/user.rb +8 -3
- data/lib/discordrb/api/webhook.rb +57 -0
- data/lib/discordrb/api.rb +19 -5
- data/lib/discordrb/bot.rb +317 -32
- data/lib/discordrb/cache.rb +27 -22
- data/lib/discordrb/commands/command_bot.rb +6 -4
- data/lib/discordrb/commands/container.rb +1 -1
- data/lib/discordrb/commands/parser.rb +2 -2
- data/lib/discordrb/commands/rate_limiter.rb +1 -1
- data/lib/discordrb/container.rb +132 -3
- data/lib/discordrb/data/attachment.rb +15 -0
- data/lib/discordrb/data/audit_logs.rb +3 -3
- data/lib/discordrb/data/channel.rb +167 -23
- data/lib/discordrb/data/component.rb +229 -0
- data/lib/discordrb/data/integration.rb +42 -3
- data/lib/discordrb/data/interaction.rb +800 -0
- data/lib/discordrb/data/invite.rb +1 -1
- data/lib/discordrb/data/member.rb +108 -33
- data/lib/discordrb/data/message.rb +99 -19
- data/lib/discordrb/data/overwrite.rb +13 -7
- data/lib/discordrb/data/role.rb +58 -1
- data/lib/discordrb/data/server.rb +82 -80
- data/lib/discordrb/data/user.rb +69 -9
- data/lib/discordrb/data/webhook.rb +97 -4
- data/lib/discordrb/data.rb +3 -0
- data/lib/discordrb/errors.rb +44 -3
- data/lib/discordrb/events/channels.rb +1 -1
- data/lib/discordrb/events/interactions.rb +482 -0
- data/lib/discordrb/events/message.rb +9 -6
- data/lib/discordrb/events/presence.rb +21 -14
- data/lib/discordrb/events/reactions.rb +0 -1
- data/lib/discordrb/events/threads.rb +96 -0
- data/lib/discordrb/gateway.rb +30 -17
- data/lib/discordrb/permissions.rb +59 -34
- data/lib/discordrb/version.rb +1 -1
- data/lib/discordrb/voice/encoder.rb +2 -2
- data/lib/discordrb/voice/network.rb +18 -7
- data/lib/discordrb/voice/sodium.rb +3 -1
- data/lib/discordrb/voice/voice_bot.rb +3 -3
- data/lib/discordrb/webhooks.rb +2 -0
- data/lib/discordrb.rb +37 -4
- metadata +48 -14
- data/.codeclimate.yml +0 -16
- data/.travis.yml +0 -32
- data/bin/travis_build_docs.sh +0 -17
| @@ -70,7 +70,9 @@ module Discordrb::Commands | |
| 70 70 | 
             
                # @option attributes [String] :quote_end Character that should end a quoted string (see
         | 
| 71 71 | 
             
                #   :advanced_functionality). Default is '"' or the same as :quote_start. Set to an empty string to disable.
         | 
| 72 72 | 
             
                # @option attributes [true, false] :ignore_bots Whether the bot should ignore bot accounts or not. Default is false.
         | 
| 73 | 
            -
                def initialize(attributes | 
| 73 | 
            +
                def initialize(**attributes)
         | 
| 74 | 
            +
                  # TODO: This needs to be revisited. undefined attributes are treated
         | 
| 75 | 
            +
                  # as explicitly passed nils.
         | 
| 74 76 | 
             
                  super(
         | 
| 75 77 | 
             
                    log_mode: attributes[:log_mode],
         | 
| 76 78 | 
             
                    token: attributes[:token],
         | 
| @@ -85,7 +87,7 @@ module Discordrb::Commands | |
| 85 87 | 
             
                    redact_token: attributes.key?(:redact_token) ? attributes[:redact_token] : true,
         | 
| 86 88 | 
             
                    ignore_bots: attributes[:ignore_bots],
         | 
| 87 89 | 
             
                    compress_mode: attributes[:compress_mode],
         | 
| 88 | 
            -
                    intents: attributes[:intents]
         | 
| 90 | 
            +
                    intents: attributes[:intents] || :all
         | 
| 89 91 | 
             
                  )
         | 
| 90 92 |  | 
| 91 93 | 
             
                  @prefix = attributes[:prefix]
         | 
| @@ -335,7 +337,7 @@ module Discordrb::Commands | |
| 335 337 | 
             
                  return nil if chain.empty?
         | 
| 336 338 |  | 
| 337 339 | 
             
                  args = chain.split(' ')
         | 
| 338 | 
            -
                  execute_command(args[0].to_sym, event, args[1 | 
| 340 | 
            +
                  execute_command(args[0].to_sym, event, args[1..])
         | 
| 339 341 | 
             
                end
         | 
| 340 342 |  | 
| 341 343 | 
             
                # Sets the permission level of a user
         | 
| @@ -443,7 +445,7 @@ module Discordrb::Commands | |
| 443 445 | 
             
                def standard_prefix_trigger(message, prefix)
         | 
| 444 446 | 
             
                  return nil unless message.start_with? prefix
         | 
| 445 447 |  | 
| 446 | 
            -
                  message[prefix.length | 
| 448 | 
            +
                  message[prefix.length..]
         | 
| 447 449 | 
             
                end
         | 
| 448 450 |  | 
| 449 451 | 
             
                def required_permissions?(member, required, channel = nil)
         | 
| @@ -86,7 +86,7 @@ module Discordrb::Commands | |
| 86 86 | 
             
                # Adds all commands from another container into this one. Existing commands will be overwritten.
         | 
| 87 87 | 
             
                # @param container [Module] A module that `extend`s {CommandContainer} from which the commands will be added.
         | 
| 88 88 | 
             
                def include_commands(container)
         | 
| 89 | 
            -
                  handlers = container.instance_variable_get  | 
| 89 | 
            +
                  handlers = container.instance_variable_get :@commands
         | 
| 90 90 | 
             
                  return unless handlers
         | 
| 91 91 |  | 
| 92 92 | 
             
                  @commands ||= {}
         | 
| @@ -246,7 +246,7 @@ module Discordrb::Commands | |
| 246 246 |  | 
| 247 247 | 
             
                    first_space = command.index ' '
         | 
| 248 248 | 
             
                    command_name = first_space ? command[0..first_space - 1] : command
         | 
| 249 | 
            -
                    arguments = first_space ? command[first_space + 1 | 
| 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]
         | 
| @@ -125,7 +125,7 @@ module Discordrb::Commands | |
| 125 125 | 
             
                # Adds all the buckets from another RateLimiter onto this one.
         | 
| 126 126 | 
             
                # @param limiter [Module] Another {RateLimiter} module
         | 
| 127 127 | 
             
                def include_buckets(limiter)
         | 
| 128 | 
            -
                  buckets = limiter.instance_variable_get( | 
| 128 | 
            +
                  buckets = limiter.instance_variable_get(:@buckets) || {}
         | 
| 129 129 | 
             
                  @buckets ||= {}
         | 
| 130 130 | 
             
                  @buckets.merge! buckets
         | 
| 131 131 | 
             
                end
         | 
    
        data/lib/discordrb/container.rb
    CHANGED
    
    | @@ -13,6 +13,7 @@ require 'discordrb/events/guilds' | |
| 13 13 | 
             
            require 'discordrb/events/await'
         | 
| 14 14 | 
             
            require 'discordrb/events/bans'
         | 
| 15 15 | 
             
            require 'discordrb/events/reactions'
         | 
| 16 | 
            +
            require 'discordrb/events/interactions'
         | 
| 16 17 |  | 
| 17 18 | 
             
            require 'discordrb/await'
         | 
| 18 19 |  | 
| @@ -522,6 +523,118 @@ module Discordrb | |
| 522 523 | 
             
                  register_event(InviteDeleteEvent, attributes, block)
         | 
| 523 524 | 
             
                end
         | 
| 524 525 |  | 
| 526 | 
            +
                # This **event** is raised whenever an interaction event is received.
         | 
| 527 | 
            +
                # @param attributes [Hash] The event's attributes.
         | 
| 528 | 
            +
                # @option attributes [Integer, Symbol, String] :type The interaction type, can be the integer value or the name
         | 
| 529 | 
            +
                #   of the key in {Discordrb::Interaction::TYPES}.
         | 
| 530 | 
            +
                # @option attributes [String, Integer, Server, nil] :server The server where this event was created. `nil` for DM channels.
         | 
| 531 | 
            +
                # @option attributes [String, Integer, Channel] :channel The channel where this event was created.
         | 
| 532 | 
            +
                # @option attributes [String, Integer, User] :user The user that triggered this event.
         | 
| 533 | 
            +
                # @yield The block is executed when the event is raised.
         | 
| 534 | 
            +
                # @yieldparam event [InteractionCreateEvent] The event that was raised.
         | 
| 535 | 
            +
                # @return [InteractionCreateEventHandler] The event handler that was registered.
         | 
| 536 | 
            +
                def interaction_create(attributes = {}, &block)
         | 
| 537 | 
            +
                  register_event(InteractionCreateEvent, attributes, block)
         | 
| 538 | 
            +
                end
         | 
| 539 | 
            +
             | 
| 540 | 
            +
                # This **event** is raised whenever an application command (slash command) is executed.
         | 
| 541 | 
            +
                # @param name [Symbol] The name of the application command this handler is for.
         | 
| 542 | 
            +
                # @param attributes [Hash] The event's attributes.
         | 
| 543 | 
            +
                # @yield The block is executed when the event is raised.
         | 
| 544 | 
            +
                # @yieldparam event [ApplicationCommandEvent] The event that was raised.
         | 
| 545 | 
            +
                # @return [ApplicationCommandEventHandler] The event handler that was registered.
         | 
| 546 | 
            +
                def application_command(name, attributes = {}, &block)
         | 
| 547 | 
            +
                  @application_commands ||= {}
         | 
| 548 | 
            +
             | 
| 549 | 
            +
                  unless block
         | 
| 550 | 
            +
                    @application_commands[name] ||= ApplicationCommandEventHandler.new(attributes, nil)
         | 
| 551 | 
            +
                    return @application_commands[name]
         | 
| 552 | 
            +
                  end
         | 
| 553 | 
            +
             | 
| 554 | 
            +
                  @application_commands[name] = ApplicationCommandEventHandler.new(attributes, block)
         | 
| 555 | 
            +
                end
         | 
| 556 | 
            +
             | 
| 557 | 
            +
                # This **event** is raised whenever an button interaction is created.
         | 
| 558 | 
            +
                # @param attributes [Hash] The event's attributes.
         | 
| 559 | 
            +
                # @option attributes [String, Regexp] :custom_id A custom_id to match against.
         | 
| 560 | 
            +
                # @option attributes [String, Integer, Message] :message The message to filter for.
         | 
| 561 | 
            +
                # @yield The block is executed when the event is raised.
         | 
| 562 | 
            +
                # @yieldparam event [ButtonEvent] The event that was raised.
         | 
| 563 | 
            +
                # @return [ButtonEventHandler] The event handler that was registered.
         | 
| 564 | 
            +
                def button(attributes = {}, &block)
         | 
| 565 | 
            +
                  register_event(ButtonEvent, attributes, block)
         | 
| 566 | 
            +
                end
         | 
| 567 | 
            +
             | 
| 568 | 
            +
                # This **event** is raised whenever an select string interaction is created.
         | 
| 569 | 
            +
                # @param attributes [Hash] The event's attributes.
         | 
| 570 | 
            +
                # @option attributes [String, Regexp] :custom_id A custom_id to match against.
         | 
| 571 | 
            +
                # @option attributes [String, Integer, Message] :message The message to filter for.
         | 
| 572 | 
            +
                # @yield The block is executed when the event is raised.
         | 
| 573 | 
            +
                # @yieldparam event [StringSelectEvent] The event that was raised.
         | 
| 574 | 
            +
                # @return [StringSelectEventHandler] The event handler that was registered.
         | 
| 575 | 
            +
                def string_select(attributes = {}, &block)
         | 
| 576 | 
            +
                  register_event(StringSelectEvent, attributes, block)
         | 
| 577 | 
            +
                end
         | 
| 578 | 
            +
             | 
| 579 | 
            +
                alias_method :select_menu, :string_select
         | 
| 580 | 
            +
             | 
| 581 | 
            +
                # This **event** is raised whenever a modal is submitted.
         | 
| 582 | 
            +
                # @param attributes [Hash] The event's attributes.
         | 
| 583 | 
            +
                # @option attributes [String, Regexp] :custom_id A custom_id to match against.
         | 
| 584 | 
            +
                # @option attributes [String, Integer, Message] :message The message to filter for.
         | 
| 585 | 
            +
                # @option attributes [String, Integer, Server, nil] :server The server where this event was created. `nil` for DM channels.
         | 
| 586 | 
            +
                # @option attributes [String, Integer, Channel] :channel The channel where this event was created.
         | 
| 587 | 
            +
                # @option attributes [String, Integer, User] :user The user that triggered this event.    # @yield The block is executed when the event is raised.
         | 
| 588 | 
            +
                # @yieldparam event [ModalSubmitEvent] The event that was raised.
         | 
| 589 | 
            +
                # @return [ModalSubmitEventHandler] The event handler that was registered.
         | 
| 590 | 
            +
                def modal_submit(attributes = {}, &block)
         | 
| 591 | 
            +
                  register_event(ModalSubmitEvent, attributes, block)
         | 
| 592 | 
            +
                end
         | 
| 593 | 
            +
             | 
| 594 | 
            +
                # This **event** is raised whenever an select user interaction is created.
         | 
| 595 | 
            +
                # @param attributes [Hash] The event's attributes.
         | 
| 596 | 
            +
                # @option attributes [String, Regexp] :custom_id A custom_id to match against.
         | 
| 597 | 
            +
                # @option attributes [String, Integer, Message] :message The message to filter for.
         | 
| 598 | 
            +
                # @yield The block is executed when the event is raised.
         | 
| 599 | 
            +
                # @yieldparam event [UserSelectEvent] The event that was raised.
         | 
| 600 | 
            +
                # @return [UserSelectEventHandler] The event handler that was registered.
         | 
| 601 | 
            +
                def user_select(attributes = {}, &block)
         | 
| 602 | 
            +
                  register_event(UserSelectEvent, attributes, block)
         | 
| 603 | 
            +
                end
         | 
| 604 | 
            +
             | 
| 605 | 
            +
                # This **event** is raised whenever an select role interaction is created.
         | 
| 606 | 
            +
                # @param attributes [Hash] The event's attributes.
         | 
| 607 | 
            +
                # @option attributes [String, Regexp] :custom_id A custom_id to match against.
         | 
| 608 | 
            +
                # @option attributes [String, Integer, Message] :message The message to filter for.
         | 
| 609 | 
            +
                # @yield The block is executed when the event is raised.
         | 
| 610 | 
            +
                # @yieldparam event [RoleSelectEvent] The event that was raised.
         | 
| 611 | 
            +
                # @return [RoleSelectEventHandler] The event handler that was registered.
         | 
| 612 | 
            +
                def role_select(attributes = {}, &block)
         | 
| 613 | 
            +
                  register_event(RoleSelectEvent, attributes, block)
         | 
| 614 | 
            +
                end
         | 
| 615 | 
            +
             | 
| 616 | 
            +
                # This **event** is raised whenever an select mentionable interaction is created.
         | 
| 617 | 
            +
                # @param attributes [Hash] The event's attributes.
         | 
| 618 | 
            +
                # @option attributes [String, Regexp] :custom_id A custom_id to match against.
         | 
| 619 | 
            +
                # @option attributes [String, Integer, Message] :message The message to filter for.
         | 
| 620 | 
            +
                # @yield The block is executed when the event is raised.
         | 
| 621 | 
            +
                # @yieldparam event [MentionableSelectEvent] The event that was raised.
         | 
| 622 | 
            +
                # @return [MentionableSelectEventHandler] The event handler that was registered.
         | 
| 623 | 
            +
                def mentionable_select(attributes = {}, &block)
         | 
| 624 | 
            +
                  register_event(MentionableSelectEvent, attributes, block)
         | 
| 625 | 
            +
                end
         | 
| 626 | 
            +
             | 
| 627 | 
            +
                # This **event** is raised whenever an select channel interaction is created.
         | 
| 628 | 
            +
                # @param attributes [Hash] The event's attributes.
         | 
| 629 | 
            +
                # @option attributes [String, Regexp] :custom_id A custom_id to match against.
         | 
| 630 | 
            +
                # @option attributes [String, Integer, Message] :message The message to filter for.
         | 
| 631 | 
            +
                # @yield The block is executed when the event is raised.
         | 
| 632 | 
            +
                # @yieldparam event [ChannelSelectEvent] The event that was raised.
         | 
| 633 | 
            +
                # @return [ChannelSelectEventHandler] The event handler that was registered.
         | 
| 634 | 
            +
                def channel_select(attributes = {}, &block)
         | 
| 635 | 
            +
                  register_event(ChannelSelectEvent, attributes, block)
         | 
| 636 | 
            +
                end
         | 
| 637 | 
            +
             | 
| 525 638 | 
             
                # This **event** is raised for every dispatch received over the gateway, whether supported by discordrb or not.
         | 
| 526 639 | 
             
                # @param attributes [Hash] The event's attributes.
         | 
| 527 640 | 
             
                # @option attributes [String, Symbol, Regexp] :type Matches the event type of the dispatch.
         | 
| @@ -552,9 +665,16 @@ module Discordrb | |
| 552 665 | 
             
                  @event_handlers[clazz].delete(handler)
         | 
| 553 666 | 
             
                end
         | 
| 554 667 |  | 
| 668 | 
            +
                # Remove an application command handler
         | 
| 669 | 
            +
                # @param name [String, Symbol] The name of the command handler to remove.
         | 
| 670 | 
            +
                def remove_application_command_handler(name)
         | 
| 671 | 
            +
                  @application_commands.delete(name)
         | 
| 672 | 
            +
                end
         | 
| 673 | 
            +
             | 
| 555 674 | 
             
                # Removes all events from this event handler.
         | 
| 556 675 | 
             
                def clear!
         | 
| 557 676 | 
             
                  @event_handlers&.clear
         | 
| 677 | 
            +
                  @application_commands&.clear
         | 
| 558 678 | 
             
                end
         | 
| 559 679 |  | 
| 560 680 | 
             
                # Adds an event handler to this container. Usually, it's more expressive to just use one of the shorthand adder
         | 
| @@ -570,11 +690,19 @@ module Discordrb | |
| 570 690 | 
             
                # Adds all event handlers from another container into this one. Existing event handlers will be overwritten.
         | 
| 571 691 | 
             
                # @param container [Module] A module that `extend`s {EventContainer} from which the handlers will be added.
         | 
| 572 692 | 
             
                def include_events(container)
         | 
| 573 | 
            -
                   | 
| 574 | 
            -
                   | 
| 693 | 
            +
                  application_command_handlers = container.instance_variable_get(:@application_commands)
         | 
| 694 | 
            +
                  handlers = container.instance_variable_get :@event_handlers
         | 
| 695 | 
            +
                  return unless handlers || application_command_handlers
         | 
| 575 696 |  | 
| 576 697 | 
             
                  @event_handlers ||= {}
         | 
| 577 | 
            -
                  @event_handlers.merge!(handlers) { |_, old, new| old + new }
         | 
| 698 | 
            +
                  @event_handlers.merge!(handlers || {}) { |_, old, new| old + new }
         | 
| 699 | 
            +
             | 
| 700 | 
            +
                  @application_commands ||= {}
         | 
| 701 | 
            +
             | 
| 702 | 
            +
                  @application_commands.merge!(application_command_handlers || {}) do |_, old, new|
         | 
| 703 | 
            +
                    old.subcommands.merge!(new.subcommands)
         | 
| 704 | 
            +
                    old
         | 
| 705 | 
            +
                  end
         | 
| 578 706 | 
             
                end
         | 
| 579 707 |  | 
| 580 708 | 
             
                alias_method :include!, :include_events
         | 
| @@ -612,6 +740,7 @@ module Discordrb | |
| 612 740 |  | 
| 613 741 | 
             
                include Discordrb::Events
         | 
| 614 742 |  | 
| 743 | 
            +
                # @return [EventHandler]
         | 
| 615 744 | 
             
                def register_event(clazz, attributes, block)
         | 
| 616 745 | 
             
                  handler = EventContainer.handler_class(clazz).new(attributes, block)
         | 
| 617 746 |  | 
| @@ -27,6 +27,16 @@ module Discordrb | |
| 27 27 | 
             
                # @return [Integer, nil] the height of an image file, in pixels, or `nil` if the file is not an image.
         | 
| 28 28 | 
             
                attr_reader :height
         | 
| 29 29 |  | 
| 30 | 
            +
                # @return [String, nil] the attachment's description.
         | 
| 31 | 
            +
                attr_reader :description
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                # @return [String, nil] the attachment's media type.
         | 
| 34 | 
            +
                attr_reader :content_type
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                # @return [true, false] whether this attachment is ephemeral.
         | 
| 37 | 
            +
                attr_reader :ephemeral
         | 
| 38 | 
            +
                alias_method :ephemeral?, :ephemeral
         | 
| 39 | 
            +
             | 
| 30 40 | 
             
                # @!visibility private
         | 
| 31 41 | 
             
                def initialize(data, message, bot)
         | 
| 32 42 | 
             
                  @bot = bot
         | 
| @@ -41,6 +51,11 @@ module Discordrb | |
| 41 51 |  | 
| 42 52 | 
             
                  @width = data['width']
         | 
| 43 53 | 
             
                  @height = data['height']
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  @description = data['description']
         | 
| 56 | 
            +
                  @content_type = data['content_type']
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  @ephemeral = data['ephemeral']
         | 
| 44 59 | 
             
                end
         | 
| 45 60 |  | 
| 46 61 | 
             
                # @return [true, false] whether this file is an image file.
         | 
| @@ -177,7 +177,7 @@ module Discordrb | |
| 177 177 |  | 
| 178 178 | 
             
                  # The inspect method is overwritten to give more useful output
         | 
| 179 179 | 
             
                  def inspect
         | 
| 180 | 
            -
                    "<AuditLogs::Entry id=#{@id} action=#{@action} reason=#{@reason} action_type=#{@action_type} target_type=#{@target_type} count=#{@count} days=#{@days} members_removed=#{@members_removed}>"
         | 
| 180 | 
            +
                    "<AuditLogs::Entry id=#{@id} key=#{@key} action=#{@action} reason=#{@reason} action_type=#{@action_type} target_type=#{@target_type} count=#{@count} days=#{@days} members_removed=#{@members_removed}>"
         | 
| 181 181 | 
             
                  end
         | 
| 182 182 |  | 
| 183 183 | 
             
                  # Process action changes
         | 
| @@ -219,8 +219,8 @@ module Discordrb | |
| 219 219 | 
             
                    @old = Permissions.new(@old) if @old && @key == 'permissions'
         | 
| 220 220 | 
             
                    @new = Permissions.new(@new) if @new && @key == 'permissions'
         | 
| 221 221 |  | 
| 222 | 
            -
                    @old = @old.map { |o| Overwrite.new(o['id'], type: o['type'] | 
| 223 | 
            -
                    @new = @new.map { |o| Overwrite.new(o['id'], type: o['type'] | 
| 222 | 
            +
                    @old = @old.map { |o| Overwrite.new(o['id'], type: o['type'], allow: o['allow'], deny: o['deny']) } if @old && @key == 'permission_overwrites'
         | 
| 223 | 
            +
                    @new = @new.map { |o| Overwrite.new(o['id'], type: o['type'], allow: o['allow'], deny: o['deny']) } if @new && @key == 'permission_overwrites'
         | 
| 224 224 | 
             
                  end
         | 
| 225 225 |  | 
| 226 226 | 
             
                  # @return [Channel, nil] the channel that was previously used in the server widget. Only present if the key for this change is `widget_channel_id`.
         | 
| @@ -1,5 +1,8 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'discordrb/webhooks/view'
         | 
| 4 | 
            +
            require 'time'
         | 
| 5 | 
            +
             | 
| 3 6 | 
             
            module Discordrb
         | 
| 4 7 | 
             
              # A Discord channel, including data like the topic
         | 
| 5 8 | 
             
              class Channel
         | 
| @@ -13,23 +16,28 @@ module Discordrb | |
| 13 16 | 
             
                  group: 3,
         | 
| 14 17 | 
             
                  category: 4,
         | 
| 15 18 | 
             
                  news: 5,
         | 
| 16 | 
            -
                  store: 6
         | 
| 19 | 
            +
                  store: 6,
         | 
| 20 | 
            +
                  news_thread: 10,
         | 
| 21 | 
            +
                  public_thread: 11,
         | 
| 22 | 
            +
                  private_thread: 12,
         | 
| 23 | 
            +
                  stage_voice: 13,
         | 
| 24 | 
            +
                  directory: 14,
         | 
| 25 | 
            +
                  forum: 15
         | 
| 17 26 | 
             
                }.freeze
         | 
| 18 27 |  | 
| 19 28 | 
             
                # @return [String] this channel's name.
         | 
| 20 29 | 
             
                attr_reader :name
         | 
| 21 30 |  | 
| 22 | 
            -
                # @return [ | 
| 23 | 
            -
                 | 
| 24 | 
            -
             | 
| 25 | 
            -
                # @return [Integer, nil] the ID of the parent channel, if this channel is inside a category
         | 
| 31 | 
            +
                # @return [Integer, nil] the ID of the parent channel, if this channel is inside a category. If this channel is a
         | 
| 32 | 
            +
                #   thread, this is the text channel it is a child to.
         | 
| 26 33 | 
             
                attr_reader :parent_id
         | 
| 27 34 |  | 
| 28 35 | 
             
                # @return [Integer] the type of this channel
         | 
| 29 36 | 
             
                # @see TYPES
         | 
| 30 37 | 
             
                attr_reader :type
         | 
| 31 38 |  | 
| 32 | 
            -
                # @return [Integer, nil] the ID of the owner of the group channel or nil if this is not a group channel.
         | 
| 39 | 
            +
                # @return [Integer, nil] the ID of the owner of the group channel or nil if this is not a group channel. If this
         | 
| 40 | 
            +
                #   channel is a thread, this is the member that started the thread.
         | 
| 33 41 | 
             
                attr_reader :owner_id
         | 
| 34 42 |  | 
| 35 43 | 
             
                # @return [Array<Recipient>, nil] the array of recipients of the private messages, or nil if this is not a Private channel
         | 
| @@ -56,6 +64,35 @@ module Discordrb | |
| 56 64 | 
             
                attr_reader :rate_limit_per_user
         | 
| 57 65 | 
             
                alias_method :slowmode_rate, :rate_limit_per_user
         | 
| 58 66 |  | 
| 67 | 
            +
                # @return [Integer, nil] An approximate count of messages sent in a thread. Stops counting at 50.
         | 
| 68 | 
            +
                attr_reader :message_count
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                # @return [Integer, nil] An approximate count of members in a thread. Stops counting at 50.
         | 
| 71 | 
            +
                attr_reader :member_count
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                # @return [true, false, nil] Whether or not this thread is archived.
         | 
| 74 | 
            +
                attr_reader :archived
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                # @return [Integer, nil] How long after the last message before a thread is automatically archived.
         | 
| 77 | 
            +
                attr_reader :auto_archive_duration
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                # @return [Time, nil] The timestamp of when this threads status last changed.
         | 
| 80 | 
            +
                attr_reader :archive_timestamp
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                # @return [true, false, nil] Whether this thread is locked or not.
         | 
| 83 | 
            +
                attr_reader :locked
         | 
| 84 | 
            +
                alias_method :locked?, :locked
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                # @return [Time, nil] When the current user joined this thread.
         | 
| 87 | 
            +
                attr_reader :join_timestamp
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                # @return [Integer, nil] Member flags for this thread, used for notifications.
         | 
| 90 | 
            +
                attr_reader :member_flags
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                # @return [true, false] For private threads, determines whether non-moderators can add other non-moderators to
         | 
| 93 | 
            +
                #   a thread.
         | 
| 94 | 
            +
                attr_reader :invitable
         | 
| 95 | 
            +
             | 
| 59 96 | 
             
                # @return [true, false] whether or not this channel is a PM or group channel.
         | 
| 60 97 | 
             
                def private?
         | 
| 61 98 | 
             
                  pm? || group?
         | 
| @@ -99,15 +136,44 @@ module Discordrb | |
| 99 136 | 
             
                    end
         | 
| 100 137 | 
             
                  else
         | 
| 101 138 | 
             
                    @name = data['name']
         | 
| 102 | 
            -
                    @ | 
| 139 | 
            +
                    @server_id = server&.id || data['guild_id'].to_i
         | 
| 140 | 
            +
                    @server = server
         | 
| 103 141 | 
             
                  end
         | 
| 104 142 |  | 
| 105 143 | 
             
                  @nsfw = data['nsfw'] || false
         | 
| 106 144 | 
             
                  @rate_limit_per_user = data['rate_limit_per_user'] || 0
         | 
| 145 | 
            +
                  @message_count = data['message_count']
         | 
| 146 | 
            +
                  @member_count = data['member_count']
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  if (metadata = data['thread_metadata'])
         | 
| 149 | 
            +
                    @archived = metadata['archived']
         | 
| 150 | 
            +
                    @auto_archive_duration = metadata['auto_archive_duration']
         | 
| 151 | 
            +
                    @archive_timestamp = Time.iso8601(metadata['archive_timestamp'])
         | 
| 152 | 
            +
                    @locked = metadata['locked']
         | 
| 153 | 
            +
                    @invitable = metadata['invitable']
         | 
| 154 | 
            +
                  end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                  if (member = data['member'])
         | 
| 157 | 
            +
                    @member_join = Time.iso8601(member['join_timestamp'])
         | 
| 158 | 
            +
                    @member_flags = member['flags']
         | 
| 159 | 
            +
                  end
         | 
| 107 160 |  | 
| 108 161 | 
             
                  process_permission_overwrites(data['permission_overwrites'])
         | 
| 109 162 | 
             
                end
         | 
| 110 163 |  | 
| 164 | 
            +
                # @return [Server, nil] the server this channel is on. If this channel is a PM channel, it will be nil.
         | 
| 165 | 
            +
                # @raise [Discordrb::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
         | 
| 166 | 
            +
                #   authorized with the `bot` scope.
         | 
| 167 | 
            +
                def server
         | 
| 168 | 
            +
                  return @server if @server
         | 
| 169 | 
            +
                  return nil if private?
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                  @server = @bot.server(@server_id)
         | 
| 172 | 
            +
                  raise Discordrb::Errors::NoPermission, 'The bot does not have access to this server' unless @server
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                  @server
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
             | 
| 111 177 | 
             
                # @return [true, false] whether or not this channel is a text channel
         | 
| 112 178 | 
             
                def text?
         | 
| 113 179 | 
             
                  @type.zero?
         | 
| @@ -143,6 +209,26 @@ module Discordrb | |
| 143 209 | 
             
                  @type == 6
         | 
| 144 210 | 
             
                end
         | 
| 145 211 |  | 
| 212 | 
            +
                # @return [true, false] whether or not this channel is a news thread.
         | 
| 213 | 
            +
                def news_thread?
         | 
| 214 | 
            +
                  @type == 10
         | 
| 215 | 
            +
                end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                # @return [true, false] whether or not this channel is a public thread.
         | 
| 218 | 
            +
                def public_thread?
         | 
| 219 | 
            +
                  @type == 11
         | 
| 220 | 
            +
                end
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                # @return [true, false] whether or not this channel is a private thread.
         | 
| 223 | 
            +
                def private_thread?
         | 
| 224 | 
            +
                  @type == 12
         | 
| 225 | 
            +
                end
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                # @return [true, false] whether or not this channel is a thread.
         | 
| 228 | 
            +
                def thread?
         | 
| 229 | 
            +
                  news_thread? || public_thread? || private_thread?
         | 
| 230 | 
            +
                end
         | 
| 231 | 
            +
             | 
| 146 232 | 
             
                # @return [Channel, nil] the category channel, if this channel is in a category
         | 
| 147 233 | 
             
                def category
         | 
| 148 234 | 
             
                  @bot.channel(@parent_id) if @parent_id
         | 
| @@ -199,7 +285,7 @@ module Discordrb | |
| 199 285 | 
             
                  ids = if parent
         | 
| 200 286 | 
             
                          parent.children
         | 
| 201 287 | 
             
                        else
         | 
| 202 | 
            -
                           | 
| 288 | 
            +
                          server.channels.reject(&:parent_id).select { |c| c.type == @type }
         | 
| 203 289 | 
             
                        end.sort_by(&:position).map(&:id)
         | 
| 204 290 |  | 
| 205 291 | 
             
                  # Move our channel ID after the target ID by deleting it,
         | 
| @@ -225,7 +311,7 @@ module Discordrb | |
| 225 311 | 
             
                    move_argument << hash
         | 
| 226 312 | 
             
                  end
         | 
| 227 313 |  | 
| 228 | 
            -
                  API::Server.update_channel_positions(@bot.token, @ | 
| 314 | 
            +
                  API::Server.update_channel_positions(@bot.token, @server_id, move_argument)
         | 
| 229 315 | 
             
                end
         | 
| 230 316 |  | 
| 231 317 | 
             
                # Sets whether this channel is NSFW
         | 
| @@ -262,9 +348,9 @@ module Discordrb | |
| 262 348 |  | 
| 263 349 | 
             
                # Sets the amount of time (in seconds) users have to wait in between sending messages.
         | 
| 264 350 | 
             
                # @param rate [Integer]
         | 
| 265 | 
            -
                # @raise [ArgumentError] if value isn't between 0 and  | 
| 351 | 
            +
                # @raise [ArgumentError] if value isn't between 0 and 21600
         | 
| 266 352 | 
             
                def rate_limit_per_user=(rate)
         | 
| 267 | 
            -
                  raise ArgumentError, 'rate_limit_per_user must be between 0 and  | 
| 353 | 
            +
                  raise ArgumentError, 'rate_limit_per_user must be between 0 and 21600' unless rate.between?(0, 21_600)
         | 
| 268 354 |  | 
| 269 355 | 
             
                  update_channel_data(rate_limit_per_user: rate)
         | 
| 270 356 | 
             
                end
         | 
| @@ -341,9 +427,10 @@ module Discordrb | |
| 341 427 | 
             
                # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
         | 
| 342 428 | 
             
                # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
         | 
| 343 429 | 
             
                # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
         | 
| 430 | 
            +
                # @param components [View, Array<Hash>] Interaction components to associate with this message.
         | 
| 344 431 | 
             
                # @return [Message] the message that was sent.
         | 
| 345 | 
            -
                def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil)
         | 
| 346 | 
            -
                  @bot.send_message(@id, content, tts, embed, attachments, allowed_mentions, message_reference)
         | 
| 432 | 
            +
                def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
         | 
| 433 | 
            +
                  @bot.send_message(@id, content, tts, embed, attachments, allowed_mentions, message_reference, components)
         | 
| 347 434 | 
             
                end
         | 
| 348 435 |  | 
| 349 436 | 
             
                alias_method :send, :send_message
         | 
| @@ -356,8 +443,9 @@ module Discordrb | |
| 356 443 | 
             
                # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
         | 
| 357 444 | 
             
                # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
         | 
| 358 445 | 
             
                # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
         | 
| 359 | 
            -
                 | 
| 360 | 
            -
             | 
| 446 | 
            +
                # @param components [View, Array<Hash>] Interaction components to associate with this message.
         | 
| 447 | 
            +
                def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
         | 
| 448 | 
            +
                  @bot.send_temporary_message(@id, content, timeout, tts, embed, attachments, allowed_mentions, message_reference, components)
         | 
| 361 449 | 
             
                end
         | 
| 362 450 |  | 
| 363 451 | 
             
                # Convenience method to send a message with an embed.
         | 
| @@ -372,13 +460,17 @@ module Discordrb | |
| 372 460 | 
             
                # @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
         | 
| 373 461 | 
             
                # @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
         | 
| 374 462 | 
             
                # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
         | 
| 463 | 
            +
                # @param components [View, Array<Hash>] Interaction components to associate with this message.
         | 
| 375 464 | 
             
                # @yield [embed] Yields the embed to allow for easy building inside a block.
         | 
| 376 465 | 
             
                # @yieldparam embed [Discordrb::Webhooks::Embed] The embed from the parameters, or a new one.
         | 
| 377 466 | 
             
                # @return [Message] The resulting message.
         | 
| 378 | 
            -
                def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil)
         | 
| 467 | 
            +
                def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, components = nil)
         | 
| 379 468 | 
             
                  embed ||= Discordrb::Webhooks::Embed.new
         | 
| 380 | 
            -
                   | 
| 381 | 
            -
             | 
| 469 | 
            +
                  view = Discordrb::Webhooks::View.new
         | 
| 470 | 
            +
             | 
| 471 | 
            +
                  yield(embed, view) if block_given?
         | 
| 472 | 
            +
             | 
| 473 | 
            +
                  send_message(message, tts, embed, attachments, allowed_mentions, message_reference, components || view.to_a)
         | 
| 382 474 | 
             
                end
         | 
| 383 475 |  | 
| 384 476 | 
             
                # Sends multiple messages to a channel
         | 
| @@ -518,9 +610,9 @@ module Discordrb | |
| 518 610 | 
             
                # @return [Array<Member>] the users in this channel
         | 
| 519 611 | 
             
                def users
         | 
| 520 612 | 
             
                  if text?
         | 
| 521 | 
            -
                     | 
| 613 | 
            +
                    server.online_members(include_idle: true).select { |u| u.can_read_messages? self }
         | 
| 522 614 | 
             
                  elsif voice?
         | 
| 523 | 
            -
                     | 
| 615 | 
            +
                    server.voice_states.filter_map { |id, voice_state| server.member(id) if !voice_state.voice_channel.nil? && voice_state.voice_channel.id == @id }
         | 
| 524 616 | 
             
                  end
         | 
| 525 617 | 
             
                end
         | 
| 526 618 |  | 
| @@ -554,9 +646,11 @@ module Discordrb | |
| 554 646 | 
             
                # @param message_id [Integer] The ID of the message to retrieve.
         | 
| 555 647 | 
             
                # @return [Message, nil] the retrieved message, or `nil` if it couldn't be found.
         | 
| 556 648 | 
             
                def load_message(message_id)
         | 
| 649 | 
            +
                  raise ArgumentError, 'message_id cannot be nil' if message_id.nil?
         | 
| 650 | 
            +
             | 
| 557 651 | 
             
                  response = API::Channel.message(@bot.token, @id, message_id)
         | 
| 558 652 | 
             
                  Message.new(JSON.parse(response), @bot)
         | 
| 559 | 
            -
                rescue  | 
| 653 | 
            +
                rescue Discordrb::Errors::UnknownMessage
         | 
| 560 654 | 
             
                  nil
         | 
| 561 655 | 
             
                end
         | 
| 562 656 |  | 
| @@ -742,9 +836,59 @@ module Discordrb | |
| 742 836 | 
             
                  invites.map { |invite_data| Invite.new(invite_data, @bot) }
         | 
| 743 837 | 
             
                end
         | 
| 744 838 |  | 
| 839 | 
            +
                # Start a thread.
         | 
| 840 | 
            +
                # @param name [String] The name of the thread.
         | 
| 841 | 
            +
                # @param auto_archive_duration [60, 1440, 4320, 10080] How long before a thread is automatically
         | 
| 842 | 
            +
                #   archived.
         | 
| 843 | 
            +
                # @param message [Message, Integer, String] The message to reference when starting this thread.
         | 
| 844 | 
            +
                # @param type [Symbol, Integer] The type of thread to create. Can be a key from {TYPES} or the value.
         | 
| 845 | 
            +
                # @return [Channel]
         | 
| 846 | 
            +
                def start_thread(name, auto_archive_duration, message: nil, type: 11)
         | 
| 847 | 
            +
                  message_id = message&.id || message
         | 
| 848 | 
            +
                  type = TYPES[type] || type
         | 
| 849 | 
            +
             | 
| 850 | 
            +
                  data = if message
         | 
| 851 | 
            +
                           API::Channel.start_thread_with_message(@bot.token, @id, message_id, name, auto_archive_duration)
         | 
| 852 | 
            +
                         else
         | 
| 853 | 
            +
                           API::Channel.start_thread_without_message(@bot.token, @id, name, auto_archive_duration, type)
         | 
| 854 | 
            +
                         end
         | 
| 855 | 
            +
             | 
| 856 | 
            +
                  Channel.new(JSON.parse(data), @bot, @server)
         | 
| 857 | 
            +
                end
         | 
| 858 | 
            +
             | 
| 859 | 
            +
                # @!group Threads
         | 
| 860 | 
            +
             | 
| 861 | 
            +
                # Join this thread.
         | 
| 862 | 
            +
                def join_thread
         | 
| 863 | 
            +
                  @bot.join_thread(@id)
         | 
| 864 | 
            +
                end
         | 
| 865 | 
            +
             | 
| 866 | 
            +
                # Leave this thread
         | 
| 867 | 
            +
                def leave_thread
         | 
| 868 | 
            +
                  @bot.leave_thread(@id)
         | 
| 869 | 
            +
                end
         | 
| 870 | 
            +
             | 
| 871 | 
            +
                # Members in the thread.
         | 
| 872 | 
            +
                def members
         | 
| 873 | 
            +
                  @bot.thread_members[@id].collect { |id| @server_id ? @bot.member(@server_id, id) : @bot.user(id) }
         | 
| 874 | 
            +
                end
         | 
| 875 | 
            +
             | 
| 876 | 
            +
                # Add a member to the thread
         | 
| 877 | 
            +
                # @param member [Member, Integer, String] The member, or ID of the member, to add to this thread.
         | 
| 878 | 
            +
                def add_member(member)
         | 
| 879 | 
            +
                  @bot.add_thread_member(@id, member)
         | 
| 880 | 
            +
                end
         | 
| 881 | 
            +
             | 
| 882 | 
            +
                # @param member [Member, Integer, String] The member, or ID of the member, to remove from a thread.
         | 
| 883 | 
            +
                def remove_member(member)
         | 
| 884 | 
            +
                  @bot.remove_thread_member(@id, member)
         | 
| 885 | 
            +
                end
         | 
| 886 | 
            +
             | 
| 887 | 
            +
                # @!endgroup
         | 
| 888 | 
            +
             | 
| 745 889 | 
             
                # The default `inspect` method is overwritten to give more useful output.
         | 
| 746 890 | 
             
                def inspect
         | 
| 747 | 
            -
                  "<Channel name=#{@name} id=#{@id} topic=\"#{@topic}\" type=#{@type} position=#{@position} server=#{@server}>"
         | 
| 891 | 
            +
                  "<Channel name=#{@name} id=#{@id} topic=\"#{@topic}\" type=#{@type} position=#{@position} server=#{@server || @server_id}>"
         | 
| 748 892 | 
             
                end
         | 
| 749 893 |  | 
| 750 894 | 
             
                # Adds a recipient to a group channel.
         | 
| @@ -790,7 +934,7 @@ module Discordrb | |
| 790 934 |  | 
| 791 935 | 
             
                # @return [String] a URL that a user can use to navigate to this channel in the client
         | 
| 792 936 | 
             
                def link
         | 
| 793 | 
            -
                  "https://discord.com/channels/#{@ | 
| 937 | 
            +
                  "https://discord.com/channels/#{@server_id || '@me'}/#{@channel.id}"
         | 
| 794 938 | 
             
                end
         | 
| 795 939 |  | 
| 796 940 | 
             
                alias_method :jump_link, :link
         |