discorb-lib/discorb

View on GitHub
lib/discorb/user.rb

Summary

Maintainability
A
1 hr
Test Coverage
# frozen_string_literal: true

module Discorb
  #
  # Represents a user of discord.
  #
  class User < DiscordModel
    # @return [Boolean] Whether the user is verified.
    attr_reader :verified
    # @return [String] The user's username. ("sevenc_nanashi" for new users, "Nanashi." for old users.)
    attr_reader :username
    alias name username
    # @return [Discorb::Snowflake] The user's ID.
    attr_reader :id
    # @return [Discorb::User::Flag] The user's flags.
    attr_reader :flag
    # @return [String] The user's discriminator. ("0" for new users, "7740" for old users.)
    # @deprecated This will be removed in the future because of discord changes.
    attr_reader :discriminator
    # @return [String] The user's global name. ("Nanashi." for new users, old users have no global name.)
    attr_reader :global_name
    # @return [Discorb::Asset, Discorb::DefaultAvatar] The user's avatar.
    attr_reader :avatar
    # @return [Boolean] Whether the user is a bot.
    attr_reader :bot
    alias bot? bot
    # @return [Time] The time the user was created.
    attr_reader :created_at

    include Discorb::Messageable

    # @!attribute [r] mention
    #   @return [String] The user's mention.

    #
    # Initializes a new user.
    # @private
    #
    # @param [Discorb::Client] client The client.
    # @param [Hash] data The user data.
    #
    def initialize(client, data)
      @client = client
      @data = {}
      @dm_channel_id = nil
      _set_data(data)
    end

    #
    # Format the user as `Global name (@Username)` or `Username#Discriminator` style.
    #
    # @return [String] The formatted username.
    #
    def to_s
      if @discriminator == "0"
        "#{@global_name} (@#{@username})"
      else
        "#{@username}##{@discriminator}"
      end
    end

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

    alias to_s_user to_s

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

    #
    # Whether the user is a owner of the client.
    # @async
    #
    # @param [Boolean] strict Whether don't allow if the user is a member of the team.
    #
    # @return [Async::Task<Boolean>] Whether the user is a owner of the client.
    #
    def bot_owner?(strict: false)
      Async do
        app = @client.fetch_application.wait
        if app.team.nil?
          app.owner == self
        elsif strict
          app.team.owner == self
        else
          app.team.members.any? { |m| m.user == self }
        end
      end
    end

    alias app_owner? bot_owner?

    #
    # Returns the dm channel id of the user.
    # @private
    #
    # @return [Async::Task<Discorb::Snowflake>] A task that resolves to the channel id.
    #
    def channel_id
      Async do
        next @dm_channel_id if @dm_channel_id

        _resp, dm_channel =
          @client
            .http
            .request(
              Route.new("/users/@me/channels", "//users/@me/channels", :post),
              { recipient_id: @id }
            )
            .wait
        @dm_channel_id = dm_channel[:id]
        @dm_channel_id
      end
    end

    #
    # Represents the user's flags.
    # ## Flag fields
    # |`1 << 0`|`:staff`|
    # |`1 << 1`|`:partner`|
    # |`1 << 2`|`:hypesquad`|
    # |`1 << 3`|`:bug_hunter_level_1`|
    # |`1 << 6`|`:hypesquad_online_house_1`|
    # |`1 << 7`|`:hypesquad_online_house_2`|
    # |`1 << 8`|`:hypesquad_online_house_3`|
    # |`1 << 9`|`:premium_early_supporter`|
    # |`1 << 10`|`:team_psuedo_user`|
    # |`1 << 14`|`:bug_hunter_level_2`|
    # |`1 << 16`|`:verified_bot`|
    # |`1 << 17`|`:verified_developer`|
    # |`1 << 18`|`:certified_moderator`|
    # |`1 << 19`|`:bot_http_interactions`|
    #
    class Flag < Discorb::Flag
      @bits = {
        staff: 0,
        partner: 1,
        hypesquad: 2,
        bug_hunter_level_1: 3,
        hypesquad_online_house_1: 6,
        hypesquad_online_house_2: 7,
        hypesquad_online_house_3: 8,
        premium_early_supporter: 9,
        team_psuedo_user: 10,
        bug_hunter_level_2: 14,
        verified_bot: 16,
        verified_developer: 17,
        certified_moderator: 18,
        bot_http_interactions: 19
      }.freeze
    end

    private

    def _set_data(data)
      @username = data[:username]
      @global_name = data[:global_name]
      @verified = data[:verified]
      @id = Snowflake.new(data[:id])
      @flag = User::Flag.new(data[:public_flags] | (data[:flags] || 0))
      @discriminator = data[:discriminator]
      @avatar =
        (
          if data[:avatar]
            Asset.new(self, data[:avatar])
          else
            DefaultAvatar.new(data[:discriminator])
          end
        )
      @bot = data[:bot] || false
      @raw_data = data
      @client.users[@id] = self unless data[:no_cache]
      @created_at = @id.timestamp
      @data.update(data)
    end
  end

  #
  # Represents a client user.
  #
  class ClientUser < User
    #
    # Edit the client user.
    # @async
    # @macro edit
    #
    # @param [String] name The new username.
    # @param [Discorb::Image] avatar The new avatar.
    #
    # @return [Async::Task<void>] The task.
    #
    def edit(name: Discorb::Unset, avatar: Discorb::Unset)
      Async do
        payload = {}
        payload[:username] = name unless name == Discorb::Unset
        if avatar == Discorb::Unset
          # Nothing
        elsif avatar.nil?
          payload[:avatar] = nil
        else
          payload[:avatar] = avatar.to_s
        end
        @client
          .http
          .request(Route.new("/users/@me", "//users/@me", :patch), payload)
          .wait
        self
      end
    end
  end
end