discorb-lib/discorb

View on GitHub
lib/discorb/gateway_events.rb

Summary

Maintainability
C
1 day
Test Coverage
# frozen_string_literal: true

module Discorb
  module Gateway
    #
    # Represents an event.
    # @abstract
    #
    class GatewayEvent
      #
      # Initializes a new instance of the GatewayEvent class.
      # @private
      #
      # @param [Hash] data The data of the event.
      #
      def initialize(data)
        @data = data
      end

      def inspect
        "#<#{self.class}>"
      end
    end

    #
    # Represents a reaction event.
    #
    class ReactionEvent < GatewayEvent
      # @return [Hash] The raw data of the event.
      attr_reader :data
      # @return [Discorb::Snowflake] The ID of the user who reacted.
      attr_reader :user_id
      alias member_id user_id
      # @return [Discorb::Snowflake] The ID of the channel the message was sent in.
      attr_reader :channel_id
      # @return [Discorb::Snowflake] The ID of the message.
      attr_reader :message_id
      # @return [Discorb::Snowflake] The ID of the guild the message was sent in.
      attr_reader :guild_id
      # @macro client_cache
      # @return [Discorb::User, Discorb::Member] The user who reacted.
      attr_reader :user
      alias member user
      # @macro client_cache
      # @return [Discorb::Channel] The channel the message was sent in.
      attr_reader :channel
      # @macro client_cache
      # @return [Discorb::Guild] The guild the message was sent in.
      attr_reader :guild
      # @macro client_cache
      # @return [Discorb::Message] The message the reaction was sent in.
      attr_reader :message
      # @return [Discorb::UnicodeEmoji, Discorb::PartialEmoji] The emoji that was reacted with.
      attr_reader :emoji

      #
      # Initializes a new instance of the ReactionEvent class.
      # @private
      #
      # @param [Discorb::Client] client The client that instantiated the object.
      # @param [Hash] data The data of the event.
      #
      def initialize(client, data)
        @client = client
        @data = data
        if data.key?(:user_id)
          @user_id = Snowflake.new(data[:user_id])
        else
          @member_data = data[:member]
        end
        @channel_id = Snowflake.new(data[:channel_id])
        @message_id = Snowflake.new(data[:message_id])
        @guild_id = Snowflake.new(data[:guild_id])
        @guild = client.guilds[data[:guild_id]]
        @channel = client.channels[data[:channel_id]] unless @guild.nil?

        @user = client.users[data[:user_id]]

        unless @guild.nil?
          @user =
            if data.key?(:member)
              @guild.members[data[:member][:user][:id]] ||
                Member.new(
                  @client,
                  @guild_id,
                  data[:member][:user],
                  data[:member]
                )
            else
              @guild.members[data[:user_id]]
            end || @user
        end

        @message = client.messages[data[:message_id]]
        @emoji =
          (
            if data[:emoji][:id].nil?
              UnicodeEmoji.new(data[:emoji][:name])
            else
              PartialEmoji.new(data[:emoji])
            end
          )
      end

      # Fetch the message.
      # If message is cached, it will be returned.
      # @async
      #
      # @param [Boolean] force Whether to force fetching the message.
      #
      # @return [Async::Task<Discorb::Message>] The message.
      def fetch_message(force: false)
        Async do
          next @message if !force && @message

          @message = @channel.fetch_message(@message_id).wait
        end
      end
    end

    #
    # Represents a `INTEGRATION_DELETE` event.
    #
    class IntegrationDeleteEvent < GatewayEvent
      # @return [Discorb::Snowflake] The ID of the integration.
      attr_reader :id

      # @!attribute [r] guild
      #   @macro client_cache
      #   @return [Discorb::Guild] The guild of the integration.
      # @!attribute [r] user
      #   @macro client_cache
      #   @return [Discorb::User] The user associated with the integration.

      #
      # Initialize a new instance of the IntegrationDeleteEvent class.
      # @private
      #
      #
      # @param [Hash] data The data of the event.
      #
      #
      def initialize(_client, data)
        @id = Snowflake.new(data[:id])
        @guild_id = data[:guild_id]
        @user_id = data[:application_id]
      end

      def guild
        @client.guilds[@guild_id]
      end

      def user
        @client.users[@user_id]
      end
    end

    #
    # Represents a `MESSAGE_REACTION_REMOVE_ALL` event.
    #
    class ReactionRemoveAllEvent < GatewayEvent
      # @return [Discorb::Snowflake] The ID of the channel the message was sent in.
      attr_reader :channel_id
      # @return [Discorb::Snowflake] The ID of the message.
      attr_reader :message_id
      # @return [Discorb::Snowflake] The ID of the guild the message was sent in.
      attr_reader :guild_id
      # @macro client_cache
      # @return [Discorb::Channel] The channel the message was sent in.
      attr_reader :channel
      # @macro client_cache
      # @return [Discorb::Guild] The guild the message was sent in.
      attr_reader :guild
      # @macro client_cache
      # @return [Discorb::Message] The message the reaction was sent in.
      attr_reader :message

      #
      # Initialize a new instance of the ReactionRemoveAllEvent class.
      # @private
      #
      # @param [Discorb::Client] client The client that instantiated the object.
      # @param [Hash] data The data of the event.
      #
      def initialize(client, data)
        @client = client
        @data = data
        @guild_id = Snowflake.new(data[:guild_id])
        @channel_id = Snowflake.new(data[:channel_id])
        @message_id = Snowflake.new(data[:message_id])
        @guild = client.guilds[data[:guild_id]]
        @channel = client.channels[data[:channel_id]]
        @message = client.messages[data[:message_id]]
      end

      # Fetch the message.
      # If message is cached, it will be returned.
      # @async
      #
      # @param [Boolean] force Whether to force fetching the message.
      #
      # @return [Async::Task<Discorb::Message>] The message.
      def fetch_message(force: false)
        Async do
          next @message if !force && @message

          @message = @channel.fetch_message(@message_id).wait
        end
      end
    end

    #
    # Represents a `MESSAGE_REACTION_REMOVE_EMOJI` event.
    #
    class ReactionRemoveEmojiEvent < GatewayEvent
      # @return [Discorb::Snowflake] The ID of the channel the message was sent in.
      attr_reader :channel_id
      # @return [Discorb::Snowflake] The ID of the message.
      attr_reader :message_id
      # @return [Discorb::Snowflake] The ID of the guild the message was sent in.
      attr_reader :guild_id
      # @macro client_cache
      # @return [Discorb::Channel] The channel the message was sent in.
      attr_reader :channel
      # @macro client_cache
      # @return [Discorb::Guild] The guild the message was sent in.
      attr_reader :guild
      # @macro client_cache
      # @return [Discorb::Message] The message the reaction was sent in.
      attr_reader :message
      # @return [Discorb::UnicodeEmoji, Discorb::PartialEmoji] The emoji that was reacted with.
      attr_reader :emoji

      #
      # Initialize a new instance of the ReactionRemoveEmojiEvent class.
      # @private
      #
      # @param [Discorb::Client] client The client that instantiated the object.
      # @param [Hash] data The data of the event.
      #
      def initialize(client, data)
        @client = client
        @data = data
        @guild_id = Snowflake.new(data[:guild_id])
        @channel_id = Snowflake.new(data[:channel_id])
        @message_id = Snowflake.new(data[:message_id])
        @guild = client.guilds[data[:guild_id]]
        @channel = client.channels[data[:channel_id]]
        @message = client.messages[data[:message_id]]
        @emoji =
          (
            if data[:emoji][:id].nil?
              DiscordEmoji.new(data[:emoji][:name])
            else
              PartialEmoji.new(data[:emoji])
            end
          )
      end

      # Fetch the message.
      # If message is cached, it will be returned.
      # @async
      #
      # @param [Boolean] force Whether to force fetching the message.
      #
      # @return [Async::Task<Discorb::Message>] The message.
      def fetch_message(force: false)
        Async do
          next @message if !force && @message

          @message = @channel.fetch_message(@message_id).wait
        end
      end
    end

    #
    # Represents a `GUILD_SCHEDULED_EVENT_USER_ADD` and `GUILD_SCHEDULED_EVENT_USER_REMOVE` event.
    #
    class ScheduledEventUserEvent < GatewayEvent
      # @return [Discorb::User] The user that triggered the event.
      attr_reader :user
      # @return [Discorb::Guild] The guild the event was triggered in.
      attr_reader :guild
      # @return [Discorb::ScheduledEvent] The scheduled event.
      attr_reader :scheduled_event

      #
      # Initialize a new instance of the ScheduledEventUserEvent class.
      # @private
      #
      # @param [Discorb::Client] client The client that instantiated the object.
      # @param [Hash] data The data of the event.
      #
      def initialize(client, data)
        @client = client
        @scheduled_event_id = Snowflake.new(data[:scheduled_event_id])
        @user_id = Snowflake.new(data[:user_id])
        @guild_id = Snowflake.new(data[:guild_id])
        @guild = client.guilds[data[:guild_id]]
        @scheduled_event = @guild.scheduled_events[@scheduled_event_id]
        @user = client.users[data[:user_id]]
      end
    end

    #
    # Represents a `MESSAGE_UPDATE` event.
    #
    class MessageUpdateEvent < GatewayEvent
      # @return [Discorb::Message] The message before update.
      attr_reader :before
      # @return [Discorb::Message] The message after update.
      attr_reader :after
      # @return [Discorb::Snowflake] The ID of the message.
      attr_reader :id
      # @return [Discorb::Snowflake] The ID of the channel the message was sent in.
      attr_reader :channel_id
      # @return [Discorb::Snowflake] The ID of the guild the message was sent in.
      attr_reader :guild_id
      # @return [String] The new content of the message.
      attr_reader :content
      # @return [Time] The time the message was edited.
      attr_reader :timestamp
      # @return [Boolean] Whether the message pings @everyone.
      attr_reader :mention_everyone
      # @macro client_cache
      # @return [Array<Discorb::Role>] The roles mentioned in the message.
      attr_reader :mention_roles
      # @return [Array<Discorb::Attachment>] The attachments in the message.
      attr_reader :attachments
      # @return [Array<Discorb::Embed>] The embeds in the message.
      attr_reader :embeds

      # @!attribute [r] channel
      #   @macro client_cache
      #   @return [Discorb::Channel] The channel the message was sent in.
      # @!attribute [r] guild
      #   @macro client_cache
      #   @return [Discorb::Guild] The guild the message was sent in.

      def initialize(client, data, before, after)
        @client = client
        @data = data
        @before = before
        @after = after
        @id = Snowflake.new(data[:id])
        @channel_id = Snowflake.new(data[:channel_id])
        @guild_id = Snowflake.new(data[:guild_id]) if data.key?(:guild_id)
        @content = data[:content]
        @timestamp = Time.iso8601(data[:edited_timestamp])
        @mention_everyone = data[:mention_everyone]
        @mention_roles =
          data[:mention_roles].map { |r| guild.roles[r] } if data.key?(
          :mention_roles
        )
        @attachments =
          data[:attachments].map { |a| Attachment.from_hash(a) } if data.key?(
          :attachments
        )
        @embeds =
          (
            if data[:embeds]
              data[:embeds].map { |e| Embed.from_hash(e) }
            else
              []
            end
          ) if data.key?(:embeds)
      end

      def channel
        @client.channels[@channel_id]
      end

      def guild
        @client.guilds[@guild_id]
      end

      # Fetch the message.
      # @async
      #
      # @return [Async::Task<Discorb::Message>] The message.
      def fetch_message
        Async { channel.fetch_message(@id).wait }
      end
    end

    #
    # Represents a message but it has only ID.
    #
    class UnknownDeleteBulkMessage < GatewayEvent
      # @return [Discorb::Snowflake] The ID of the message.
      attr_reader :id

      # @!attribute [r] channel
      #   @macro client_cache
      #   @return [Discorb::Channel] The channel the message was sent in.
      # @!attribute [r] guild
      #   @macro client_cache
      #   @return [Discorb::Guild] The guild the message was sent in.

      #
      # Initialize a new instance of the UnknownDeleteBulkMessage class.
      # @private
      #
      # @param [Discorb::Client] client The client that instantiated the object.
      # @param [Hash] data The data of the event.
      #
      def initialize(client, id, data)
        @client = client
        @id = Snowflake.new(id)
        @data = data
        @channel_id = Snowflake.new(data[:channel_id])
        @guild_id = Snowflake.new(data[:guild_id]) if data.key?(:guild_id)
      end

      def channel
        @client.channels[@channel_id]
      end

      def guild
        @client.guilds[@guild_id]
      end
    end

    #
    # Represents a `INVITE_DELETE` event.
    #
    class InviteDeleteEvent < GatewayEvent
      # @return [String] The invite code.
      attr_reader :code

      # @!attribute [r] channel
      #   @macro client_cache
      #   @return [Discorb::Channel] The channel the message was sent in.
      # @!attribute [r] guild
      #   @macro client_cache
      #   @return [Discorb::Guild] The guild the message was sent in.

      #
      # Initialize a new instance of the InviteDeleteEvent class.
      # @private
      #
      # @param [Discorb::Client] client The client that instantiated the object.
      # @param [Hash] data The data of the event.
      #
      def initialize(client, data)
        @client = client
        @data = data
        @channel_id = Snowflake.new(data[:channel])
        @guild_id = Snowflake.new(data[:guild_id])
        @code = data[:code]
      end

      def channel
        @client.channels[@channel_id]
      end

      def guild
        @client.guilds[@guild_id]
      end
    end

    #
    # Represents a `TYPING_START` event.
    #
    class TypingStartEvent < GatewayEvent
      # @return [Discorb::Snowflake] The ID of the channel the user is typing in.
      attr_reader :user_id

      # @!attribute [r] channel
      #   @macro client_cache
      #   @return [Discorb::Channel] The channel the user is typing in.
      # @!attribute [r] guild
      #   @macro client_cache
      #   @return [Discorb::Guild] The guild the user is typing in.
      # @!attribute [r] user
      #   @macro client_cache
      #   @return [Discorb::User, Discorb::Member] The user that is typing.

      #
      # Initialize a new instance of the TypingStartEvent class.
      # @private
      #
      # @param [Discorb::Client] client The client that instantiated the object.
      # @param [Hash] data The data of the event.
      #
      def initialize(client, data)
        @client = client
        @data = data
        @channel_id = Snowflake.new(data[:channel_id])
        @guild_id = Snowflake.new(data[:guild_id]) if data.key?(:guild_id)
        @user_id = Snowflake.new(data[:user_id])
        @timestamp = Time.at(data[:timestamp])
        if guild
          @member =
            guild.members[@user_id] ||
              Member.new(
                @client,
                @guild_id,
                @client.users[@user_id].instance_variable_get(:@data),
                data[:member]
              )
        end
      end

      def user
        @member || guild&.members&.[](@user_id) || @client.users[@user_id]
      end

      alias member user

      def channel
        @client.channels[@channel_id]
      end

      def guild
        @client.guilds[@guild_id]
      end
    end

    #
    # Represents a message pin event.
    #
    class MessagePinEvent < GatewayEvent
      # @return [Discorb::Message] The message that was pinned.
      attr_reader :message
      # @return [:pinned, :unpinned] The type of event.
      attr_reader :type

      # @!attribute [r] pinned?
      #   @return [Boolean] Whether the message was pinned.
      # @!attribute [r] unpinned?
      #   @return [Boolean] Whether the message was unpinned.

      def initialize(client, data, message)
        @client = client
        @data = data
        @message = message
        @type =
          if message.nil?
            :unknown
          elsif @message.pinned?
            :pinned
          else
            :unpinned
          end
      end

      def pinned?
        @type == :pinned
      end

      def unpinned?
        @type == :unpinned
      end
    end

    #
    # Represents a `WEBHOOKS_UPDATE` event.
    #
    class WebhooksUpdateEvent < GatewayEvent
      # @!attribute [r] channel
      #   @macro client_cache
      #   @return [Discorb::Channel] The channel where the webhook was updated.
      # @!attribute [r] guild
      #   @macro client_cache
      #   @return [Discorb::Guild] The guild where the webhook was updated.

      #
      # Initialize a new instance of the WebhooksUpdateEvent class.
      # @private
      #
      # @param [Discorb::Client] client The client that instantiated the object.
      # @param [Hash] data The data of the event.
      #
      def initialize(client, data)
        @client = client
        @data = data
        @guild_id = Snowflake.new(data[:guild_id])
        @channel_id = Snowflake.new(data[:channel_id])
      end

      def guild
        @client.guilds[@guild_id]
      end

      def channel
        @client.channels[@channel_id]
      end
    end

    #
    # Represents a `AUTO_MODERATION_ACTION_EXECUTION` event.
    #
    class AutoModerationActionExecutionEvent < GatewayEvent
      # @return [Discorb::Snowflake] The id of the rule.
      attr_reader :rule_id

      # @return [Symbol] The type of action that was executed.
      attr_reader :rule_trigger_type

      # @return [Discorb::Snowflake] The id of the message that triggered the action.
      # @return [nil] If the message was deleted.
      attr_reader :message_id

      # @return [Discorb::Snowflake] The id of the system message that was sent.
      # @return [nil] If the system message channel was not set.
      attr_reader :alert_system_message_id

      # @return [String] The content of the message that was sent.
      attr_reader :content

      # @return [String] The keyword that triggered the action.
      # @return [nil] If the action was not triggered by a keyword.
      attr_reader :matched_keyword

      # @return [String] The content that triggered the action.
      # @return [nil] If the action was not triggered by a keyword.
      attr_reader :matched_content

      # @return [Discorb::AutoModRule::Action] The action that was executed.
      attr_reader :action

      #
      # Initialize a new instance of the AutoModerationActionExecutionEvent class.
      # @private
      #
      # @param [Discorb::Client] client The client that instantiated the object.
      # @param [Hash] data The data of the event.
      #
      def initialize(client, data)
        @client = client
        @data = data
        @rule_id = Snowflake.new(data[:rule_id])
        @rule_trigger_type =
          Discorb::AutoModRule::TRIGGER_TYPES[data[:rule_trigger_type]]
        @action = Discorb::AutoModRule::Action.new(data[:action])
        @user_id = Snowflake.new(data[:user_id])
        @guild_id = Snowflake.new(data[:guild_id])
        @channel_id = data[:channel_id] && Snowflake.new(data[:channel_id])
        @message_id = data[:message_id] && Snowflake.new(data[:message_id])
        @alert_system_message_id =
          data[:alert_system_message_id] &&
            Snowflake.new(data[:alert_system_message_id])
        @content = data[:content]
        @matched_keyword = data[:matched_keyword]
        @matched_content = data[:matched_content]
      end

      # @!attribute [r] guild
      #   @return [Discorb::Guild] The guild where the rule was executed.
      def guild
        @client.guilds[@guild_id]
      end

      # @!attribute [r] channel
      #   @return [Discorb::Channel] The channel where the rule was executed.
      def channel
        @client.channels[@channel_id]
      end

      # @!attribute [r] member
      #   @return [Discorb::Member] The member that triggered the action.
      def member
        guild.members[@user_id]
      end

      alias user member
    end
  end
end