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){
if(!e.isDefaultPrevented()){
e.preventDefault();

File diff suppressed because one or more lines are too long

View File

@ -24,6 +24,27 @@ $(document).ready(function (){
$('#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){
$(this).wrap('<fieldset></fieldset>');
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.
try{
await db.users.insertOne(doc);
req.session.message = 'User account inserted';
req.session.messageType = 'success';
res.redirect('/admin/login');
res.status(200).json({ message: 'User account inserted' });
return;
}catch(ex){
console.error(colors.red('Failed to insert user: ' + ex));
req.session.message = 'Setup failed';
req.session.messageType = 'danger';
res.redirect('/admin/setup');
res.status(200).json({ message: 'Setup failed' });
return;
}
}
res.redirect('/admin/login');
res.status(200).json({ message: 'Already setup.' });
});
// settings

View File

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

View File

@ -88,7 +88,8 @@ test('[Fail] Create new user with invalid email', async t => {
.send(user)
.set('apiKey', g.users[0].apiKey)
.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 => {
@ -123,7 +124,8 @@ test('[Fail] Update user invalid email', async t => {
.send(user)
.set('apiKey', g.users[0].apiKey)
.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 => {

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">
<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>
<div class="form-group">
<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 class="form-group">
<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 class="form-group">
<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 class="form-group">
<label for="frm_userPassword_confirm">{{ @root.__ "Password confirm" }} *</label>

View File

@ -3,47 +3,48 @@
<div class="row">
<div class="col-md-8">
<h2>User edit</h2>
<form method="post" id="edit_form" action="/admin/user/update" data-toggle="validator">
<input type="hidden" name="userId" value="{{user._id}}" />
<div class="form-group">
<label>{{ @root.__ "Users name" }}</label>
<input type="text" class="form-control" name="usersName" value="{{user.usersName}}" required>
</div>
<div class="form-group">
<label>{{ @root.__ "User email" }}</label>
<input type="text" class="form-control" name="userEmail" value="{{user.userEmail}}" readonly>
</div>
<div class="form-group">
<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}}>
</div>
<div class="form-group">
<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}}>
</div>
{{#isAnAdmin @root.session.isAdmin}}
{{#ifCond @root.session.user '!=' user.userEmail}}
<div class="checkbox">
<label>
<input name="user_admin" {{#checkedState @root.user.isAdmin}}{{/checkedState}} type="checkbox"> {{ @root.__ "User is admin?" }}
</label>
</div>
{{/ifCond}}
{{/isAnAdmin}}
<div class="form-group">
<label>API Key</label>
<div class="input-group">
<input type="text" class="form-control" id="apiKey" value="{{user.apiKey}}" aria-label="..." readonly>
<div class="input-group-btn">
<button id="btnGenerateAPIkey" class="btn btn-success">{{ @root.__ "Generate" }}</button>
<form id="userEditForm" data-toggle="validator">
<input type="hidden" id="userId" value="{{user._id}}" />
<div class="form-group">
<label>{{ @root.__ "Users name" }}</label>
<input type="text" class="form-control" id="usersName" value="{{user.usersName}}" required>
</div>
<div class="form-group">
<label>{{ @root.__ "User email" }}</label>
<input type="text" class="form-control" id="userEmail" value="{{user.userEmail}}" readonly>
</div>
<div class="form-group">
<label>{{ @root.__ "User password" }} {{#ifCond session.user '==' user.userEmail}}*{{/ifCond}}</label>
<input autocomplete="off" type="password" class="form-control" id="userPassword" {{#ifCond session.user '==' user.userEmail}}required{{/ifCond}}>
</div>
<div class="form-group">
<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" {{#ifCond session.user '==' user.userEmail}}required{{/ifCond}}>
</div>
{{#isAnAdmin @root.session.isAdmin}}
{{#ifCond @root.session.user '!=' user.userEmail}}
<div class="checkbox">
<label>
<input id="userAdmin" {{#checkedState @root.user.isAdmin}}{{/checkedState}} type="checkbox"> {{ @root.__ "User is admin?" }}
</label>
</div>
{{/ifCond}}
{{/isAnAdmin}}
<div class="form-group">
<label>API Key</label>
<div class="input-group">
<input type="text" class="form-control" id="apiKey" value="{{user.apiKey}}" aria-label="..." readonly>
<div class="input-group-btn">
<button id="btnGenerateAPIkey" class="btn btn-success">{{ @root.__ "Generate" }}</button>
</div>
</div>
</div><br/>
<div class="form-group">
<div class="pull-right">
<button type="submit" class="btn btn-success">{{ @root.__ "Update" }}</button>
</div>
</div>
</div><br/>
<div class="form-group">
<div class="pull-right">
<button type="submit" class="btn btn-success">{{ @root.__ "Update" }}</button>
</div>
</div>
</form>
</div>
</div>
</div>

View File

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