diff --git a/services/api/users.js b/services/api/users.js index c0bd252..6c9fd41 100644 --- a/services/api/users.js +++ b/services/api/users.js @@ -31,7 +31,7 @@ const userValidator = checkSchema({ }, }) -const createUserValidator = checkSchema({ +const roleValidator = checkSchema({ role: { matches: { errorMessage: `Role should be "${ROLES.WRITER}" or "${ROLES.READER}"`, @@ -41,9 +41,9 @@ const createUserValidator = checkSchema({ }) const changePasswordValidator = checkSchema({ - password: { + newPassword: { exists: true, - errorMessage: 'Password is required', + errorMessage: 'New password is required', }, }) @@ -144,22 +144,71 @@ async function deleteUser(req, res, next) { } async function changePassword(req, res, next) { - const { id } = req.params + const { id: targetId } = req.params + const { _id: requesterId } = req.user + const { oldPassword, newPassword } = req.body - if (!isValidId(id)) { + if (!isValidId(targetId)) { return next(createError(400, 'Invalid ID')) } try { + const targetUser = await models.users.findById(targetId) + + if (!targetUser) { + return next(createError(404, 'User not existed')) + } + + // If the user changes its own password and it is not the first time + // to be changed, then the request also needs old password. + if (requesterId.toString() === targetId && targetUser.passwordLastUpdated) { + if (oldPassword !== targetUser.password) { + return next(createError(400, 'Incorrect old password')) + } + } + const updated = { - password: req.body.password, + password: newPassword, passwordLastUpdated: new Date(), } const options = { new: true, runValidators: true, } - const result = await models.users.findByIdAndUpdate(id, updated, options) + const result = await models.users.findByIdAndUpdate(targetId, updated, options) + + if (!result) { + return next(createError(404, 'User not existed')) + } + + return res.status(204).send() + } catch (err) { + return next(createError(500, null, err)) + } +} + +async function updateRole(req, res, next) { + const { id: targetId } = req.params + const { role } = req.body + const { _id: requesterId } = req.user + + try { + const targetUser = await models.users.findById(targetId) + + if (!targetUser) { + return next(createError(404, 'User not existed')) + } + + if (targetUser.role === ROLES.ADMIN) { + return next(createError(400, 'Updating admin role is not allowed')) + } + + const updated = { role } + const options = { + new: true, + runValidators: true, + } + const result = await models.users.findByIdAndUpdate(targetId, updated, options) if (!result) { return next(createError(404, 'User not existed')) @@ -223,13 +272,14 @@ async function createAdminUser() { routesWithAuth( router, ['get', '/users', getAllUsers], - ['post', '/users', userValidator, createUserValidator, validate, createUser], + ['post', '/users', userValidator, roleValidator, validate, createUser], ) routesWithAuth( router, ['get', '/user/:id', isSelfOrAdmin, getUser], ['delete', '/user/:id', isSelfOrAdmin, deleteUser], ['patch', '/user/:id/password', isSelfOrAdmin, changePasswordValidator, validate, changePassword], + ['patch', '/user/:id/role', roleValidator, validate, updateRole], ) router.post('/login', userValidator, validate, login)