This is something I've done a few times, but I've found it to feel a bit error-prone with so many conditions, and am wondering if anyone can point me in the direction of a cleaner way. This is a PATCH route for editing a user. Super admin and admin users are both able to change other users (with some limitations) while other types of users can only edit themselves.
router.patch('/:userId', async (req, res) => {
const patcher = (req as AuthRequest).user;
const otherUser = await database.getUserById(req.params.userId);
const requestedUpdate = req.body;
// 404 if user is not found.
if (!otherUser) {
return sendCannotFind(res);
}
// Basic validation of requestedUpdate
if (requestedUpdate.userType && !isUserTypeValid(requestedUpdate.userType)) {
return sendInvalidUserType(res);
}
if (patcher.userType === 'superAdmin') {
// Super admin cannot demote self.
if (otherUser.id === patcher.id && requestedUpdate.userType) {
return sendCannotSetUserType(res);
}
// Super admin cannot edit other super admins
if (otherUser.userType === 'superAdmin' && otherUser.id !== patcher.id) {
return sendCannotEdit(res);
}
} else if (patcher.userType === 'admin') {
// Admin cannot edit super admins
if (otherUser.userType === 'superAdmin') {
return sendCannotEdit(res);
}
// Admin cannot edit other admins
if (otherUser.userType === 'admin' && otherUser.id !== patcher.id) {
return sendCannotEdit(res);
}
// Admin cannot promote or demote themselves
if (otherUser.id === patcher.id && requestedUpdate.userType) {
return sendCannotSetUserType(res);
}
// Admin cannot promote anyone to admin or superAdmin
if (requestedUpdate.userType === 'admin' || requestedUpdate.userType === 'superAdmin') {
return sendCannotSetUserType(res);
}
} else {
// Non-admins cannot edit anyone but themselves
if (otherUser.id !== patcher.id) {
return sendCannotEdit(res);
}
// Non-admins cannot promote or demote themselves
if (requestedUpdate.userType && requestedUpdate.userType !== otherUser.userType) {
return sendCannotSetUserType(res);
}
}
await doEdit(otherUser, requestedUpdate);
return res.json(otherUser);
});
```