File: //var/dev/farhangmoaser/web/routes/api/1.0/user.js
/**
* Express endpoints for /user address
* Version: 0.1
* Author: Babak Vandad
*
* Restful api for these addresses:
* GET /user/role
* PUT /user/role
* POST /user/role/:id
* DELETE /user/role/:id
* GET /user/access/actions
* GET /user/access/rebuild
* GET /user/access
* GET /user/access/:role
* GET /user/access/:action
* GET /user/access/:action/:role
* PUT /user/access/:action/:role
* DELETE /user/access/:action/:role
* GET /user/me
* GET /user/:email
* GET /user
* PUT /user
* PUT /user/me
* POST /user/me
* POST /user/:email
* DELETE /user/:email
*/
var express = require('express');
var router = express.Router();
var path = require('path');
var fs = require('fs');
var glob = require('glob');
var md5 = require('md5');
var consts = require(path.join(BASEDIR, 'consts'));
var authHelper = require(path.join(BASEDIR, 'helpers/auth'));
var mailHelper = require(path.join(BASEDIR, 'helpers/mail'));
var UserModel = require(path.join(BASEDIR, 'models/user'));
var UserAccessModel = require(path.join(BASEDIR, 'models/userAccess'));
var UserRoleModel = require(path.join(BASEDIR, 'models/userRole'));
var db = require(path.join(BASEDIR, 'connectors/mysql'));
var authenticate = authHelper.authenticate;
var access = authHelper.access;
/**
* Fail a request by releasing database connection, rollback transaction
* and sending the proper error code and message with 4xx or 5xx status codes.
* @param {object} express response object
* @param {object} db connection
* @param {object} error object from costs.js
* @param {integer} override status code (if you want to send 200 instead of 4xx/5xx)
* @return {function} the function to fail the request.
*/
var fail = function(response, conn, error, status){
return function(err){
if(conn && conn.release)
conn.release();
response.status(status ? status : error.status).json({error: error.code, message: error.message});
};
};
/**
* Sends data to the client, commits transaction and releases the db connection
* @param {object} express response object
* @param {object} db connection
* @param {object} data for the client
*/
var send = function(res, conn, data){
if(conn) conn.release();
if(data) res.json(data);
else res.end();
};
/**
* makes a searchable string (does not remove spaces)
* @param {string} str user input or given entry title
* @return {string} searchable string
*/
var simplifyString = function(str){
return str
.trim()
.toLowerCase()
.replace(/[\t'\-!() ]/g, '')
.replace(/ +/g, ' ')
.replace(/[ًٌٍَُِّْـ.]/g, '')
.replace(/ي/g, 'ی')
.replace(/ى/g, 'ی')
.replace(/ك/g, 'ک')
.replace(/[àâä]/g, 'a')
.replace(/æ/g, 'ae')
.replace(/[îï]/g, 'i')
.replace(/[éèêë]/g, 'e')
.replace(/[ôö]/g, 'o')
.replace(/œ/g, 'oe')
.replace(/[ùûü]/g, 'u')
.replace(/ç/g, 'c')
.replace(/ñ/g, 'n')
.replace(/ÿ/g, 'y')
;
};
/* list all roles */
router.get('/role', authenticate, access('user:role:get', 'نمایش فهرست نقشها'), function(req, res, next){
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
UserRoleModel.list(conn).then(
function(roles){
send(res, conn, {list: roles, sum: roles.length});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* add a new role */
router.put('/role', authenticate, access('user:role:put', 'افزودن نقش'), function(req, res, next){
if(!req.body.title)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
var roletitle = req.body.title;
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
(new UserRoleModel(conn, {title: roletitle})).save().then(
function(role){
send(res, conn, {id: role.field('id'), title: role.field('title')});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* update an existing role */
router.post('/role/:id', authenticate, access('user:role:post', 'ویرایش عنوان نقش'), function(req, res, next){
if(!req.params.id)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
var roleid = parseInt(req.params.id);
if(isNaN(roleid))
return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
var record = {id: roleid};
if(req.body.hasOwnProperty('title'))
record.title = req.body.title;
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
(new UserRoleModel(conn, record)).save().then(
function(user){
send(res, conn, user.fields());
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* delete an existing role */
router.delete('/role/:id', authenticate, access('user:role:delete', 'حذف نقش'), function(req, res, next){
if(!req.params.id)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
if(!req.body.hasOwnProperty('substitute') && !req.query.hasOwnProperty('substitute'))
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
var roleid = parseInt(req.params.id);
if(isNaN(roleid))
return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
if(roleid===consts.v.ROLE_ADMIN) return fail(res, null, consts.e.ERR_DATA_CONFLICT)();
if(roleid===consts.v.ROLE_UNAUTHENTICATED) return fail(res, null, consts.e.ERR_DATA_CONFLICT)();
var record = {id: roleid};
var substituteid = NaN;
if(req.body.hasOwnProperty('substitute'))
var substituteid = parseInt(req.body.substitute);
else if(req.query.hasOwnProperty('substitute'))
var substituteid = parseInt(req.query.substitute);
if(isNaN(substituteid))
return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
UserRoleModel.reRole(conn, roleid, substituteid).then(
function(){
(new UserRoleModel(conn, {id: substituteid})).save().then(
function(){
(new UserRoleModel(conn, {id: roleid})).remove().then(
function(){
send(res, conn, {id: roleid});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* list all actions */
router.get('/access/actions', authenticate, access('user:access:get-actions', 'نمایش فهرست همه کارهایی که نقشهای مختلف میتوانند انجام دهند'), function(req, res, next){
var actions = UserAccessModel.listActions();
send(res, null, {list: actions, sum: actions.length});
});
/* rebuild rules cache */
router.get('/access/rebuild', authenticate, access('user:access:get-rebuild', 'بازسازی cache قواعد دسترسی'), function(req, res, next){
UserAccessModel.rebuild().then(
function(){
var actions = UserAccessModel.listActions();
send(res, null, {list: actions, sum: actions.length});
}, fail(res, null, consts.e.ERR_DB_ERROR));
});
/* list all access rules */
router.get('/access', authenticate, access('user:access:get', 'نمایش فهرست قواعد دسترسی'), function(req, res, next){
UserAccessModel.list(false, false).then(
function(rows){
send(res, null, {list: rows, sum: rows.length});
}, fail(res, null, consts.e.ERR_DB_ERROR));
});
/* list access rules by role */
router.get('/access/:role', authenticate, access('user:access:get-role', 'نمایش فهرست کارهایی که یک نقش میتواند انجام دهد'), function(req, res, next){
if(!/^\d+$/.exec(req.params.role)) return next();
var role = parseInt(req.params.role);
UserAccessModel.list(null, role).then(
function(rows){
send(res, null, {list: rows, sum: rows.length});
}, fail(res, null, consts.e.ERR_DB_ERROR));
});
/* list access rules by action */
router.get('/access/:action', authenticate, access('user:access:get-action', 'نمایش فهرست نقشهایی که میتوانند یک کار را انجام دهند'), function(req, res, next){
var action = req.params.action;
if(!/.*:.*/.exec(action)) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
UserAccessModel.list(action, false).then(
function(rows){
send(res, null, {list: rows, sum: rows.length});
}, fail(res, null, consts.e.ERR_DB_ERROR));
});
/* check an access by (action, role) pair */
router.get('/access/:action/:role', authenticate, access('user:access:get-action-role', 'استعلام امکان انجام یک کار مشخص توسط یک نقش مشخص'), function(req, res, next){
var action = req.params.action;
var role = parseInt(req.params.role);
if(isNaN(role)) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
if(!/.*:.*/.exec(action)) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
if(role===1) return send(res, null, {result: true});
UserAccessModel.check(action, role).then(
function(permits){
send(res, null, {result: permits});
}, fail(res, null, consts.e.ERR_DB_ERROR));
});
/* add an access rule */
router.put('/access/:action/:role', authenticate, access('user:access:put-action-role', 'صدور مجوز انجام یک کار مشخص برای یک نقش مشخص'), function(req, res, next){
var action = req.params.action;
var role = parseInt(req.params.role);
if(isNaN(role)) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
if(!/.*:.*/.exec(action)) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
if(role===1) return fail(res, null, consts.e.ERR_DATA_CONFLICT)();
(new UserAccessModel({action: action, role: role})).save().then(
function(){
send(res, null, {action: action, role: role});
}, fail(res, null, consts.e.ERR_DB_ERROR));
});
/* delete an access rule */
router.delete('/access/:action/:role', authenticate, access('user:access:delete-action-role', 'منع انجام یک کار مشخص برای یک نقش مشخص'), function(req, res, next){
var action = req.params.action;
var role = parseInt(req.params.role);
if(isNaN(role)) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
if(!/.*:.*/.exec(action)) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
if(role===1) return fail(res, null, consts.e.ERR_DATA_CONFLICT)();
(new UserAccessModel({action: action, role: role})).remove().then(
function(){
send(res, null, {action: action, role: role});
}, fail(res, null, consts.e.ERR_DB_ERROR));
});
/* user gets his/her own data */
router.get('/me', authenticate, access('user:get-me', 'کاربر اطلاعات خودش را مشاهده کند'), function(req, res, next){
if(!req.user || !req.isAuthenticated()) return fail(res, null, consts.e.ERR_AUTH)();
var userData = req.user.fields();
delete userData.id;
if(userData.userType == consts.v.USER_TYPE_PEOPLE)
delete userData.key;
delete userData.searchable;
delete userData.sortable;
delete userData.password;
send(res, null, req.user.fields());
});
/* load user by email */
router.get('/:email', authenticate, access('user:get-email', 'مشاهده اطلاعات یک کاربر'), function(req, res, next){
if(!req.params.email)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
var userModel = new UserModel(conn, {email: req.params.email});
userModel.load().then(
function(user) {
if(!user) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
var userData = user.fields();
delete userData.id;
delete userData.password;
userData.hitData = user.hitData;
send(res, conn, userData);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* reset user's hit counter */
router.get('/:email/reset-hits', authenticate, access('user:reset-hits', 'بازنشانی شمارنده بازدیدها'), function(req, res, next){
if(!req.params.email)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection((err, conn) => {
if(err) return fail(res, conn, err)();
var userModel = new UserModel(conn, {email: req.params.email});
userModel.load().then(
user => {
if(!user) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
user.resetHitCounter().then(
() => {
let userData = user.fields();
delete userData.id;
delete userData.password;
userData.hitData = user.hitData;
send(res, conn, userData);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* list users */
router.get('/', authenticate, access('user:get', 'نمایش فهرست کاربران'), function(req, res, next){
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
var query = {};
if(req.query.hasOwnProperty('email')) query.email = req.query.email.toLowerCase();
if(req.query.hasOwnProperty('minDate')) query['>=created'] = parseInt(req.query.minDate);
if(req.query.hasOwnProperty('maxDate')) query['<=created'] = parseInt(req.query.maxDate);
if(req.query.hasOwnProperty('state')) query.state = parseInt(req.query.state);
if(req.query.hasOwnProperty('role')) query.role = parseInt(req.query.role);
if(req.query.hasOwnProperty('userType')) query.userType = parseInt(req.query.userType);
// TODO: support quota full
// if(req.query.hasOwnProperty('quotaFull'))
if(req.query.hasOwnProperty('displayname'))
query['%%searchable'] = '%'+simplifyString(req.query.displayname)+'%';
if(req.query.hasOwnProperty('email') && (/^%/.exec(req.query.email) || /%$/.exec(req.query.email))){
delete query.email;
query['%%email'] = simplifyString(req.query.email);
}
var limit = req.query.hasOwnProperty('limit') ? Math.min(100, parseInt(req.query.limit)) : 100;
var page = req.query.hasOwnProperty('page') ? parseInt(req.query.page) : 0;
var offset = page*limit;
// list of records based on criteria
var listQuery = function(records) {
records.map(function(record){
delete record.id;
});
var response = [];
return UserModel.count(conn, query).then(
function(sum) {
send(res, conn, {sum: sum, list: records});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
};
UserModel.list(conn, query, limit, offset, req.query.orderBy).then(
listQuery, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* add a new user */
router.put('/', authenticate, access('user:put', 'افزودن کاربر'), function(req, res, next) {
if(!req.body.email || !req.body.role)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
var data = {
email: req.body.email.toLowerCase(),
displayname: '',
searchable: '',
sortable: ''
};
if(req.body.key) data.key = parseInt(req.body.key);
if(req.body.displayname) data.displayname = req.body.displayname;
else if(req.body.firstname || req.body.lastname) data.displayname = (req.body.firstname + ' ' + req.body.lastname).trim();
data.searchable = simplifyString(data.displayname);
if(req.body.sortable) data.sortable = req.body.sortable;
else if(req.body.firstname || req.body.lastname) data.sortable = simplifyString(req.body.lastname + ' ' + req.body.firstname);
if(req.body.userType) data.userType = parseInt(req.body.userType);
if(req.body.role) data.role = parseInt(req.body.role);
if(req.body.firstname) data.firstname = req.body.firstname;
if(req.body.lastname) data.lastname = req.body.lastname;
if(req.body.gender) data.gender = parseInt(req.body.gender);
if(req.body.password) data.password = md5(req.body.password);
if(req.body.avatar) data.avatar = req.body.avatar;
if(req.body.hitCount) data.hitCount = parseInt(req.body.hitCount);
if(req.body.hitLimit) data.hitLimit = parseInt(req.body.hitLimit);
if(req.body.hitPeriod) data.hitPeriod = parseInt(req.body.hitPeriod);
if(req.body.state) data.state = parseInt(req.body.state);
if(data.role && data.role==consts.v.ROLE_UNAUTHENTICATED) return fail(res, null, consts.e.ERR_DATA_CONFLICT)();
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
var addUser = function(){
(new UserModel(conn, {email: data.email})).load().then(
function(duplicateUser) {
if(duplicateUser) return fail(res, conn, consts.e.ERR_DUPLICATE_RECORD)();
var userModel = new UserModel(conn, data);
userModel.save().then(
function(user) {
(new UserRoleModel(conn, {id: user.field('role')})).save().then(
function(){
var userData = user.fields();
delete userData.id;
userData.hitData = user.hitData;
send(res, conn, userData);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
};
if(req.body.avatar)
fs.rename(path.join(BASEDIR, 'private/temp/'+req.body.avatar), path.join(BASEDIR, 'private/avatar/'+req.body.avatar), addUser);
else
addUser();
});
});
/* user creates an account. (no authentication needed) */
router.put('/me', authenticate, access('user:put-me', 'عضویت کاربر ناشناس'), function(req, res, next) {
if(!req.body.email || !req.body.password)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
if(!/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.exec(req.body.email))
return fail(res, null, consts.e.ERR_MALFORMED_REQUEST);
var data = {
email: req.body.email.toLowerCase(),
displayname: '',
searchable: '',
sortable: '',
userType: consts.v.USER_TYPE_PEOPLE,
role: consts.v.ROLE_SERVICE_USER,
state: consts.v.STATE_INACTIVE,
hitCount: 0,
hitLimit: 300,
hitPeriod: 1
};
req.body.firstname = (req.body.firstname || '').trim();
req.body.lastname = (req.body.lastname || '').trim();
data.displayname = req.body.firstname + ' ' + req.body.lastname
data.searchable = simplifyString(data.displayname);
data.sortable = simplifyString(req.body.lastname + ' ' + req.body.firstname);
if(req.body.firstname) data.firstname = req.body.firstname;
if(req.body.lastname) data.lastname = req.body.lastname;
if(req.body.gender) data.gender = parseInt(req.body.gender);
if(req.body.password) data.password = md5(req.body.password);
db.getConnection(function(err, conn){
if(err) return fail(res, conn, consts.e.ERR_DB_ERROR)();
var addUser = function(){
(new UserModel(conn, {email: data.email})).load().then(
function(duplicateUser) {
if(duplicateUser) return fail(res, conn, consts.e.ERR_DUPLICATE_RECORD)();
var userModel = new UserModel(conn, data);
userModel.generateActivationKey();
userModel.save().then(
function(user) {
(new UserRoleModel(conn, {id: user.field('role')})).save().then(
function(){
var userData = user.fields();
mailHelper.sendActivationEMail(user).then(
info => {
// console.log(info);
},
error => {
// console.log('mail error', error);//log this
}
);
delete userData.id;
delete userData.password;
delete userData.hitLimit;
delete userData.hitPeriod;
delete userData.hitCount;
delete userData.activationKey;
send(res, conn, userData);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
};
addUser();
});
});
/* request user activation mail */
router.get('/me/reset-password/:email', authenticate, access('user:reset-pass-me', 'کاربر ایمیل تغییر پسورد درخواست کند'), function(req, res, next) {
if(!/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.exec(req.params.email))
return fail(res, null, consts.e.ERR_MALFORMED_REQUEST);
db.getConnection(function(err, conn){
if(err) return fail(res, conn, consts.e.ERR_DB_ERROR)();
var user = new UserModel(conn, {email: req.params.email});
user.load().then(
user => {
if(!user)
return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
user.generateActivationKey();
user.save().then(
() => {
mailHelper.sendResetPasswordEMail(user).then(
info => {
// console.log(info);
},
error => {
// console.log('mail error', error);//log this
}
);
send(res, conn, {});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* reset user's password */
router.post('/me/reset-password/:key', authenticate, access('user:reset-pass-me', 'کاربر ایمیل تغییر پسورد درخواست کند'), function(req, res, next) {
if(!req.body.password)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection(function(err, conn){
if(err) return fail(res, conn, consts.e.ERR_DB_ERROR)();
var user = new UserModel(conn, {activationKey: req.params.key});
user.load().then(
user => {
if(!user) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
if(user.field('state') != consts.v.STATE_ACTIVE)
return fail(res, conn, consts.e.ERR_ACCESS_PERMISSION)();
user.field('password', md5(req.body.password));
user.generateActivationKey(); // just to change the previously used key
user.save().then(
function(){
var userData = user.fields();
delete userData.id;
delete userData.password;
delete userData.hitLimit;
delete userData.hitPeriod;
delete userData.hitCount;
delete userData.activationKey;
send(res, conn, userData);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* user updates his/her own data */
router.post('/me', authenticate, access('user:post', 'کاربر اطلاعات خودش را ویرایش کند'), function(req, res, next) {
if(!req.user) fail(res, null, consts.e.ERR_AUTH)();
var user = req.user;
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
var displaynameFlag = (req.body.hasOwnProperty('displayname') && req.body.displayname) || (user.field('displayname') != user.field('firstname') + ' ' + user.field('lastname'));
if(req.body.hasOwnProperty('gender')) user.field('gender', parseInt(req.body.gender));
if(req.body.hasOwnProperty('password')) user.field('password', md5(req.body.password));
if(req.body.hasOwnProperty('avatar')) user.field('avatar', req.body.avatar);
if(req.body.hasOwnProperty('displayname')) user.field('displayname', req.body.displayname);
if(req.body.hasOwnProperty('firstname')) user.field('firstname', req.body.firstname);
if(req.body.hasOwnProperty('lastname')) user.field('lastname', req.body.lastname);
/* hitCount and timestamp fields are not editable */
var manageAvatar = function(callback){
var finishup = function(){
user.field('avatar', req.body.avatar);
callback();
};
var deletePreviousAvatar = function() {
if(user.field('avatar'))
glob(path.join(BASEDIR, 'private/avatar/'+user.field('avatar')+'*'), {}, function(err, files){
if(err) return finishup();
files.forEach(function(file){
fs.unlinkSync(file);
});
finishup();
});
else finishup();
};
if(req.body.hasOwnProperty('avatar') && req.body.avatar!=user.field('avatar')) {
if(req.body.avatar)
fs.rename(path.join(BASEDIR, 'private/temp/'+req.body.avatar), path.join(BASEDIR, 'private/avatar/'+req.body.avatar), deletePreviousAvatar);
else
deletePreviousAvatar();
}else callback();
};
if(displaynameFlag) {
user.field('searchable', simplifyString(user.field('displayname')));
user.field('sortable', simplifyString(user.field('displayname')));
}else {
user.field('displayname', user.field('firstname') + ' ' + user.field('lastname'))
user.field('searchable', simplifyString(user.field('displayname')));
user.field('sortable', simplifyString(user.field('lastname') + ' ' + user.field('firstname')));
}
manageAvatar(function(){
user.save().then(
function(){
var userData = user.fields();
delete userData.id;
if(userData.userType == consts.v.USER_TYPE_PEOPLE)
delete userData.key;
delete userData.searchable;
delete userData.sortable;
delete userData.password;
send(res, conn, userData);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
});
/* update an existing user */
router.post('/:email', authenticate, access('user:post', 'ویرایش اطلاعات کاربر'), function(req, res, next) {
if(!req.params.email)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
(new UserModel(conn, {email: req.params.email.toLowerCase()})).load().then(
function(user) {
if(!user) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
var prevrole = user.field('role');
var displaynameFlag = (req.body.hasOwnProperty('displayname') && req.body.displayname) || (user.field('displayname') != user.field('firstname') + ' ' + user.field('lastname'));
if(req.body.hasOwnProperty('key')) user.field('key', parseInt(req.body.key));
if(req.body.hasOwnProperty('userType')) user.field('userType', parseInt(req.body.userType));
if(req.body.hasOwnProperty('role')) user.field('role', parseInt(req.body.role));
if(req.body.hasOwnProperty('gender')) user.field('gender', parseInt(req.body.gender));
if(req.body.hasOwnProperty('password')) user.field('password', md5(req.body.password));
if(req.body.hasOwnProperty('hitCount')) user.field('hitCount', parseInt(req.body.hitCount)); // e.g. to reset the counter.
if(req.body.hasOwnProperty('hitLimit')) user.field('hitLimit', parseInt(req.body.hitLimit));
if(req.body.hasOwnProperty('hitPeriod')) user.field('hitPeriod', parseInt(req.body.hitPeriod));
if(req.body.hasOwnProperty('state')) user.field('state', parseInt(req.body.state));
if(req.body.hasOwnProperty('displayname')) user.field('displayname', req.body.displayname);
if(req.body.hasOwnProperty('firstname')) user.field('firstname', req.body.firstname);
if(req.body.hasOwnProperty('lastname')) user.field('lastname', req.body.lastname);
/* hitCount and timestamp fields are not editable */
if(user.field('role') && user.field('role')==consts.v.ROLE_UNAUTHENTICATED) return fail(res, conn, consts.e.ERR_DATA_CONFLICT)();
var manageAvatar = function(callback){
var finishup = function(){
user.field('avatar', req.body.avatar);
callback();
};
var deletePreviousAvatar = function() {
if(user.field('avatar'))
glob(path.join(BASEDIR, 'private/avatar/'+user.field('avatar')+'*'), {}, function(err, files){
if(err) return finishup();
files.forEach(function(file){
fs.unlinkSync(file);
});
finishup();
});
else finishup();
};
if(req.body.hasOwnProperty('avatar') && req.body.avatar!=user.field('avatar')) {
if(req.body.avatar)
fs.rename(path.join(BASEDIR, 'private/temp/'+req.body.avatar), path.join(BASEDIR, 'private/avatar/'+req.body.avatar), deletePreviousAvatar);
else
deletePreviousAvatar();
}else callback();
};
if(displaynameFlag) {
user.field('searchable', simplifyString(user.field('displayname')));
user.field('sortable', simplifyString(user.field('displayname')));
}else {
user.field('displayname', user.field('firstname') + ' ' + user.field('lastname'))
user.field('searchable', simplifyString(user.field('displayname')));
user.field('sortable', simplifyString(user.field('lastname') + ' ' + user.field('firstname')));
}
manageAvatar(function(){
user.save().then(
function(){
var userData = user.fields();
delete userData.id;
userData.hitData = user.hitData;
if(prevrole!=user.field('role'))
(new UserRoleModel(conn, {id: user.field('role')})).save().then(
function(){
(new UserRoleModel(conn, {id: prevrole})).save().then(
function(){
send(res, conn, userData);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
else
send(res, conn, userData);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* delete an user */
router.delete('/:email', authenticate, access('user:delete', 'حذف کاربر'), function(req, res, next) {
if(!req.params.email)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
(new UserModel(conn, {email: req.params.email})).load().then(
function(user) {
if(!user) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
user.delete().then(
function(user){
(new UserRoleModel(conn, {id: user.field('role')})).save().then(
function(){
send(res, conn, {email: user.field('email')});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
module.exports = router;