Source: userinfo.js

'use strict';

const EventEmitter = require('events').EventEmitter;
const inherits = require('util').inherits;

/**
 * @class
 * @classdesc Extended user information
 * @param {String} identity - Identity of user
 * @param {String} uri - uri to user's info object
 * @param {Object} datasync - datasync service
 * @param {Object} session - session service
 *
 * @property {String} identity - User identity
 * @property {String} friendlyName - User friendly name. Null if not set
 * @property {Object} attributes - Object with custom attributes for user
 * @fires UserInfo#updated
 */
function UserInfo(identity, uri, datasync, session) {
  Object.defineProperties(this, {
    _datasync: { value: datasync },
    _session: { value: session },
    _identity: { value: identity },
    _uri: { value: uri, writable: true }, // writable only because of lazy loading of myUserInfo
    _attributes: { value: {}, writable: true },
    _friendlyName: { value: null, writable: true },
    _promiseToFetch: { writable: true },
    identity: { enumerable: true, get: () => this._identity },
    attributes: { enumerable: true, get: () => this._attributes },
    friendlyName: { enumerable: true, get: () => this._friendlyName }
  });

  EventEmitter.call(this);
}

inherits(UserInfo, EventEmitter);

UserInfo.prototype._update = function(key, value) {
  switch (key) {
    case 'friendlyName':
      this._friendlyName = value;
      break;
    case 'attributes':
      try {
        this._attributes = JSON.parse(value);
      } catch (e) {
        this._attributes = {};
      }
      break;
    default:
      return;
  }
  this.emit('updated');
};

UserInfo.prototype._fetch = function() {
  if (!this._uri) {
    return Promise.resolve(this);
  }

  let update = item => this._update(item.id, item.value.value);
  this._promiseToFetch = this._datasync.openMap(this._uri).then(map => {
    map.subscribe();
    map.on('entityUpdated', update);
    return Promise.all([
      map.get('friendlyName').then(update),
      map.get('attributes').then(update)
    ]);
  })
  .then(() => this)
  .catch(err => {
    this._promiseToFetch = null;
    throw err;
  });
  return this._promiseToFetch;
};

UserInfo.prototype._ensureFetched = function() {
  return this._promiseToFetch || this._fetch();
};

/**
 * Update the UserInfo's attributes.
 * @param {Object} attributes - The new attributes object.
 * @returns {Promise<UserInfo|SessionError>} A Promise for the UserInfo
 */
UserInfo.prototype.updateAttributes = function(attributes) {
  if (attributes.constructor !== Object)  {
    throw new Error('Attributes must be an object.');
  }

  return this._session.addCommand('editUserAttributes', {
    username: this._identity,
    attributes: JSON.stringify(attributes)
  }).then(() => this);
};

/**
 * Update the Users's friendlyName.
 * @param {String} name - The new friendlyName.
 * @returns {Promise<UserInfo|SessionError>} A Promise for the UserInfo
 */
UserInfo.prototype.updateFriendlyName = function(friendlyName) {
  return this._session.addCommand('editUserFriendlyName', {
    username: this._identity,
    friendlyName: friendlyName
  }).then(() => this);
};

Object.freeze(UserInfo);

/**
 * Fired when the UserInfo's fields have been updated.
 * @event UserInfo#updated
 */

module.exports = UserInfo;