From 1deb54d52557011c87cd9ffbfcd381ed58ced287 Mon Sep 17 00:00:00 2001 From: Mark Moffat Date: Sat, 9 Nov 2019 09:48:32 +1030 Subject: [PATCH] Refactor user route --- routes/user.js | 337 +++++++++++++++++++++++++++++-------------------- 1 file changed, 200 insertions(+), 137 deletions(-) diff --git a/routes/user.js b/routes/user.js index 1486c0f..d7f17b1 100644 --- a/routes/user.js +++ b/routes/user.js @@ -5,61 +5,69 @@ const colors = require('colors'); const bcrypt = require('bcryptjs'); const router = express.Router(); -router.get('/admin/users', restrict, (req, res) => { +router.get('/admin/users', restrict, async (req, res) => { const db = req.app.db; - db.users.find({}).toArray((err, users) => { - if(err){ - console.info(err.stack); - } - res.render('users', { - title: 'Users', - users: users, - admin: true, - config: req.app.config, - isAdmin: req.session.isAdmin, - helpers: req.handlebars.helpers, - session: req.session, - message: common.clearSessionValue(req.session, 'message'), - messageType: common.clearSessionValue(req.session, 'messageType') - }); + const users = await db.users.find({}, { projection: { userPassword: 0 } }).toArray(); + + if(req.apiAuthenticated){ + res.status(200).json(users); + return; + } + + res.render('users', { + title: 'Users', + users: users, + admin: true, + config: req.app.config, + isAdmin: req.session.isAdmin, + helpers: req.handlebars.helpers, + session: req.session, + message: common.clearSessionValue(req.session, 'message'), + messageType: common.clearSessionValue(req.session, 'messageType') }); }); // edit user -router.get('/admin/user/edit/:id', restrict, (req, res) => { +router.get('/admin/user/edit/:id', restrict, async (req, res) => { const db = req.app.db; - db.users.findOne({ _id: common.getId(req.params.id) }, (err, user) => { - if(err){ - console.info(err.stack); - } + const user = await db.users.findOne({ _id: common.getId(req.params.id) }); - // Check user is found - if(!user){ - req.session.message = 'User not found'; - req.session.messageType = 'danger'; - res.redirect('/admin/users'); + // Check user is found + if(!user){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'User not found' }); return; } - // if the user we want to edit is not the current logged in user and the current user is not - // an admin we render an access denied message - if(user.userEmail !== req.session.user && req.session.isAdmin === false){ - req.session.message = 'Access denied'; - req.session.messageType = 'danger'; - res.redirect('/admin/users'); + req.session.message = 'User not found'; + req.session.messageType = 'danger'; + res.redirect('/admin/users'); + return; + } + + // if the user we want to edit is not the current logged in user and the current user is not + // an admin we render an access denied message + if(user.userEmail !== req.session.user && req.session.isAdmin === false){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'Access denied' }); return; } - res.render('user_edit', { - title: 'User edit', - user: user, - admin: true, - session: req.session, - message: common.clearSessionValue(req.session, 'message'), - messageType: common.clearSessionValue(req.session, 'messageType'), - helpers: req.handlebars.helpers, - config: req.app.config - }); + req.session.message = 'Access denied'; + req.session.messageType = 'danger'; + res.redirect('/admin/users'); + return; + } + + res.render('user_edit', { + title: 'User edit', + user: user, + admin: true, + session: req.session, + message: common.clearSessionValue(req.session, 'message'), + messageType: common.clearSessionValue(req.session, 'messageType'), + helpers: req.handlebars.helpers, + config: req.app.config }); }); @@ -82,6 +90,11 @@ router.get('/admin/user/delete/:id', restrict, async (req, res) => { // userId if(req.session.isAdmin !== true){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'Access denied' }); + return; + } + req.session.message = 'Access denied.'; req.session.messageType = 'danger'; res.redirect('/admin/users'); @@ -90,6 +103,11 @@ router.get('/admin/user/delete/:id', restrict, async (req, res) => { // Cannot delete your own account if(req.session.userId === req.params.id){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'Unable to delete own user account' }); + return; + } + req.session.message = 'Unable to delete own user account.'; req.session.messageType = 'danger'; res.redirect('/admin/users'); @@ -100,6 +118,11 @@ router.get('/admin/user/delete/:id', restrict, async (req, res) => { // If user is not found if(!user){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'User not found.' }); + return; + } + req.session.message = 'User not found.'; req.session.messageType = 'danger'; res.redirect('/admin/users'); @@ -108,139 +131,179 @@ router.get('/admin/user/delete/:id', restrict, async (req, res) => { // Cannot delete the original user/owner if(user.isOwner){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'Access denied.' }); + return; + } + req.session.message = 'Access denied.'; req.session.messageType = 'danger'; res.redirect('/admin/users'); return; } - db.users.deleteOne({ _id: common.getId(req.params.id) }, {}, (err, numRemoved) => { - if(err){ - console.info(err.stack); + try{ + await db.users.deleteOne({ _id: common.getId(req.params.id) }, {}); + if(req.apiAuthenticated){ + res.status(200).json({ message: 'User deleted.' }); + return; } req.session.message = 'User deleted.'; req.session.messageType = 'success'; res.redirect('/admin/users'); - }); + }catch(ex){ + console.log('Failed to delete user', ex); + if(req.apiAuthenticated){ + res.status(200).json({ message: 'Cannot delete user' }); + return; + } + req.session.message = 'Cannot delete user'; + req.session.messageType = 'danger'; + res.redirect('/admin/users'); + }; }); // update a user -router.post('/admin/user/update', restrict, (req, res) => { +router.post('/admin/user/update', restrict, async (req, res) => { const db = req.app.db; let isAdmin = req.body.user_admin === 'on'; // get the user we want to update - db.users.findOne({ _id: common.getId(req.body.userId) }, (err, user) => { - if(err){ - console.info(err.stack); - } + const user = await db.users.findOne({ _id: common.getId(req.body.userId) }); - // If the current user changing own account ensure isAdmin retains existing - if(user.userEmail === req.session.user){ - isAdmin = user.isAdmin; - } - - // if the user we want to edit is not the current logged in user and the current user is not - // an admin we render an access denied message - if(user.userEmail !== req.session.user && req.session.isAdmin === false){ - req.session.message = 'Access denied'; - req.session.messageType = 'danger'; - res.redirect('/admin/users'); + // If user not found + if(!user){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'User not found' }); return; } - // create the update doc - const updateDoc = {}; - updateDoc.isAdmin = isAdmin; - updateDoc.usersName = req.body.usersName; - if(req.body.userPassword){ - updateDoc.userPassword = bcrypt.hashSync(req.body.userPassword); + req.session.message = 'User not found'; + req.session.messageType = 'danger'; + res.redirect('/admin/users'); + return; + } + + // If the current user changing own account ensure isAdmin retains existing + if(user.userEmail === req.session.user){ + isAdmin = user.isAdmin; + } + + // if the user we want to edit is not the current logged in user and the current user is not + // an admin we render an access denied message + if(user.userEmail !== req.session.user && req.session.isAdmin === false){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'Access denied' }); + return; } - db.users.updateOne({ _id: common.getId(req.body.userId) }, + req.session.message = 'Access denied'; + req.session.messageType = 'danger'; + res.redirect('/admin/users'); + return; + } + + // create the update doc + const updateDoc = {}; + updateDoc.isAdmin = isAdmin; + updateDoc.usersName = req.body.usersName; + if(req.body.userPassword){ + updateDoc.userPassword = bcrypt.hashSync(req.body.userPassword); + } + + try{ + await db.users.updateOne( + { _id: common.getId(req.body.userId) }, { $set: updateDoc - }, { multi: false }, (err, numReplaced) => { - if(err){ - console.error(colors.red('Failed updating user: ' + err)); - req.session.message = 'Failed to update user'; - req.session.messageType = 'danger'; - res.redirect('/admin/user/edit/' + req.body.userId); - }else{ - // show the view - req.session.message = 'User account updated.'; - req.session.messageType = 'success'; - res.redirect('/admin/user/edit/' + req.body.userId); - } - }); - }); + }, { multi: false } + ); + if(req.apiAuthenticated){ + res.status(200).json({ message: 'User account updated.' }); + return; + } + // show the view + req.session.message = 'User account updated.'; + req.session.messageType = 'success'; + res.redirect('/admin/user/edit/' + req.body.userId); + }catch(ex){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'Failed to update user' }); + return; + } + console.error(colors.red('Failed updating user: ' + ex)); + req.session.message = 'Failed to update user'; + req.session.messageType = 'danger'; + res.redirect('/admin/user/edit/' + req.body.userId); + } }); // insert a user -router.post('/admin/user/insert', restrict, (req, res) => { +router.post('/admin/user/insert', restrict, async (req, res) => { const db = req.app.db; // set the account to admin if using the setup form. Eg: First user account const urlParts = new URL(req.header('Referer')); // Check number of users - db.users.countDocuments({}, (err, userCount) => { - let isAdmin = false; + const userCount = await db.users.countDocuments({}); + let isAdmin = false; - // if no users, setup user as admin - if(userCount === 0){ - isAdmin = true; + // if no users, setup user as admin + if(userCount === 0){ + isAdmin = true; + } + + const doc = { + usersName: req.body.usersName, + userEmail: req.body.userEmail, + userPassword: bcrypt.hashSync(req.body.userPassword, 10), + isAdmin: isAdmin + }; + + // check for existing user + const user = await db.users.findOne({ userEmail: req.body.userEmail }); + if(user){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'A user with that email address already exists' }); + return; + } + // user already exists with that email address + console.error(colors.red('Failed to insert user, possibly already exists: ' + err)); + req.session.message = 'A user with that email address already exists'; + req.session.messageType = 'danger'; + res.redirect('/admin/user/new'); + return; + } + // email is ok to be used. + try{ + await db.users.insertOne(doc); + // if from setup we add user to session and redirect to login. + // Otherwise we show users screen + if(urlParts.path === '/admin/setup'){ + req.session.user = req.body.userEmail; + res.redirect('/admin/login'); + return; + } + if(req.apiAuthenticated){ + res.status(200).json({ message: 'User account inserted' }); + return; } - const doc = { - usersName: req.body.usersName, - userEmail: req.body.userEmail, - userPassword: bcrypt.hashSync(req.body.userPassword, 10), - isAdmin: isAdmin - }; - - // check for existing user - db.users.findOne({ userEmail: req.body.userEmail }, (err, user) => { - if(user){ - // user already exists with that email address - console.error(colors.red('Failed to insert user, possibly already exists: ' + err)); - req.session.message = 'A user with that email address already exists'; - req.session.messageType = 'danger'; - res.redirect('/admin/user/new'); - return; - } - // email is ok to be used. - db.users.insertOne(doc, (err, doc) => { - // show the view - if(err){ - if(doc){ - console.error(colors.red('Failed to insert user: ' + err)); - req.session.message = 'User exists'; - req.session.messageType = 'danger'; - res.redirect('/admin/user/edit/' + doc._id); - return; - } - console.error(colors.red('Failed to insert user: ' + err)); - req.session.message = 'New user creation failed'; - req.session.messageType = 'danger'; - res.redirect('/admin/user/new'); - return; - } - req.session.message = 'User account inserted'; - req.session.messageType = 'success'; - - // if from setup we add user to session and redirect to login. - // Otherwise we show users screen - if(urlParts.path === '/admin/setup'){ - req.session.user = req.body.userEmail; - res.redirect('/admin/login'); - return; - } - res.redirect('/admin/users'); - }); - }); - }); + req.session.message = 'User account inserted'; + req.session.messageType = 'success'; + res.redirect('/admin/users'); + }catch(ex){ + if(req.apiAuthenticated){ + res.status(400).json({ message: 'New user creation failed' }); + return; + } + console.error(colors.red('Failed to insert user: ' + ex)); + req.session.message = 'New user creation failed'; + req.session.messageType = 'danger'; + res.redirect('/admin/user/new'); + } }); module.exports = router;