discorb-lib/discorb

View on GitHub
lib/discorb/channel/guild.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module Discorb
  #
  # Represents a channel in guild.
  # @abstract
  #
  class GuildChannel < Channel
    # @return [Integer] The position of the channel as integer.
    attr_reader :position
    # @return [Hash{Discorb::Role, Discorb::Member => PermissionOverwrite}] The permission overwrites of the channel.
    attr_reader :permission_overwrites

    # @!attribute [r] mention
    #   @return [String] The mention of the channel.
    #
    # @!attribute [r] parent
    #   @macro client_cache
    #   @return [Discorb::CategoryChannel] The parent of channel.
    #   @return [nil] If the channel is not a child of category.
    #
    # @!attribute [r] guild
    #   @return [Discorb::Guild] The guild of channel.
    #   @macro client_cache

    include Comparable
    @channel_type = nil

    #
    # Compares position of two channels.
    #
    # @param [Discorb::GuildChannel] other The channel to compare.
    #
    # @return [-1, 0, 1] -1 if the channel is at lower than the other, 1 if the channel is at highter than the other.
    #
    def <=>(other)
      return nil unless other.respond_to?(:position)

      @position <=> other.position
    end

    #
    # Checks if the channel is same as another.
    #
    # @param [Discorb::GuildChannel] other The channel to check.
    #
    # @return [Boolean] `true` if the channel is same as another.
    #
    def ==(other)
      return false unless other.respond_to?(:id)

      @id == other.id
    end

    #
    # Stringifies the channel.
    #
    # @return [String] The name of the channel with `#`.
    #
    def to_s
      "##{@name}"
    end

    def mention
      "<##{@id}>"
    end

    def parent
      return nil unless @parent_id

      @client.channels[@parent_id]
    end

    alias category parent

    def guild
      @client.guilds[@guild_id]
    end

    def inspect
      "#<#{self.class} \"##{@name}\" id=#{@id}>"
    end

    #
    # Deletes the channel.
    # @async
    #
    # @param [String] reason The reason of deleting the channel.
    #
    # @return [Async::Task<self>] The deleted channel.
    #
    def delete(reason: nil)
      Async do
        @client
          .http
          .request(
            Route.new(
              base_url.wait.to_s,
              "//webhooks/:webhook_id/:token",
              :delete
            ),
            {},
            audit_log_reason: reason
          )
          .wait
        @deleted = true
        self
      end
    end

    alias close delete
    alias destroy delete

    #
    # Moves the channel to another position.
    # @async
    #
    # @param [Integer] position The position to move the channel.
    # @param [Boolean] lock_permissions Whether to lock the permissions of the channel.
    # @param [Discorb::CategoryChannel] parent The parent of channel.
    # @param [String] reason The reason of moving the channel.
    #
    # @return [Async::Task<self>] The moved channel.
    #
    def move(
      position,
      lock_permissions: false,
      parent: Discorb::Unset,
      reason: nil
    )
      Async do
        # @type var payload: Hash[Symbol, untyped]
        payload = { position: }
        payload[:lock_permissions] = lock_permissions
        payload[:parent_id] = parent&.id if parent != Discorb::Unset
        @client
          .http
          .request(
            Route.new(
              "/guilds/#{@guild_id}/channels",
              "//guilds/:guild_id/channels",
              :patch
            ),
            payload,
            audit_log_reason: reason
          )
          .wait
      end
    end

    #
    # Set the channel's permission overwrite.
    # @async
    #
    # @param [Discorb::Role, Discorb::Member] target The target of the overwrite.
    # @param [String] reason The reason of setting the overwrite.
    # @param [{Symbol => Boolean}] perms The permission overwrites to replace.
    #
    # @return [Async::Task<void>] The task.
    #
    def set_permissions(target, reason: nil, **perms)
      Async do
        allow_value = @permission_overwrites[target]&.allow_value.to_i
        deny_value = @permission_overwrites[target]&.deny_value.to_i
        perms.each do |perm, value|
          allow_value[Discorb::Permission.bits[perm]] = 1 if value == true
          deny_value[Discorb::Permission.bits[perm]] = 1 if value == false
        end
        payload = {
          allow: allow_value,
          deny: deny_value,
          type: target.is_a?(Member) ? 1 : 0
        }
        @client
          .http
          .request(
            Route.new(
              "/channels/#{@id}/permissions/#{target.id}",
              "//channels/:channel_id/permissions/:target_id",
              :put
            ),
            payload,
            audit_log_reason: reason
          )
          .wait
      end
    end

    alias modify_permissions set_permissions
    alias modify_permisssion set_permissions
    alias edit_permissions set_permissions
    alias edit_permission set_permissions

    #
    # Delete the channel's permission overwrite.
    # @async
    #
    # @param [Discorb::Role, Discorb::Member] target The target of the overwrite.
    # @param [String] reason The reason of deleting the overwrite.
    #
    # @return [Async::Task<void>] The task.
    #
    def delete_permissions(target, reason: nil)
      Async do
        @client
          .http
          .request(
            Route.new(
              "/channels/#{@id}/permissions/#{target.id}",
              "//channels/:channel_id/permissions/:target_id",
              :delete
            ),
            {},
            audit_log_reason: reason
          )
          .wait
      end
    end

    alias delete_permission delete_permissions
    alias destroy_permissions delete_permissions
    alias destroy_permission delete_permissions

    #
    # Fetch the channel's invites.
    # @async
    #
    # @return [Async::Task<Array<Discorb::Invite>>] The invites in the channel.
    #
    def fetch_invites
      Async do
        _resp, data =
          @client
            .http
            .request(
              Route.new(
                "/channels/#{@id}/invites",
                "//channels/:channel_id/invites",
                :get
              )
            )
            .wait
        data.map { |invite| Invite.new(@client, invite, false) }
      end
    end

    #
    # Create an invite in the channel.
    # @async
    #
    # @param [Integer] max_age The max age of the invite.
    # @param [Integer] max_uses The max uses of the invite.
    # @param [Boolean] temporary Whether the invite is temporary.
    # @param [Boolean] unique Whether the invite is unique.
    #   @note if it's `false` it may return existing invite.
    # @param [String] reason The reason of creating the invite.
    #
    # @return [Async::Task<Invite>] The created invite.
    #
    def create_invite(
      max_age: nil,
      max_uses: nil,
      temporary: false,
      unique: false,
      reason: nil
    )
      Async do
        _resp, data =
          @client
            .http
            .request(
              Route.new(
                "/channels/#{@id}/invites",
                "//channels/:channel_id/invites",
                :post
              ),
              {
                max_age:,
                max_uses:,
                temporary:,
                unique:
              },
              audit_log_reason: reason
            )
            .wait
        Invite.new(@client, data, false)
      end
    end

    private

    def _set_data(data)
      @guild_id = data[:guild_id]
      @position = data[:position]
      @permission_overwrites =
        if data[:permission_overwrites]
          data[:permission_overwrites].to_h do |ow|
            [
              (ow[:type] == 1 ? guild.roles : guild.members)[ow[:id]],
              PermissionOverwrite.new(ow[:allow].to_i, ow[:deny].to_i)
            ]
          end
        else
          {}
        end
      @parent_id = data[:parent_id]

      super
    end
  end
end