UNPKG

we-core

Version:

We.js is a node.js framework for build real time applications, sites or blogs!

374 lines (340 loc) 10.9 kB
/** * User * * @module :: Model * @description :: System User model * */ var userNameRegex = /^[A-Za-z0-9_-]{2,30}$/; module.exports = function UserModel(we) { var model = { definition: { username: { type: we.db.Sequelize.STRING, unique: true, validate: { userNameIsValid: function(val) { if (!userNameRegex.test(val)) { throw new Error('user.username.invalid'); } }, uniqueUsername: function(val, cb) { if(!val) return cb(); return we.db.models.user.findOne({ where: { username: val }, attributes: ['id'] }).then(function (u) { if (u) return cb('auth.register.error.username.registered'); cb(); }); } } }, displayName: { type: we.db.Sequelize.STRING }, fullName: { type: we.db.Sequelize.TEXT, formFieldType: 'text' }, biography: { type: we.db.Sequelize.TEXT, formFieldType: 'html', formFieldHeight: 200 }, gender: { type: we.db.Sequelize.STRING, formFieldType: 'select' , fieldOptions: { M: 'Male', F: 'Female' } }, email: { // Email type will get validated by the ORM type: we.db.Sequelize.STRING, allowNull: false, unique: true, formFieldType: 'user-email', validate: { isEmail: true, notEmptyOnCreate: function(val) { if (this.isNewRecord) { if (!val) { throw new Error('auth.register.email.required'); } } }, equalEmailFields: function(val) { if (this.isNewRecord) { if (this.getDataValue('email') != val) { throw new Error('auth.email.and.confirmEmail.diferent'); } } }, uniqueEmail: function(val, cb) { return we.db.models.user.findOne({ where: { email: val }, attributes: ['id'] }).then(function (u) { if (u) return cb('auth.register.email.exists'); cb(); }); } } }, active: { type: we.db.Sequelize.BOOLEAN, defaultValue: false, formFieldType: null }, language: { type: we.db.Sequelize.STRING, defaultValue: 'pt-br', validations: { max: 6 }, formFieldType: null // TODO }, confirmEmail: { type: we.db.Sequelize.VIRTUAL, formFieldType: null, set: function (val) { this.setDataValue('confirmEmail', val); }, validate: { isEmail: true, notEmptyOnCreate: function(val) { if (this.isNewRecord) { if (!val) { throw new Error('auth.register.confirmEmail.required'); } } }, equalEmailFields: function(val) { if (this.isNewRecord) { if (this.getDataValue('email') != val) { throw new Error('auth.email.and.confirmEmail.diferent'); } } } } }, acceptTerms: { type: we.db.Sequelize.BOOLEAN, defaultValue: true, equals: true, allowNull: false, formFieldType: null }, roles: { type: we.db.Sequelize.TEXT, formFieldType: null, skipSanitizer: true, get: function() { if (this.getDataValue('roles')) return JSON.parse( this.getDataValue('roles') ); return []; }, set: function(object) { if (typeof object == 'object') { this.setDataValue('roles', JSON.stringify(object)); } else { throw new Error('invalid error in user roles value: ', object); } } } }, associations: { passports: { type: 'belongsToMany', model: 'passport', inverse: 'user', through: 'users_passports' } }, options: { titleField: 'displayName', termFields: { organization: { vocabularyName: 'Organization', canCreate: true, formFieldMultiple: false, onlyLowercase: false }, }, imageFields: { avatar: { formFieldMultiple: false }, banner: { formFieldMultiple: false } }, // table comment comment: 'We.js users table', classMethods: { validUsername: function(username){ var restrictedUsernames = [ 'logout', 'login', 'auth', 'api', 'admin', 'account', 'user' ]; if (restrictedUsernames.indexOf(username) >= 0) { return false; } return true }, /** * Context loader, preload current request record and related data * * @param {Object} req express.js request * @param {Object} res express.js response * @param {Function} done callback */ contextLoader: function contextLoader(req, res, done) { if (!res.locals.id || !res.locals.loadCurrentRecord) return done(); this.findById(res.locals.id) .then(function (record) { res.locals.data = record; if (record && record.id && req.isAuthenticated()) { // ser role owner if (req.user.id == record.id) if(req.userRoleNames.indexOf('owner') == -1 ) req.userRoleNames.push('owner'); } return done(); }); }, // returns an url alias urlAlias: function urlAlias(record) { return { alias: '/'+ we.i18n.__('user') +'/' + record.id + '-'+ we.utils .string( record.username || record.displayName ).slugify().s, target: '/user/' + record.id, } }, loadPrivacity: function loadPrivacity(record, done) { we.db.models.userPrivacity.findAll({ where: { userId: record.id }, raw: true }).then(function (p) { record.privacity = p; done(); }).catch(done); } }, instanceMethods: { getPassword: function getPassword (){ return we.db.models.password.findOne({ where: { userId: this.id } }); }, verifyPassword: function verifyPassword (password, cb){ return this.getPassword().then( function(passwordObj){ if (!passwordObj) return cb(null, false); passwordObj.validatePassword(password, cb); }); }, updatePassword: function updatePassword (newPassword, cb){ var user = this; return this.getPassword().then( function (password){ if (!password) { // create one password if this user dont have one return we.db.models.password.create({ userId: user.id, password: newPassword }).then(function (password) { return cb(null, password); }) } // update password.password = newPassword; password.save().then(function(r){ cb(null, r) }); }); }, toJSON: function toJSON() { var obj = this.get(); // delete and hide user email delete obj.email; // remove password hash from view delete obj.password; if (!obj.displayName) obj.displayName = obj.username; return obj; }, getRoles: function getRoles() { var self = this; return new we.db.Sequelize .Promise(function getRolesPromisse(resolve){ resolve(self.roles); }); }, setRoles: function setRoles(rolesToSave) { var self = this; return new we.db.Sequelize .Promise(function setRolesPromisse(resolve, reject){ self.roles = rolesToSave; self.save().then(resolve).catch(reject); }); }, addRole: function addRole(role) { if (typeof role == 'object') { role = role.name; } var self = this; return new we.db.Sequelize .Promise(function setRolesPromisse(resolve, reject){ var roles = self.roles; // if this user already have the role, do nothing if (roles.indexOf(role) > -1) return resolve(self); // else add the role and save the user roles.push(role); self.roles = roles; self.save().then(resolve).catch(reject); }); } }, hooks: { beforeValidate: function beforeValidate(user, options, next) { if (user.isNewRecord) { // dont set password on create user.dataValues.password = null; user.dataValues.passwordId = null; } next(null, user); }, // Lifecycle Callbacks beforeCreate: function beforeCreate(user, options, next) { // set default displayName as username if (!user.displayName) { if (user.fullName && user.fullName.trim()) { user.displayName = user.fullName.split(' ')[0]; } else if (user.username) { user.displayName = user.username; } } // never save consumers on create delete user.consumers; // dont allow to set admin and moderator flags delete user.isAdmin; delete user.isModerator; next(null, user); }, beforeUpdate: function beforeUpdate(user, options, next) { // set default displayName as username if (!user.displayName) { if (user.fullName && user.fullName.trim()) { user.displayName = user.fullName.split(' ')[0]; } else if (user.username) { user.displayName = user.username; } } // dont change user acceptTerms in update user.acceptTerms = true; return next(null, user); }, afterFind: function afterFind(record, options, next) { if (!record) return next(); // load privacity to hide user fields in toJSON if (we.utils._.isArray(record)) { we.utils.async.eachSeries(record, function (r, next) { we.db.models.user.loadPrivacity(r, next); }, next); } else { we.db.models.user.loadPrivacity(record, next); } } } } }; return model; };