/**
* The User module
* @module user
* @copyright CHECKROOM NV 2015
*/
define([
'jquery',
'base',
'common'], /** @lends User */ function ($, Base, common) {
var DEFAULTS = {
name: '',
email: '',
group: '', // groupid
picture: '',
role: 'user', // user, admin
active: true,
isOwner: false,
archived: null,
restrictLocations: []
};
// Allow overriding the ctor during inheritance
// http://stackoverflow.com/questions/4152931/javascript-inheritance-call-super-constructor-or-use-prototype-chain
var tmp = function() {};
tmp.prototype = Base.prototype;
/**
* @name User
* @class User
* @constructor
* @extends Base
* @property {string} name - The name
* @property {string} role - The role (admin, user)
* @property {boolean} active - Is the user active?
*/
var User = function(opt) {
var spec = $.extend({
_fields: ['*', 'group', 'picture']
}, opt);
Base.call(this, spec);
this.helper = spec.helper;
this.name = spec.name || DEFAULTS.name;
this.picture = spec.picture || DEFAULTS.picture;
this.email = spec.email || DEFAULTS.email;
this.role = spec.role || DEFAULTS.role;
this.group = spec.group || DEFAULTS.group;
this.active = (spec.active!=null) ? spec.active : DEFAULTS.active;
this.isOwner = (spec.isOwner!=null) ? spec.isOwner : DEFAULTS.isOwner;
this.archived = spec.archived || DEFAULTS.archived;
this.restrictLocations = spec.restrictLocations?spec.restrictLocations.slice():DEFAULTS.restrictLocations.slice();
this.dsAnonymous = spec.dsAnonymous;
};
User.prototype = new tmp();
User.prototype.constructor = User;
//
// Document overrides
//
User.prototype.isValidName = function() {
this.name = $.trim(this.name);
return (this.name.length>=4);
};
User.prototype.isValidEmail = function() {
this.email = $.trim(this.email);
return common.isValidEmail(this.email);
};
User.prototype.isValidRole = function() {
switch(this.role) {
case "user":
case "admin":
case "root":
case "selfservice":
return true;
default:
return false;
}
};
User.prototype.emailExists = function() {
if (this.isValidEmail()) {
// Don't check for emailExists for exisiting user
if(this.id != null && this.email == this.raw.email){
return $.Deferred().resolve(false);
}
return this.dsAnonymous.call('emailExists', {email: this.email})
.then(function(resp) {
return resp.result;
});
} else {
return $.Deferred().resolve(false);
}
};
User.prototype.isValidPassword = function() {
this.password = $.trim(this.password);
return common.isValidPassword(this.password);
};
/**
* Checks if the user is valid
* @returns {boolean}
*/
User.prototype.isValid = function() {
return (
this.isValidName() &&
this.isValidEmail() &&
this.isValidRole());
};
/**
* Checks if the user is empty
* @method
* @name User#isEmpty
* @returns {boolean}
*/
User.prototype.isEmpty = function() {
// We check: name, role
return (
(Base.prototype.isEmpty.call(this)) &&
(this.name==DEFAULTS.name) &&
(this.email==DEFAULTS.email) &&
(this.role==DEFAULTS.role) &&
(this.restrictLocations && this.restrictLocations.length == 0));
};
User.prototype._isDirtyInfo = function(){
if((this.raw)) {
var name = this.raw.name || DEFAULTS.name;
var role = this.raw.role || DEFAULTS.role;
var email = this.raw.email || DEFAULTS.email;
var active = (this.raw.active!=null) ? this.raw.active : DEFAULTS.active;
return (
(this.name!=name) ||
(this.email!=email) ||
(this.role!=role) ||
(this.active!=active)
);
}
return false;
};
User.prototype._isDirtyRestrictLocations = function(){
if((this.raw)) {
var that = this,
restrictLocations = this.raw.restrictLocations || DEFAULTS.restrictLocations;
// Check if other locations have been selected
return this.restrictLocations.filter(function(x){ return restrictLocations.indexOf(x) < 0; }).length > 0 ||
restrictLocations.filter(function(x){ return that.restrictLocations.indexOf(x) < 0; }).length > 0;
}
return false;
};
/**
* Checks if the user is dirty and needs saving
* @method
* @name User#isDirty
* @returns {boolean}
*/
User.prototype.isDirty = function() {
var isDirty = Base.prototype.isDirty.call(this);
return isDirty || this._isDirtyInfo() || this._isDirtyRestrictLocations();
};
/**
* Gets a url for a user avatar
* 'XS': (64, 64),
* 'S': (128, 128),
* 'M': (256, 256),
* 'L': (512, 512)
* @param size {string} default null is original size
* @param bustCache {boolean}
* @returns {string}
*/
User.prototype.getImageUrl = function(size, bustCache) {
return (
(this.picture!=null) &&
(this.picture.length>0)) ?
this.helper.getImageCDNUrl(this.group, this.picture, size, bustCache) :
this.helper.getImageUrl(this.ds, this.id, size, bustCache);
};
User.prototype._getDefaults = function() {
return DEFAULTS;
};
// OVERRIDE BASE: addKeyValue not implemented
User.prototype.addKeyValue = function(key, value, kind, skipRead) {
return $.Deferred().reject("Not implemented for User, use setPicture instead?");
};
// OVERRIDE BASE: addKeyValue not implemented
User.prototype.addKeyValue = function(id, key, value, kind, skipRead) {
return $.Deferred().reject("Not implemented for User, use setPicture instead?");
};
// OVERRIDE BASE: removeKeyValue not implemented
User.prototype.removeKeyValue = function(id, skipRead) {
return $.Deferred().reject("Not implemented for User, use clearPicture instead?");
};
User.prototype.setPicture = function(attachmentId, skipRead) {
if (!this.existsInDb()) {
return $.Deferred().reject("User does not exist in database");
}
this.picture = attachmentId;
return this._doApiCall({
method: 'setPicture',
params: {attachment: attachmentId},
skipRead: skipRead
});
};
User.prototype.clearPicture = function(skipRead) {
if (!this.existsInDb()) {
return $.Deferred().reject("User does not exist in database");
}
return this._doApiCall({
method: 'clearPicture',
skipRead: skipRead
});
};
//
// Business logic
//
/**
* Checks if a user can be activated
* @returns {boolean}
*/
User.prototype.canActivate = function() {
return (!this.active) && (this.archived==null);
};
/**
* Checks if a user can be deactivated
* @returns {boolean}
*/
User.prototype.canDeactivate = function() {
// TODO: We should also check if we're not deactivating the last or only user
return (this.active) && (this.archived==null) && (!this.isOwner);
};
/**
* Checks if a user can be archived
* @returns {boolean}
*/
User.prototype.canArchive = function() {
// TODO: We should also check if we're not deactivating the last or only user
return (this.archived==null) && (!this.isOwner);
};
/**
* Checks if a user can be unarchived
* @returns {boolean}
*/
User.prototype.canUndoArchive = function() {
return (this.archived!=null);
};
/**
* Checks if a user can be owner
* @returns {boolean}
*/
User.prototype.canBeOwner = function() {
return (this.archived==null) && (this.active) && (!this.isOwner) && (this.role=="admin");
};
/**
* Activates a user
* @param skipRead
* @returns {promise}
*/
User.prototype.activate = function(skipRead) {
if (!this.existsInDb()) {
return $.Deferred().reject("User does not exist in database");
}
return this._doApiCall({method: 'activate', skipRead: skipRead});
};
/**
* Deactivates a user
* @param skipRead
* @returns {promise}
*/
User.prototype.deactivate = function(skipRead) {
if (!this.existsInDb()) {
return $.Deferred().reject("User does not exist in database");
}
return this._doApiCall({method: 'deactivate', skipRead: skipRead});
};
/**
* Archives a user
* @param skipRead
* @returns {promise}
*/
User.prototype.archive = function(skipRead) {
if (!this.existsInDb()) {
return $.Deferred().reject("User does not exist in database");
}
return this._doApiCall({method: 'archive', skipRead: skipRead});
};
/**
* Unarchives a user
* @param skipRead
* @returns {promise}
*/
User.prototype.undoArchive = function(skipRead) {
if (!this.existsInDb()) {
return $.Deferred().reject("User does not exist in database");
}
return this._doApiCall({method: 'undoArchive', skipRead: skipRead});
};
/**
* Restrict user access to specific location(s)
* @param locations
* @param skipRead
* @returns {promise}
*/
User.prototype.setRestrictLocations = function(locations, skipRead) {
if (!this.existsInDb()) {
return $.Deferred().reject("User does not exist in database");
}
return this._doApiCall({method: 'setRestrictLocations', params: { restrictLocations: locations }, skipRead: skipRead});
};
/**
* Clear user location(s) access (makes all location accessible for the user)
* @param skipRead
* @returns {promise}
*/
User.prototype.clearRestrictLocations = function(skipRead) {
if (!this.existsInDb()) {
return $.Deferred().reject("User does not exist in database");
}
return this._doApiCall({method: 'clearRestrictLocations', skipRead: skipRead});
};
/**
* Updates the user
* @param skipRead
* @returns {*}
*/
User.prototype.update = function(skipRead) {
if (this.isEmpty()) {
return $.Deferred().reject(new Error("Cannot update to empty user"));
}
if (!this.existsInDb()) {
return $.Deferred().reject(new Error("Cannot update user without id"));
}
if (!this.isValid()) {
return $.Deferred().reject(new Error("Cannot update, invalid user"));
}
var that = this,
dfdRestrictLocations = $.Deferred(),
dfdInfo = $.Deferred();
if(this._isDirtyInfo()){
dfdInfo = this.ds.update(this.id, this._toJson(), this._fields);
}else{
dfdInfo.resolve();
}
if(this._isDirtyRestrictLocations()){
if(this.restrictLocations.length != 0){
dfdRestrictLocations = this.setRestrictLocations(this.restrictLocations, true);
} else{
dfdRestrictLocations = this.clearRestrictLocations(true);
}
}else{
dfdRestrictLocations.resolve();
}
return $.when(dfdInfo, dfdRestrictLocations);
};
/**
* Writes the user to a json object
* @param options
* @returns {object}
* @private
*/
User.prototype._toJson = function(options) {
var data = Base.prototype._toJson.call(this, options);
data.name = this.name || DEFAULTS.name;
data.email = this.email || DEFAULTS.email;
data.group = this.group || DEFAULTS.group;
data.role = this.role || DEFAULTS.role;
return data;
};
/**
* Reads the user from the json object
* @param data
* @param options
* @returns {promise}
* @private
*/
User.prototype._fromJson = function(data, options) {
var that = this;
return Base.prototype._fromJson.call(this, data, options)
.then(function() {
// Read the group id from group or group._id
// depending on the fields
that.group = ((data.group) && (data.group._id!=null)) ? data.group._id : (data.group || DEFAULTS.group);
that.name = data.name || DEFAULTS.name;
that.picture = data.picture || DEFAULTS.picture;
that.email = data.email || DEFAULTS.email;
that.role = data.role || DEFAULTS.role;
that.active = (data.active!=null) ? data.active : DEFAULTS.active;
that.isOwner = (data.isOwner!=null) ? data.isOwner : DEFAULTS.isOwner;
that.archived = data.archived || DEFAULTS.archived;
that.restrictLocations = data.restrictLocations?data.restrictLocations.slice():DEFAULTS.restrictLocations.slice();
$.publish('user.fromJson', data);
return data;
});
};
return User;
});