Fixed user create and update API endpoints

master
Mark Moffat 2019-12-16 14:52:27 +10:30
parent 38ccb1fd9f
commit 1f84f77089
10 changed files with 163 additions and 159 deletions

View File

@ -112,6 +112,50 @@ $(document).ready(function (){
}); });
}); });
$('#userNewForm').validator().on('submit', function(e){
if(!e.isDefaultPrevented()){
e.preventDefault();
$.ajax({
method: 'POST',
url: '/admin/user/insert',
data: {
usersName: $('#usersName').val(),
userEmail: $('#userEmail').val(),
userPassword: $('#userPassword').val()
}
})
.done(function(msg){
showNotification(msg.message, 'success', false, '/admin/user/edit/' + msg.userId);
})
.fail(function(msg){
showNotification(msg.responseJSON.message, 'danger');
});
}
});
$('#userEditForm').validator().on('submit', function(e){
if(!e.isDefaultPrevented()){
e.preventDefault();
$.ajax({
method: 'POST',
url: '/admin/user/update',
data: {
userId: $('#userId').val(),
usersName: $('#usersName').val(),
userEmail: $('#userEmail').val(),
userPassword: $('#userPassword').val(),
userAdmin: $('#userPassword').is(':checked')
}
})
.done(function(msg){
showNotification(msg.message, 'success');
})
.fail(function(msg){
showNotification(msg.responseJSON.message, 'danger');
});
}
});
$('#productNewForm').validator().on('submit', function(e){ $('#productNewForm').validator().on('submit', function(e){
if(!e.isDefaultPrevented()){ if(!e.isDefaultPrevented()){
e.preventDefault(); e.preventDefault();

File diff suppressed because one or more lines are too long

View File

@ -24,6 +24,27 @@ $(document).ready(function (){
$('#offcanvasClose').hide(); $('#offcanvasClose').hide();
} }
$('#userSetupForm').validator().on('submit', function(e){
if(!e.isDefaultPrevented()){
e.preventDefault();
$.ajax({
method: 'POST',
url: '/admin/setup_action',
data: {
usersName: $('#usersName').val(),
userEmail: $('#userEmail').val(),
userPassword: $('#userPassword').val()
}
})
.done(function(msg){
showNotification(msg.message, 'success', false, '/admin/login');
})
.fail(function(msg){
showNotification(msg.responseJSON.message, 'danger');
});
}
});
$('.shipping-form input').each(function(e){ $('.shipping-form input').each(function(e){
$(this).wrap('<fieldset></fieldset>'); $(this).wrap('<fieldset></fieldset>');
var tag = $(this).attr('placeholder'); var tag = $(this).attr('placeholder');

File diff suppressed because one or more lines are too long

View File

@ -116,19 +116,15 @@ router.post('/admin/setup_action', async (req, res) => {
// email is ok to be used. // email is ok to be used.
try{ try{
await db.users.insertOne(doc); await db.users.insertOne(doc);
req.session.message = 'User account inserted'; res.status(200).json({ message: 'User account inserted' });
req.session.messageType = 'success';
res.redirect('/admin/login');
return; return;
}catch(ex){ }catch(ex){
console.error(colors.red('Failed to insert user: ' + ex)); console.error(colors.red('Failed to insert user: ' + ex));
req.session.message = 'Setup failed'; res.status(200).json({ message: 'Setup failed' });
req.session.messageType = 'danger';
res.redirect('/admin/setup');
return; return;
} }
} }
res.redirect('/admin/login'); res.status(200).json({ message: 'Already setup.' });
}); });
// settings // settings

View File

@ -168,24 +168,17 @@ router.get('/admin/user/delete/:id', restrict, async (req, res) => {
router.post('/admin/user/update', restrict, async (req, res) => { router.post('/admin/user/update', restrict, async (req, res) => {
const db = req.app.db; const db = req.app.db;
let isAdmin = req.body.user_admin === 'on'; let isAdmin = req.body.userAdmin === 'on';
// get the user we want to update // get the user we want to update
const user = await db.users.findOne({ _id: common.getId(req.body.userId) }); const user = await db.users.findOne({ _id: common.getId(req.body.userId) });
// If user not found // If user not found
if(!user){ if(!user){
if(req.apiAuthenticated){
res.status(400).json({ message: 'User not found' }); res.status(400).json({ message: 'User not found' });
return; return;
} }
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 the current user changing own account ensure isAdmin retains existing
if(user.userEmail === req.session.user){ if(user.userEmail === req.session.user){
isAdmin = user.isAdmin; isAdmin = user.isAdmin;
@ -194,17 +187,10 @@ router.post('/admin/user/update', restrict, async (req, res) => {
// 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){
if(req.apiAuthenticated){
res.status(400).json({ message: 'Access denied' }); res.status(400).json({ message: 'Access denied' });
return; return;
} }
req.session.message = 'Access denied';
req.session.messageType = 'danger';
res.redirect('/admin/users');
return;
}
// create the update doc // create the update doc
const updateDoc = {}; const updateDoc = {};
updateDoc.isAdmin = isAdmin; updateDoc.isAdmin = isAdmin;
@ -221,13 +207,10 @@ router.post('/admin/user/update', restrict, async (req, res) => {
// Validate update user // Validate update user
const schemaResult = validateJson('editUser', updateDoc); const schemaResult = validateJson('editUser', updateDoc);
if(!schemaResult.result){ if(!schemaResult.result){
if(req.apiAuthenticated){ res.status(400).json({
res.status(400).json(schemaResult.errors); message: 'Failed to create user. Check inputs.',
return; error: schemaResult.errors
} });
req.session.message = 'Please check your inputs.';
req.session.messageType = 'danger';
res.redirect('/admin/user/edit/' + req.body.userId);
return; return;
} }
@ -238,26 +221,15 @@ router.post('/admin/user/update', restrict, async (req, res) => {
$set: updateDoc $set: updateDoc
}, { multi: false, returnOriginal: false } }, { multi: false, returnOriginal: false }
); );
if(req.apiAuthenticated){
const returnUser = updatedUser.value; const returnUser = updatedUser.value;
delete returnUser.userPassword; delete returnUser.userPassword;
delete returnUser.apiKey; delete returnUser.apiKey;
res.status(200).json({ message: 'User account updated', user: updatedUser.value }); res.status(200).json({ message: 'User account updated', user: updatedUser.value });
return; return;
}
// show the view
req.session.message = 'User account updated';
req.session.messageType = 'success';
res.redirect('/admin/user/edit/' + req.body.userId);
}catch(ex){ }catch(ex){
console.error(colors.red('Failed updating user: ' + ex)); console.error(colors.red('Failed updating user: ' + ex));
if(req.apiAuthenticated){
res.status(400).json({ message: 'Failed to update user' }); res.status(400).json({ message: 'Failed to update user' });
return;
}
req.session.message = 'Failed to update user';
req.session.messageType = 'danger';
res.redirect('/admin/user/edit/' + req.body.userId);
} }
}); });
@ -265,9 +237,6 @@ router.post('/admin/user/update', restrict, async (req, res) => {
router.post('/admin/user/insert', restrict, async (req, res) => { router.post('/admin/user/insert', restrict, async (req, res) => {
const db = req.app.db; const db = req.app.db;
// set the account to admin if using the setup form. Eg: First user account
const urlParts = req.get('Referrer');
// Check number of users // Check number of users
const userCount = await db.users.countDocuments({}); const userCount = await db.users.countDocuments({});
let isAdmin = false; let isAdmin = false;
@ -287,57 +256,27 @@ router.post('/admin/user/insert', restrict, async (req, res) => {
// Validate new user // Validate new user
const schemaResult = validateJson('newUser', userObj); const schemaResult = validateJson('newUser', userObj);
if(!schemaResult.result){ if(!schemaResult.result){
if(req.apiAuthenticated){ res.status(400).json({ message: 'Failed to create user. Check inputs.', error: schemaResult.errors });
res.status(400).json(schemaResult.errors);
return;
}
req.session.message = 'Invalid new user. Please check your inputs.';
req.session.messageType = 'danger';
res.redirect('/admin/user/new');
return; return;
} }
// check for existing user // check for existing user
const user = await db.users.findOne({ userEmail: req.body.userEmail }); const user = await db.users.findOne({ userEmail: req.body.userEmail });
if(user){ 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')); console.error(colors.red('Failed to insert user, possibly already exists'));
req.session.message = 'A user with that email address already exists'; res.status(400).json({ message: 'A user with that email address already exists' });
req.session.messageType = 'danger';
res.redirect('/admin/user/new');
return; return;
} }
// email is ok to be used. // email is ok to be used.
try{ try{
await db.users.insertOne(userObj); const newUser = await db.users.insertOne(userObj);
// if from setup we add user to session and redirect to login. res.status(200).json({
// Otherwise we show users screen message: 'User account inserted',
if(urlParts && urlParts.path === '/admin/setup'){ userId: newUser.insertedId
req.session.user = req.body.userEmail; });
res.redirect('/admin/login');
return;
}
if(req.apiAuthenticated){
res.status(200).json({ message: 'User account inserted' });
return;
}
req.session.message = 'User account inserted';
req.session.messageType = 'success';
res.redirect('/admin/users');
}catch(ex){ }catch(ex){
console.error(colors.red('Failed to insert user: ' + ex)); console.error(colors.red('Failed to insert user: ' + ex));
if(req.apiAuthenticated){
res.status(400).json({ message: 'New user creation failed' }); res.status(400).json({ message: 'New user creation failed' });
return;
}
req.session.message = 'New user creation failed';
req.session.messageType = 'danger';
res.redirect('/admin/user/new');
} }
}); });

View File

@ -88,7 +88,8 @@ test('[Fail] Create new user with invalid email', async t => {
.send(user) .send(user)
.set('apiKey', g.users[0].apiKey) .set('apiKey', g.users[0].apiKey)
.expect(400); .expect(400);
t.deepEqual(res.body[0].message, 'should match format "emailAddress"'); t.deepEqual(res.body.message, 'Failed to create user. Check inputs.');
t.deepEqual(res.body.error[0].message, 'should match format "emailAddress"');
}); });
test('[Success] Update user', async t => { test('[Success] Update user', async t => {
@ -123,7 +124,8 @@ test('[Fail] Update user invalid email', async t => {
.send(user) .send(user)
.set('apiKey', g.users[0].apiKey) .set('apiKey', g.users[0].apiKey)
.expect(400); .expect(400);
t.deepEqual(res.body[0].message, 'should match format "emailAddress"'); t.deepEqual(res.body.message, 'Failed to create user. Check inputs.');
t.deepEqual(res.body.error[0].message, 'should match format "emailAddress"');
}); });
test('[Fail] Update user invalid userId', async t => { test('[Fail] Update user invalid userId', async t => {

View File

@ -1,17 +1,17 @@
<div class="col-md-offset-4 col-md-4 col-lg-offset-4 col-lg-4" style="padding-top: 50px"> <div class="col-md-offset-4 col-md-4 col-lg-offset-4 col-lg-4" style="padding-top: 50px">
<form class="form-signin" action="/admin/setup_action" method="post" role="form" data-toggle="validator"> <form class="form-signin" id="userSetupForm" role="form" data-toggle="validator">
<h2 class="form-signin-heading text-center">expressCart Setup</h2> <h2 class="form-signin-heading text-center">expressCart Setup</h2>
<div class="form-group"> <div class="form-group">
<label for="usersName">{{ @root.__ "Users name" }} *</label> <label for="usersName">{{ @root.__ "Users name" }} *</label>
<input type="text" class="form-control" id="usersName" name="usersName" placeholder="{{ @root.__ "Users name" }}" required> <input type="text" class="form-control" id="usersName" placeholder="{{ @root.__ "Users name" }}" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="userEmail">{{ @root.__ "User email" }} *</label> <label for="userEmail">{{ @root.__ "User email" }} *</label>
<input type="email" class="form-control" id="userEmail" name="userEmail" placeholder="{{ @root.__ "Email address" }}" required> <input type="email" class="form-control" id="userEmail" placeholder="{{ @root.__ "Email address" }}" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="userPassword">{{ @root.__ "User password" }} *</label> <label for="userPassword">{{ @root.__ "User password" }} *</label>
<input type="password" class="form-control" id="userPassword" name="userPassword" placeholder="Password" required> <input type="password" class="form-control" id="userPassword" placeholder="Password" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="frm_userPassword_confirm">{{ @root.__ "Password confirm" }} *</label> <label for="frm_userPassword_confirm">{{ @root.__ "Password confirm" }} *</label>

View File

@ -3,29 +3,29 @@
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<h2>User edit</h2> <h2>User edit</h2>
<form method="post" id="edit_form" action="/admin/user/update" data-toggle="validator"> <form id="userEditForm" data-toggle="validator">
<input type="hidden" name="userId" value="{{user._id}}" /> <input type="hidden" id="userId" value="{{user._id}}" />
<div class="form-group"> <div class="form-group">
<label>{{ @root.__ "Users name" }}</label> <label>{{ @root.__ "Users name" }}</label>
<input type="text" class="form-control" name="usersName" value="{{user.usersName}}" required> <input type="text" class="form-control" id="usersName" value="{{user.usersName}}" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{ @root.__ "User email" }}</label> <label>{{ @root.__ "User email" }}</label>
<input type="text" class="form-control" name="userEmail" value="{{user.userEmail}}" readonly> <input type="text" class="form-control" id="userEmail" value="{{user.userEmail}}" readonly>
</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 autocomplete="off" type="password" class="form-control" name="userPassword" {{#ifCond session.user '==' user.userEmail}}required{{/ifCond}}> <input autocomplete="off" type="password" class="form-control" id="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 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}}> <input autocomplete="off" type="password" data-validation-match-match="userPassword" data-validation-match-message="Password values to not match" class="form-control" {{#ifCond session.user '==' user.userEmail}}required{{/ifCond}}>
</div> </div>
{{#isAnAdmin @root.session.isAdmin}} {{#isAnAdmin @root.session.isAdmin}}
{{#ifCond @root.session.user '!=' user.userEmail}} {{#ifCond @root.session.user '!=' user.userEmail}}
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input name="user_admin" {{#checkedState @root.user.isAdmin}}{{/checkedState}} type="checkbox"> {{ @root.__ "User is admin?" }} <input id="userAdmin" {{#checkedState @root.user.isAdmin}}{{/checkedState}} type="checkbox"> {{ @root.__ "User is admin?" }}
</label> </label>
</div> </div>
{{/ifCond}} {{/ifCond}}
@ -44,6 +44,7 @@
<button type="submit" class="btn btn-success">{{ @root.__ "Update" }}</button> <button type="submit" class="btn btn-success">{{ @root.__ "Update" }}</button>
</div> </div>
</div> </div>
</form>
</div> </div>
</div> </div>
</div> </div>

View File

@ -3,28 +3,29 @@
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<h2>{{ @root.__ "New User" }}</h2> <h2>{{ @root.__ "New User" }}</h2>
<form method="post" id="edit_form" action="/admin/user/insert" data-toggle="validator"> <form id="userNewForm" data-toggle="validator" autocomplete="off">
<div class="form-group"> <div class="form-group">
<label>{{ @root.__ "Users name" }} *</label> <label>{{ @root.__ "Users name" }} *</label>
<input type="text" class="form-control" name="usersName" value="{{user.usersName}}" required> <input type="text" class="form-control" id="usersName" value="{{user.usersName}}" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{ @root.__ "User email" }} *</label> <label>{{ @root.__ "User email" }} *</label>
<input type="email" class="form-control" name="userEmail" value="{{user.userEmail}}" required> <input type="email" class="form-control" id="userEmail" value="{{user.userEmail}}" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{ @root.__ "User password" }} *</label> <label>{{ @root.__ "User password" }} *</label>
<input type="password" class="form-control" id="userPassword" name="userPassword" required> <input type="password" class="form-control" id="userPassword" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{ @root.__ "Password confirm" }} *</label> <label>{{ @root.__ "Password confirm" }} *</label>
<input type="password" data-match="#userPassword" class="form-control" name="frm_userPassword_confirm" required> <input type="password" data-match="#userPassword" class="form-control" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="pull-right"> <div class="pull-right">
<button type="submit" class="btn btn-success">{{ @root.__ "Create" }}</button> <button type="submit" class="btn btn-success">{{ @root.__ "Create" }}</button>
</div> </div>
</div> </div>
</form>
</div> </div>
</div> </div>
</div> </div>