Source: web/WebUserData.js

// Copyright 2019 Campbell Crowley. All rights reserved.
// Author: Campbell Crowley (dev@campbellcrowley.com)

/**
 * @classdesc The user data injected to be sent along with all user request to
 * the web API.
 * @class
 */
class WebUserData {
  /**
   * @description Create an instance of the user metadata.
   * @param {string} id User ID of user performing request.
   * @param {string} ip IP of current request client.
   */
  constructor(id, ip) {
    /**
     * @description The user's ID.
     *
     * @see {WebUserData~id}
     *
     * @private
     * @type {string}
     * @constant
     */
    this._id = id;
    /**
     * @description IP address of requesting client. Used for logging and rate
     * limiting.
     *
     * @see {WebUserData~ip}
     *
     * @private
     * @type {string}
     * @constant
     */
    this._ip = ip;
    /**
     * @description Array of guild IDs this user is a part of. This will only be
     * available if request was made using the user's token with 'guilds' as a
     * scope, and thus may not exist in all requests.* It may be used to improve
     * efficiency, to prevent looking up all guilds with the user performing the
     * request.
     *
     * @see {WebUserData~guilds}
     *
     * @private
     * @type {null|string[]}
     * @default
     */
    this._guilds = null;

    /**
     * @description Is this user data, and this request, from the public API. If
     * false, there are fewer restrictions because this request is from a
     * private filtered internal source.
     *
     * @private
     * @type {boolean}
     * @default
     */
    this.apiRequest = false;

    /**
     * @description Session ID for the user request. Null if request was not
     * made as a session.
     * @private
     * @type {?string}
     * @default
     */
    this._sessionId = null;
    /**
     * @description Session expiration timestamp for the user request.
     * @private
     * @type {?number}
     * @default
     */
    this._sessionExpirationDate = null;

    /**
     * @description Legacy session data.
     * @private
     * @type {object}
     * @deprecated
     * @default
     */
    this._session = {
      id: this.sessionId,
      expiration_date: this.sessionExpirationDate,
    };

    /**
     * @description User's username.
     *
     * {@link
     * https://discordapp.com/developers/docs/resources/user#user-object}.
     *
     * @public
     * @type {?string}
     * @default
     */
    this.username = null;
    /**
     * @description User's account discriminator.
     *
     * {@link
     * https://discordapp.com/developers/docs/resources/user#user-object}.
     *
     * @public
     * @type {?string}
     * @default
     */
    this.discriminator = null;
    /**
     * @description User's avatar hash.
     *
     * {@link
     * https://discordapp.com/developers/docs/resources/user#user-object}.
     *
     * @public
     * @type {?string}
     * @default
     */
    this.avatar = null;
    /**
     * @description Is this user a bot.
     *
     * {@link
     * https://discordapp.com/developers/docs/resources/user#user-object}.
     *
     * @public
     * @type {?boolean}
     * @default
     */
    this.bot = null;
    /**
     * @description Is two factor authentication enabled on this user's account.
     *
     * {@link
     * https://discordapp.com/developers/docs/resources/user#user-object}.
     *
     * @public
     * @type {?boolean}
     * @default
     */
    this.mfaEnabled = null;
    /**
     * @description The user's chosen language option.
     *
     * {@link
     * https://discordapp.com/developers/docs/resources/user#user-object}.
     *
     * @public
     * @type {?string}
     * @default
     */
    this.locale = null;
    /**
     * @description Discord user flags.
     *
     * {@link
     * https://discordapp.com/developers/docs/resources/user#user-object}.
     *
     * @public
     * @type {?number}
     * @default
     */
    this.flags = null;
    /**
     * @description User's Nitro status.
     *
     * {@link
     * https://discordapp.com/developers/docs/resources/user#user-object}.
     *
     * @public
     * @type {?number}
     * @default
     */
    this.premiumType = null;
  }

  /**
   * @description Getter for user ID.
   * @see {@link WebUserData~_id}
   * @public
   * @returns {string} User's ID.
   */
  get id() {
    return this._id;
  }

  /**
   * @description Getter for client IP address.
   * @see {@link WebUserData~_ip}
   * @public
   * @returns {string} Client's IP.
   */
  get ip() {
    return this._ip;
  }

  /**
   * @description Getter for guild list.
   * @see {@link WebUserData~_guilds}
   * @public
   * @returns {null|string[]} Guild ID list.
   */
  get guilds() {
    return this._guilds;
  }

  /**
   * @description Getter for session ID.
   * @see {@link WebUserData~_sessionId}
   * @public
   * @returns {?string} Session ID if it exists.
   */
  get sessionId() {
    return this._sessionId;
  }

  /**
   * @description Setter for session ID and expiration date.
   * @see {@link WebUserData~_sessionId}
   * @see {@link WebUserData~_sessionExpirationDate}
   * @param {?string} sId Session ID or null to unset.
   * @param {?number|Date|string} date Date or timestamp, or null to unset.
   */
  setSession(sId, date) {
    this.setSessionId(sId);
    this.setSessionExpirationDate(date);
  }

  /**
   * @description Setter for session ID.
   * @see {@link WebUserData~_sessionId}
   * @param {?string} sId Session ID or null to unset.
   */
  setSessionId(sId) {
    this._sessionId = sId;
    this._session.id = sId;
  }

  /**
   * @description Getter for session expiration timestamp.
   * @see {@link WebUserData~_sessionExpirationDate}
   * @public
   * @returns {?number} Session expiration timestamp if it exists.
   */
  get sessionExpirationDate() {
    return this._sessionExpirationDate;
  }

  /**
   * @description Setter for session expiration timestamp.
   * @see {@link WebUserData~_sessionExpirationDate}
   * @param {?number|Date|string} sED Date or timestamp, or null to unset.
   */
  setSessionExpirationDate(sED) {
    if (sED === null) {
      this._sessionExpirationDate = null;
    } else {
      this._sessionExpirationDate = new Date(sED).getTime();
    }
    this._session.expiration_date = this._sessionExpirationDate;
  }

  /**
   * @description Set the list of guilds for this user.
   * @see {@link https://discordapp.com/developers/docs/resources/user#get-current-user-guilds}
   * @public
   * @param {object[]} guilds Array of guild data for this user.
   */
  setGuilds(guilds) {
    if (!Array.isArray(guilds) || typeof guilds[0] !== 'object') {
      throw new TypeError('Guild data is not array of guild data.');
    }
    this._guilds = guilds;
  }

  /**
   * @description Get a serializable version of this class instance. Behaves
   * differently than HG serializable getters in that private variables are
   * converted to public instead of being removed. Assumes all variables are
   * serializable if they aren't a function.
   * @public
   * @returns {object} Serializable version of this instance.
   */
  get serializable() {
    const all = Object.entries(Object.getOwnPropertyDescriptors(this));
    const output = {};
    for (const one of all) {
      const name = one[0].replace(/^_/, '');
      if (typeof one[1].value === 'function') {
        continue;
      } else if (one[1].value && one[1].value.serializable) {
        output[name] = one[1].value.serializable;
      } else {
        output[name] = one[1].value;
      }
    }
    return output;
  }

  /**
   * @description Create this object from a Discord User Object response data.
   * @public
   * @static
   * @param {object} obj Object data from Discord.
   * @returns {WebUserData} Created object.
   */
  static from(obj) {
    const out = new WebUserData(obj.id);
    out.username = obj.username || null;
    out.discriminator = obj.discriminator || null;
    out.avatar = obj.avatar || null;
    out.bot = typeof obj.bot === 'boolean' ? obj.bot : null;
    out.mfaEnabled = typeof obj.mfa_enabled === 'boolean' ?
        obj.mfa_enabled :
        (typeof obj.mfaEnabled === 'boolean' ? obj.mfaEnabled : null);
    out.locale = obj.locale || null;
    out.flags = typeof obj.flags === 'number' ? obj.flags : null;
    out.premiumType = typeof obj.premium_type === 'number' ?
        obj.premium_type :
        (typeof obj.premiumType === 'number' ? obj.premiumType : null);
    return out;
  }
}

module.exports = WebUserData;