Friday, September 20, 2024 2:53:43 AM
> settings

Customize


Authenticate

> user.rb
# frozen_string_literal: true

module ESM
  class User < ApplicationRecord
    attr_writer :discord_user

    after_create :create_user_steam_data
    after_create :create_id_defaults

    attribute :discord_id, :string
    attribute :discord_username, :string
    attribute :discord_avatar, :text, default: nil
    attribute :discord_access_token, :string, default: nil
    attribute :discord_refresh_token, :string, default: nil
    attribute :steam_uid, :string, default: nil
    attribute :created_at, :datetime
    attribute :updated_at, :datetime

    alias_attribute :avatar_url, :discord_avatar
    alias_attribute :distinct, :discord_username
    alias_attribute :username, :discord_username

    has_many :cooldowns, dependent: :nullify
    has_many :id_aliases, class_name: "UserAlias", dependent: :destroy
    has_one :id_defaults, class_name: "UserDefault", dependent: :destroy
    has_many :logs, class_name: "Log", foreign_key: "requestors_user_id", dependent: :destroy
    has_many :my_requests, foreign_key: :requestor_user_id, class_name: "Request", dependent: :destroy
    has_many :pending_requests, foreign_key: :requestee_user_id, class_name: "Request", dependent: :destroy
    has_many :user_gamble_stats, dependent: :destroy
    has_many :user_notification_preferences, dependent: :destroy
    has_many :user_notification_routes, dependent: :destroy
    has_one :user_steam_data, dependent: :destroy

    # validates :discord_id, uniqueness: true, presence: true
    # validates :steam_uid, uniqueness: true

    delegate :on, to: :discord_user, allow_nil: true

    #########################
    # Public Methods
    #########################

    # Parses and finds a user based off of SteamUID, Discord ID, or Discord Mention
    def self.parse(input)
      return if input.nil?

      # In case of frozen strings
      input = input.dup if input.frozen?

      # Discordrb stores the Discord ID as an Integer.
      input = input.to_s if !input.is_a?(String)

      if ESM::Regex::DISCORD_TAG_ONLY.match?(input)
        # Remove the extra stuff from a mention
        find_by_discord_id(input.gsub(/[<@!&>]/, ""))
      elsif input.steam_uid?
        find_by_steam_uid(input)
      else
        find_by_discord_id(input)
      end
    end

    def self.from_discord(discord_user)
      return if discord_user.nil?

      user = order(:discord_id)
        .where(discord_id: discord_user.id)
        .first_or_initialize

      user.update!(discord_username: discord_user.username, discord_avatar: discord_user.avatar_url)
      user.discord_user = discord_user
      user
    end

    def self.find_by_steam_uid(uid)
      order(:steam_uid).where(steam_uid: uid).first
    end

    def self.find_by_discord_id(id)
      id = id.to_s unless id.is_a?(String)
      order(:discord_id).where(discord_id: id).first
    end

    #########################
    # Instance Methods
    #########################

    def attributes_for_logging
      attributes.except("id", "discord_avatar", "discord_access_token", "discord_refresh_token", "updated_at")
    end

    def steam_data
      @steam_data ||= user_steam_data&.refresh
    end

    def registered?
      steam_uid.present?
    end

    def developer?
      ESM.config.dev_user_allowlist.include?(discord_id)
    end

    def mention
      "<@#{discord_id}>"
    end
    alias_method :discord_mention, :mention

    def discord_user
      return if discord_id.nil?

      @discord_user ||= lambda do
        discord_user = ESM.bot.user(discord_id)
        return if discord_user.nil?

        # Keep the discord user data up-to-date
        incoming_attributes = [discord_user.username, discord_user.avatar_url]
        current_attributes = [discord_username, discord_avatar]

        if current_attributes != incoming_attributes
          update!(
            discord_username: discord_user.username,
            discord_avatar: discord_user.avatar_url
          )
        end

        # Save some data for later consumption
        discord_user.esm_user = self
        discord_user
      end.call
    end

    def discord_servers
      return if discord_id.nil?

      @discord_servers ||= ESM.bot.servers.values.select do |server|
        server.users.any? { |user| user.id.to_s == discord_id }
      end
    end

    def can_modify?(guild_id)
      return false if discord_id.nil?
      return true if developer? && !Rails.env.development?

      community = Community.find_by_guild_id(guild_id)
      return false if community.nil?

      server = community.discord_server
      return false if server.nil?

      # Check if they're the owner or admin
      community.modifiable_by?(on(server))
    end

    def channel_permission?(permission, channel)
      !!on(channel.server)&.permission?(permission, channel)
    end
  end
end
All opinions represented herein are my own
- © 2024 itsthedevman
- build 340fbb8