discorb-lib/discorb

View on GitHub
lib/discorb/interaction/response.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module Discorb
  #
  # Represents an interaction of Discord.
  #
  class Interaction
    #
    # A module for response with source.
    #
    module SourceResponder
      # @type instance: Discorb::Interaction

      #
      # Response with `DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE`(`5`).
      #
      # @async
      #
      # @param [Boolean] ephemeral Whether to make the response ephemeral.
      #
      # @return [Async::Task<void>] The task.
      #
      def defer_source(ephemeral: false)
        Async do
          @client
            .http
            .request(
              Route.new(
                "/interactions/#{@id}/#{@token}/callback",
                "//interactions/:interaction_id/:token/callback",
                :post
              ),
              { type: 5, data: { flags: (ephemeral ? 1 << 6 : 0) } }
            )
            .wait
          @defered = true
        end
      end

      #
      # Response with `CHANNEL_MESSAGE_WITH_SOURCE`(`4`).
      #
      # @async
      #
      # @param [String] content The content of the response.
      # @param [Boolean] tts Whether to send the message as text-to-speech.
      # @param [Discorb::Embed] embed The embed to send.
      # @param [Array<Discorb::Embed>] embeds The embeds to send. (max: 10)
      # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions to send.
      # @param [Discorb::Attachment] attachment The attachment to send.
      # @param [Array<Discorb::Attachment>] attachments The attachments to send. (max: 10)
      # @param [Array<Discorb::Component>, Array<Array<Discorb::Component>>] components The components to send.
      # @param [Boolean] ephemeral Whether to make the response ephemeral.
      #
      # @return [Discorb::Interaction::SourceResponder::CallbackMessage, Discorb::Webhook::Message]
      #   The callback message.
      #
      def post(
        content = nil,
        tts: false,
        embed: nil,
        embeds: nil,
        allowed_mentions: nil,
        attachment: nil,
        attachments: nil,
        components: nil,
        ephemeral: false
      )
        Async do
          payload = {}
          payload[:content] = content if content
          payload[:tts] = tts
          payload[:embeds] = (embeds || [embed])
            .map { |e| e&.to_hash }
            .filter { _1 }
          payload[:allowed_mentions] = allowed_mentions&.to_hash(
            @client.allowed_mentions
          ) || @client.allowed_mentions.to_hash
          payload[:components] = Component.to_payload(components) if components
          payload[:flags] = (ephemeral ? 1 << 6 : 0)
          attachments ||= attachment ? [attachment] : []

          payload[:attachments] = attachments.map.with_index do |a, i|
            { id: i, filename: a.filename, description: a.description }
          end

          ret =
            if @responded
              _resp, data =
                @client
                  .http
                  .multipart_request(
                    Route.new(
                      "/webhooks/#{@application_id}/#{@token}",
                      "//webhooks/:webhook_id/:token",
                      :post
                    ),
                    payload,
                    attachments
                  )
                  .wait
              webhook =
                Webhook::URLWebhook.new(
                  "/webhooks/#{@application_id}/#{@token}"
                )
              Webhook::Message.new(webhook, data, @client)
            elsif @defered
              @client
                .http
                .multipart_request(
                  Route.new(
                    "/webhooks/#{@application_id}/#{@token}/messages/@original",
                    "//webhooks/:webhook_id/:token/messages/@original",
                    :patch
                  ),
                  payload,
                  attachments
                )
                .wait
              CallbackMessage.new(@client, payload, @application_id, @token)
            else
              @client
                .http
                .multipart_request(
                  Route.new(
                    "/interactions/#{@id}/#{@token}/callback",
                    "//interactions/:interaction_id/:token/callback",
                    :post
                  ),
                  { type: 4, data: payload },
                  attachments
                )
                .wait
              CallbackMessage.new(@client, payload, @application_id, @token)
            end
          @responded = true
          ret
        end
      end
    end

    #
    # Represents of a callback message of interaction.
    #
    class CallbackMessage
      #
      # Initializes a new instance of CallbackMessage.
      # @private
      #
      # @param [Client] client The client.
      # @param [Hash] data The payload.
      # @param [String] application_id The application ID.
      # @param [String] token The token.
      #
      def initialize(client, data, application_id, token)
        @client = client
        @data = data
        @application_id = application_id
        @token = token
      end

      #
      # Edits the callback message.
      # @async
      # @macro edit
      #
      # @param [String] content The new content of the message.
      # @param [Discorb::Embed] embed The new embed of the message.
      # @param [Array<Discorb::Embed>] embeds The new embeds of the message.
      # @param [Array<Discorb::Attachment>] attachments The attachments to remain.
      # @param [Discorb::Attachment] file The file to send.
      # @param [Array<Discorb::Attachment>] files The files to send.
      #
      # @return [Async::Task<void>] The task.
      #
      def edit(
        content = Discorb::Unset,
        embed: Discorb::Unset,
        embeds: Discorb::Unset,
        file: Discorb::Unset,
        files: Discorb::Unset,
        attachments: Discorb::Unset
      )
        Async do
          payload = {}
          payload[:content] = content if content != Discorb::Unset
          payload[:embeds] = embed ? [embed.to_hash] : [] if embed !=
            Discorb::Unset
          payload[:embeds] = embeds.map(&:to_hash) if embeds != Discorb::Unset
          payload[:attachments] = attachments.map(&:to_hash) if attachments !=
            Discorb::Unset
          files = [file] if file != Discorb::Unset
          files = [] if files == Discorb::Unset
          @client
            .http
            .multipart_request(
              Route.new(
                "/webhooks/#{@application_id}/#{@token}/messages/@original",
                "//webhooks/:webhook_id/:token/messages/@original",
                :patch
              ),
              payload,
              files
            )
            .wait
        end
      end

      alias modify edit

      #
      # Deletes the callback message.
      # @async
      # @note This will fail if the message is ephemeral.
      #
      # @return [Async::Task<void>] The task.
      #
      def delete
        Async do
          @client
            .http
            .request(
              Route.new(
                "/webhooks/#{@application_id}/#{@token}/messages/@original",
                "//webhooks/:webhook_id/:token/messages/@original",
                :delete
              )
            )
            .wait
        end
      end

      def inspect
        "#<#{self.class.name} application_id=#{@application_id}"
      end
    end

    #
    # A module for response with update.
    #
    module UpdateResponder
      # @type instance: Discorb::Interaction

      #
      # Response with `DEFERRED_UPDATE_MESSAGE`(`6`).
      # @async
      #
      # @param [Boolean] ephemeral Whether to make the response ephemeral.
      #
      # @return [Async::Task<void>] The task.
      #
      def defer_update(ephemeral: false)
        Async do
          @client
            .http
            .request(
              Route.new(
                "/interactions/#{@id}/#{@token}/callback",
                "//interactions/:interaction_id/:token/callback",
                :post
              ),
              { type: 6, data: { flags: (ephemeral ? 1 << 6 : 0) } }
            )
            .wait
        end
      end

      #
      # Response with `UPDATE_MESSAGE`(`7`).
      #
      # @async
      #
      # @param [String] content The content of the response.
      # @param [Boolean] tts Whether to send the message as text-to-speech.
      # @param [Discorb::Embed] embed The embed to send.
      # @param [Array<Discorb::Embed>] embeds The embeds to send. (max: 10)
      # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions to send.
      # @param [Discorb::Attachment] attachment The attachment to send.
      # @param [Array<Discorb::Attachment>] attachments The attachments to send. (max: 10)
      # @param [Array<Discorb::Component>, Array<Array<Discorb::Component>>] components The components to send.
      # @param [Boolean] ephemeral Whether to make the response ephemeral.
      #
      # @return [Async::Task<void>] The task.
      #
      def edit(
        content,
        tts: false,
        embed: nil,
        embeds: nil,
        allowed_mentions: nil,
        attachment: nil,
        attachments: nil,
        components: nil,
        ephemeral: false
      )
        Async do
          payload = {}
          payload[:content] = content if content
          payload[:tts] = tts
          tmp_embed =
            if embed
              [embed]
            elsif embeds
              embeds
            end
          payload[:embeds] = tmp_embed.map(&:to_hash) if tmp_embed
          payload[:allowed_mentions] = (
            if allowed_mentions
              allowed_mentions.to_hash(@client.allowed_mentions)
            else
              @client.allowed_mentions.to_hash
            end
          )
          payload[:components] = Component.to_payload(components) if components
          payload[:flags] = (ephemeral ? 1 << 6 : 0)
          attachments ||= [attachment] if attachment
          payload[:attachments] = attachments.map.with_index do |a, i|
            { id: i, filename: a.filename, description: a.description }
          end
          @client
            .http
            .multipart_request(
              Route.new(
                "/interactions/#{@id}/#{@token}/callback",
                "//interactions/:interaction_id/:token/callback",
                :post
              ),
              { type: 7, data: payload },
              attachments
            )
            .wait
        end
      end
    end

    #
    # A module for response with modal.
    #
    module ModalResponder
      # @type instance: Discorb::Interaction

      #
      # Response with `MODAL`(`9`).
      #
      # @param [String] title The title of the modal.
      # @param [String] custom_id The custom id of the modal.
      # @param [Array<Discorb::TextInput>] components The text inputs to send.
      #
      # @return [Async::Task<void>] The task.
      #
      def show_modal(title, custom_id, components)
        Async do
          payload = {
            title:,
            custom_id:,
            components: Component.to_payload(components)
          }
          @client
            .http
            .request(
              Route.new(
                "/interactions/#{@id}/#{@token}/callback",
                "//interactions/:interaction_id/:token/callback",
                :post
              ),
              { type: 9, data: payload }
            )
            .wait
        end
      end
    end

    private

    def _set_data(_)
      nil
    end
  end
end