UNPKG

linagora-rse

Version:
497 lines (419 loc) 12.7 kB
'use strict'; const Q = require('q'); const userModule = require('../../core').user; const imageModule = require('../../core').image; const logger = require('../../core').logger; const ObjectId = require('mongoose').Types.ObjectId; const denormalizeUser = require('../denormalize/user').denormalize; const userSearch = require('../../core/user/search'); module.exports = { getProfileAvatar, getTargetUserAvatar, getProfilesByQuery, logmein, logout, postProfileAvatar, profile, updatePassword, updateProfile, updateTargetUserAvatar, updateTargetUserProfile, updateStates, user }; /** * Log the user in. The user should already be loaded in the request from a middleware. */ function logmein(req, res) { if (!req.user || !req.user.emails || !req.user.emails.length) { return res.status(500).send('User not set'); } return res.redirect('/'); } /** * Logout the current user * * @param {request} req * @param {response} res */ function logout(req, res) { req.logout(); res.redirect('/'); } /** * Get a user profile. * * @param {request} req * @param {response} res */ function profile(req, res) { var uuid = req.params.uuid; const denormalizeOptions = { includeIsFollowing: true, includeFollow: true, includePrivateData: String(req.user._id) === uuid, user: req.user }; if (!uuid) { return res.status(400).json({error: {code: 400, message: 'Bad parameters', details: 'User ID is missing'}}); } userModule.get(uuid, function(err, user) { if (err) { return res.status(500).json({ error: 500, message: 'Error while loading user ' + uuid, details: err.message }); } if (!user) { return res.status(404).json({ error: 404, message: 'User not found', details: 'User ' + uuid + ' has not been found' }); } denormalizeUser(user, denormalizeOptions) .then(denormalized => res.status(200).json(denormalized)); }); } /** * Get users profile. * * @param {request} req * @param {response} res */ function getProfilesByQuery(req, res) { let getUsers; let errorMessage; if (req.query.email) { const email = req.query.email; errorMessage = `Error while finding users by email ${email}`; getUsers = _findUsersByEmail(email); } else { const options = { search: req.query.search, limit: req.query.limit, offset: req.query.offset, not_in_collaboration: req.query.not_in_collaboration }; errorMessage = 'Error while searching users'; getUsers = Q.ninvoke(userSearch, 'search', options); } const denormalizeUsers = users => users.map(user => denormalizeUser(user, { user: req.user })); getUsers .then(result => Q.all(denormalizeUsers(result.list)) .then(denormalizedUsers => { res.header('X-ESN-Items-Count', result.total_count); res.status(200).json(denormalizedUsers); })) .catch(err => { logger.error(errorMessage, err); res.status(500).json({ error: 500, message: 'Server Error', details: errorMessage }); }); } /** * Update a parameter value in the current user profile * * @param {Request} req * @param {Response} res */ function updateProfile(req, res) { if (!req.user) { return res.status(404).json({error: 404, message: 'Not found', details: 'User not found'}); } if (!req.body) { return res.status(400).json({error: 400, message: 'Bad Request', details: 'No value defined'}); } Q.denodeify(userModule.updateProfile)(req.user, _buildNewProfile(req.body)) .then(updatedUser => denormalizeUser(updatedUser)) .then(denormalizedUser => res.status(200).json(denormalizedUser)) .catch(err => { const details = `Error while updating profile of user ${req.user.id}`; logger.error(details, err); res.status(500).json({ error: { code: 500, message: 'Server Error', details } }); }); } function updateTargetUserAvatar(req, res) { // assign our domain object to "domain" property of request object (by load domain middleware) // causes error "domain.enter is not a function" when process data stream (imageModule.recordAvatar function) on nodejs 8. // The reason is request object is an instance of EventEmitter that uses domain module to handle IO errors. // However, the domain module is deprecated (https://nodejs.org/api/domain.html) // Note: it does not cause error on nodejs 9.11.2 delete req.domain; const avatarId = new ObjectId(); Q.denodeify(imageModule.recordAvatar)( avatarId, req.query.mimetype.toLowerCase(), { creator: { objectType: 'user', id: req.targetUser._id } }, req ) .then(storedBytes => { const size = parseInt(req.query.size, 10); if (storedBytes !== size) { return res.status(412).json({ error: { code: 412, message: 'Precondition Failed', details: `Avatar size given by user agent is ${size} and avatar size returned by storage system is ${storedBytes}` } }); } const targetUser = req.targetUser; targetUser.avatars.push(avatarId); targetUser.currentAvatar = avatarId; return Q.denodeify(userModule.update)(targetUser); }) .then(() => res.status(200).json({ _id: avatarId })) .catch(err => { let details = 'Error while updating user avatar'; switch (err.code) { case 1: details = `${details}: failed to store avatar`; break; case 2: details = `${details}: failed to process avatar`; } logger.error(details, err); res.status(500).json({ error: { code: 500, message: 'Server Error', details: details } }); }); } /** * Update profile of a specific user {req.targetUser}. * * @param {Request} req - Request object contains targetUser * @param {Response} res - Response object */ function updateTargetUserProfile(req, res) { if (!req.body) { return res.status(400).json({ error: { code: 400, message: 'Bad Request', details: 'No value defined' } }); } Q.denodeify(userModule.updateProfile)(req.targetUser, _buildNewProfile(req.body)) .then(updatedUser => denormalizeUser(updatedUser)) .then(denormalizedUser => res.status(200).json(denormalizedUser)) .catch(err => { const details = `Error while updating profile of user ${req.targetUser.id}`; logger.error(details, err); res.status(500).json({ error: { code: 500, message: 'Server Error', details } }); }); } function _buildNewProfile(data) { return { firstname: data.firstname || '', lastname: data.lastname || '', job_title: data.job_title || '', service: data.service || '', building_location: data.building_location || '', office_location: data.office_location || '', main_phone: data.main_phone || '', description: data.description || '' }; } /** * Update the password in the current user profile * * @param {Request} req * @param {Response} res */ function updatePassword(req, res) { if (!req.body && !req.body.password) { return res.status(400).json({error: 400, message: 'Bad Request', details: 'No password defined'}); } userModule.updatePassword(req.user, req.body.password, function(err) { if (err) { return res.status(500).json({error: 500, message: 'Server Error', details: err.message}); } return res.status(200).end(); }); } /** * Returns the current authenticated user * * @param {Request} req * @param {Response} res */ function user(req, res) { if (!req.user) { return res.status(404).json({error: 404, message: 'Not found', details: 'User not found'}); } const denormalizeOption = { includeConfigurations: true, includePrivateData: true, includeIsPlatformAdmin: true, includeIsFollowing: true, includeFollow: true }; denormalizeUser(req.user, denormalizeOption).then(denormalized => res.status(200).json(denormalized)); } function postProfileAvatar(req, res) { const avatarId = new ObjectId(); Q.denodeify(imageModule.recordAvatar)( avatarId, req.query.mimetype.toLowerCase(), { creator: { objectType: 'user', id: req.user._id } }, req ) .then(storedBytes => { const size = parseInt(req.query.size, 10); if (storedBytes !== size) { return res.status(412).json({ error: { code: 412, message: 'Precondition Failed', details: `Avatar size given by user agent is ${size} and avatar size returned by storage system is ${storedBytes}` } }); } const user = req.user; user.avatars.push(avatarId); user.currentAvatar = avatarId; return Q.denodeify(userModule.update)(user); }) .then(() => res.status(200).json({ _id: avatarId })) .catch(err => { let details = 'Error while updating user avatar'; switch (err.code) { case 1: details = `${details}: failed to store avatar`; break; case 2: details = `${details}: failed to process avatar`; } logger.error(details, err); res.status(500).json({ error: { code: 500, message: 'Server Error', details: details } }); }); } function getProfileAvatar(req, res) { if (!req.user) { return res.status(404).json({error: 404, message: 'Not found', details: 'User not found'}); } if (!req.user.currentAvatar) { return _redirectToGeneratedAvatar(req.user, res); } Q.ninvoke(imageModule, 'getAvatar', req.user.currentAvatar, req.query.format) .spread((fileStoreMeta, readable) => { if (!readable) { logger.warn('Can not retrieve avatar stream for user %s', req.user._id); return _redirectToGeneratedAvatar(req.user, res); } if (!fileStoreMeta) { return readable.pipe(res.status(200)); } if (req.headers['if-modified-since'] && Number(new Date(req.headers['if-modified-since']).setMilliseconds(0)) === Number(fileStoreMeta.uploadDate.setMilliseconds(0))) { return res.status(304).end(); } res.header('Last-Modified', fileStoreMeta.uploadDate); readable.pipe(res.status(200)); }) .catch(err => { logger.warn('Can not get user avatar: %s', err.message); _redirectToGeneratedAvatar(req.user, res); }); } /** * Get avatar of a specific user {req.targetUser}. * * @param {Request} req - Request object contains targetUser * @param {Response} res - Response object */ function getTargetUserAvatar(req, res) { if (!req.targetUser.currentAvatar) { return _redirectToGeneratedAvatar(req.targetUser, res); } Q.ninvoke(imageModule, 'getAvatar', req.targetUser.currentAvatar, req.query.format) .spread((fileStoreMeta, readable) => { if (!readable) { logger.warn('Can not retrieve avatar stream for user %s', req.targetUser._id); return _redirectToGeneratedAvatar(req.targetUser, res); } if (!fileStoreMeta) { return readable.pipe(res.status(200)); } if (req.headers['if-modified-since'] && Number(new Date(req.headers['if-modified-since']).setMilliseconds(0)) === Number(fileStoreMeta.uploadDate.setMilliseconds(0))) { return res.status(304).end(); } res.header('Last-Modified', fileStoreMeta.uploadDate); readable.pipe(res.status(200)); }) .catch(err => { logger.warn('Can not get user avatar: %s', err.message); _redirectToGeneratedAvatar(req.targetUser, res); }); } function _redirectToGeneratedAvatar(user, res) { res.redirect(`/api/avatars?objectType=email&email=${user.preferredEmail}`); } /** * Find users by email. * * @param {string} email */ function _findUsersByEmail(email) { return Q.ninvoke(userModule, 'findUsersByEmail', email) .then(users => { const result = { total_count: users.length, list: users }; return result; }); } function updateStates(req, res) { userModule.updateStates(req.params.uuid, req.body, err => { if (err) { const details = 'Error while updating user states'; logger.error(details, err); return res.status(500).json({ error: { code: 500, message: 'Server Error', details } }); } res.status(204).end(); }); }