Enhancing user management

master
Mark Moffat 2019-11-07 17:06:20 +10:30
parent 001c015c36
commit 22c4362dc4
6 changed files with 80 additions and 33 deletions

View File

@ -101,7 +101,8 @@
"usersName" : "test", "usersName" : "test",
"userEmail" : "test@test.com", "userEmail" : "test@test.com",
"userPassword" : "$2a$10$7jQx/hQOWrRni531b/dHRuH8o1ZP8Yo8g..GpTOF4M7RrEH/pzTMy", "userPassword" : "$2a$10$7jQx/hQOWrRni531b/dHRuH8o1ZP8Yo8g..GpTOF4M7RrEH/pzTMy",
"isAdmin" : true "isAdmin" : true,
"isOwner": true
} }
], ],
"orders": [ "orders": [

View File

@ -107,7 +107,8 @@ router.post('/admin/setup_action', async (req, res) => {
usersName: req.body.usersName, usersName: req.body.usersName,
userEmail: req.body.userEmail, userEmail: req.body.userEmail,
userPassword: bcrypt.hashSync(req.body.userPassword, 10), userPassword: bcrypt.hashSync(req.body.userPassword, 10),
isAdmin: true isAdmin: true,
isOwner: true
}; };
// check for users // check for users

View File

@ -41,6 +41,14 @@ router.get('/admin/user/edit/:id', restrict, (req, res) => {
return; return;
} }
// Cannot edit the original user/owner
if(user._id !== req.session.userId && user.isOwner){
req.session.message = 'Access denied.';
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 // 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 // an admin we render an access denied message
if(user.userEmail !== req.session.user && req.session.isAdmin === false){ if(user.userEmail !== req.session.user && req.session.isAdmin === false){
@ -77,31 +85,51 @@ router.get('/admin/user/new', restrict, (req, res) => {
}); });
// delete user // delete user
router.get('/admin/user/delete/:id', restrict, (req, res) => { router.get('/admin/user/delete/:id', restrict, async (req, res) => {
const db = req.app.db; const db = req.app.db;
// userId // userId
if(req.session.isAdmin === true){ if(req.session.isAdmin !== true){
if(req.session.userId === req.params.id){
req.session.message = 'You can\'t delete your own user account.';
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);
}
req.session.message = 'User deleted.';
req.session.messageType = 'success';
res.redirect('/admin/users');
});
}else{
req.session.message = 'Access denied.'; req.session.message = 'Access denied.';
req.session.messageType = 'danger'; req.session.messageType = 'danger';
res.redirect('/admin/users'); res.redirect('/admin/users');
return;
} }
// Cannot delete your own account
if(req.session.userId === req.params.id){
req.session.message = 'Unable to delete own user account.';
req.session.messageType = 'danger';
res.redirect('/admin/users');
return;
}
const user = await db.users.findOne({ _id: common.getId(req.params.id) });
// If user is not found
if(!user){
req.session.message = 'User not found.';
req.session.messageType = 'danger';
res.redirect('/admin/users');
return;
}
// Cannot delete the original user/owner
if(user.isOwner){
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);
}
req.session.message = 'User deleted.';
req.session.messageType = 'success';
res.redirect('/admin/users');
});
}); });
// update a user // update a user

View File

@ -98,6 +98,17 @@ test.serial('[Success] User Login', async t => {
t.deepEqual(res.body.message, 'Login successful'); t.deepEqual(res.body.message, 'Login successful');
}); });
test.serial('[Fail] Incorrect user password', async t => {
const res = await request
.post('/admin/login_action')
.send({
email: users[0].userEmail,
password: 'test1'
})
.expect(400);
t.deepEqual(res.body.message, 'Access denied. Check password and try again.');
});
test.serial('[Success] Create API key', async t => { test.serial('[Success] Create API key', async t => {
const res = await request const res = await request
.post('/admin/createApiKey') .post('/admin/createApiKey')
@ -108,15 +119,18 @@ test.serial('[Success] Create API key', async t => {
t.deepEqual(res.body.apiKey.length, 24); t.deepEqual(res.body.apiKey.length, 24);
}); });
test.serial('[Fail] Incorrect user password', async t => { test.serial('[Fail] Delete own user account', async t => {
const res = await request const res = await request
.post('/admin/login_action') .get(`/admin/user/delete/${users[0]._id}`)
.send({ .expect(302);
email: users[0].userEmail, t.deepEqual(res.header['location'], '/admin/users');
password: 'test1' });
})
.expect(400); test.serial('[Fail] Delete invalid user ID', async t => {
t.deepEqual(res.body.message, 'Access denied. Check password and try again.'); const res = await request
.get('/admin/user/delete/invalid_user_id')
.expect(302);
t.deepEqual(res.header['location'], '/admin/users');
}); });
test.serial('[Fail] Customer login with incorrect email', async t => { test.serial('[Fail] Customer login with incorrect email', async t => {

View File

@ -15,17 +15,17 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{ @root.__ "User password" }} {{#ifCond session.user '==' user.userEmail}}*{{/ifCond}}</label> <label>{{ @root.__ "User password" }} {{#ifCond session.user '==' user.userEmail}}*{{/ifCond}}</label>
<input type="password" class="form-control" name="userPassword" {{#ifCond session.user '==' user.userEmail}}required{{/ifCond}}> <input autocomplete="off" type="password" class="form-control" name="userPassword" {{#ifCond session.user '==' user.userEmail}}required{{/ifCond}}>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{ @root.__ "Password confirm" }} {{#ifCond session.user '==' user.userEmail}}*{{/ifCond}}</label> <label>{{ @root.__ "Password confirm" }} {{#ifCond session.user '==' user.userEmail}}*{{/ifCond}}</label>
<input type="password" data-validation-match-match="userPassword" data-validation-match-message="Password values to not match" class="form-control" name="frm_userPassword_confirm" {{#ifCond session.user '==' user.userEmail}}required{{/ifCond}}> <input autocomplete="off" type="password" data-validation-match-match="userPassword" data-validation-match-message="Password values to not match" class="form-control" name="frm_userPassword_confirm" {{#ifCond session.user '==' user.userEmail}}required{{/ifCond}}>
</div> </div>
{{#isAnAdmin session.isAdmin}} {{#isAnAdmin @root.session.isAdmin}}
{{#ifCond session.user '!=' user.userEmail}} {{#ifCond @root.session.user '!=' user.userEmail}}
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input name="user_admin" {{#checkedState user.isAdmin}}{{/checkedState}} type="checkbox"> {{ @root.__ "User is admin?" }} <input name="user_admin" {{#checkedState @root.user.isAdmin}}{{/checkedState}} type="checkbox"> {{ @root.__ "User is admin?" }}
</label> </label>
</div> </div>
{{/ifCond}} {{/ifCond}}

View File

@ -11,6 +11,9 @@
<strong>{{ @root.__ "Role" }}: </strong> <strong>{{ @root.__ "Role" }}: </strong>
{{#isAnAdmin this.isAdmin}} {{#isAnAdmin this.isAdmin}}
<span>Admin</span> <span>Admin</span>
{{#if ../this.isOwner}}
(Owner)
{{/if}}
{{else}} {{else}}
<span>{{ @root.__ "User" }}</span> <span>{{ @root.__ "User" }}</span>
{{/isAnAdmin}} {{/isAnAdmin}}