Update customer route and tests
parent
f779ee4baf
commit
a6645e9d81
|
@ -90,10 +90,22 @@
|
||||||
"address1" : "1 test street",
|
"address1" : "1 test street",
|
||||||
"address2" : "testvile",
|
"address2" : "testvile",
|
||||||
"country" : "Netherlands",
|
"country" : "Netherlands",
|
||||||
"state" : "",
|
"state" : "NL",
|
||||||
"postcode" : "2000TW",
|
"postcode" : "2000TW",
|
||||||
"phone" : "123456789",
|
"phone" : "123456789",
|
||||||
"password" : "$2a$10$kKjnX1J/CAdgdmLI0WuPY.ILH1c7N8mD0H/ZyUXEfee1mJxJvZIS."
|
"password" : "$2a$10$kKjnX1J/CAdgdmLI0WuPY.ILH1c7N8mD0H/ZyUXEfee1mJxJvZIS."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email" : "test1@test.com",
|
||||||
|
"firstName" : "Testy",
|
||||||
|
"lastName" : "McTesterson",
|
||||||
|
"address1" : "2 test street",
|
||||||
|
"address2" : "testvile",
|
||||||
|
"country" : "Netherlands",
|
||||||
|
"state" : "",
|
||||||
|
"postcode" : "2000ZT",
|
||||||
|
"phone" : "123456789",
|
||||||
|
"password" : "$2a$10$kKjnX1J/CAdgdmLI0WuPY.ILH1c7N8mD0H/ZyUXEfee1mJxJvZIS."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"users": [
|
"users": [
|
||||||
|
|
|
@ -18,6 +18,14 @@ const addSchemas = () => {
|
||||||
// Amount format
|
// Amount format
|
||||||
const amountRegex = /^[1-9]\d*(\.\d+)?$/;
|
const amountRegex = /^[1-9]\d*(\.\d+)?$/;
|
||||||
ajv.addFormat('amount', amountRegex);
|
ajv.addFormat('amount', amountRegex);
|
||||||
|
|
||||||
|
ajv.addKeyword('isNotEmpty', {
|
||||||
|
type: 'string',
|
||||||
|
validate: (schema, data) => {
|
||||||
|
return typeof data === 'string' && data.trim() !== '';
|
||||||
|
},
|
||||||
|
errors: false
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateJson = (schema, json) => {
|
const validateJson = (schema, json) => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"$id": "customer",
|
"$id": "editCustomer",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"email": {
|
"email": {
|
||||||
|
@ -7,28 +7,35 @@
|
||||||
"format": "emailAddress"
|
"format": "emailAddress"
|
||||||
},
|
},
|
||||||
"firstName": {
|
"firstName": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
},
|
},
|
||||||
"lastName": {
|
"lastName": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
},
|
},
|
||||||
"address1": {
|
"address1": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
},
|
},
|
||||||
"address2": {
|
"address2": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"country": {
|
"country": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
},
|
},
|
||||||
"postcode": {
|
"postcode": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
},
|
},
|
||||||
"phone": {
|
"phone": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -39,11 +46,9 @@
|
||||||
"firstName",
|
"firstName",
|
||||||
"lastName",
|
"lastName",
|
||||||
"address1",
|
"address1",
|
||||||
"address2",
|
|
||||||
"country",
|
"country",
|
||||||
"state",
|
"state",
|
||||||
"postcode",
|
"postcode",
|
||||||
"phone",
|
"phone"
|
||||||
"password"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
{
|
||||||
|
"$id": "newCustomer",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "emailAddress"
|
||||||
|
},
|
||||||
|
"firstName": {
|
||||||
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
|
},
|
||||||
|
"lastName": {
|
||||||
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
|
},
|
||||||
|
"address1": {
|
||||||
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
|
},
|
||||||
|
"address2": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
|
},
|
||||||
|
"postcode": {
|
||||||
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
|
},
|
||||||
|
"phone": {
|
||||||
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"isNotEmpty": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"email",
|
||||||
|
"firstName",
|
||||||
|
"lastName",
|
||||||
|
"address1",
|
||||||
|
"country",
|
||||||
|
"state",
|
||||||
|
"postcode",
|
||||||
|
"phone",
|
||||||
|
"password"
|
||||||
|
]
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ router.post('/customer/create', async (req, res) => {
|
||||||
created: new Date()
|
created: new Date()
|
||||||
};
|
};
|
||||||
|
|
||||||
const schemaResult = validateJson('customer', customerObj);
|
const schemaResult = validateJson('newCustomer', customerObj);
|
||||||
if(!schemaResult.result){
|
if(!schemaResult.result){
|
||||||
res.status(400).json(schemaResult.errors);
|
res.status(400).json(schemaResult.errors);
|
||||||
return;
|
return;
|
||||||
|
@ -55,6 +55,83 @@ router.post('/customer/create', async (req, res) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update a customer
|
||||||
|
router.post('/admin/customer/update', restrict, async (req, res) => {
|
||||||
|
const db = req.app.db;
|
||||||
|
|
||||||
|
const customerObj = {
|
||||||
|
email: req.body.email,
|
||||||
|
firstName: req.body.firstName,
|
||||||
|
lastName: req.body.lastName,
|
||||||
|
address1: req.body.address1,
|
||||||
|
address2: req.body.address2,
|
||||||
|
country: req.body.country,
|
||||||
|
state: req.body.state,
|
||||||
|
postcode: req.body.postcode,
|
||||||
|
phone: req.body.phone
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle optional values
|
||||||
|
if(req.body.password){ customerObj.password = bcrypt.hashSync(req.body.password, 10); }
|
||||||
|
|
||||||
|
const schemaResult = validateJson('editCustomer', customerObj);
|
||||||
|
if(!schemaResult.result){
|
||||||
|
console.log('errors', schemaResult.errors);
|
||||||
|
if(req.apiAuthenticated){
|
||||||
|
res.status(400).json(schemaResult.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
req.session.message = 'Unable to update customer. Check input values';
|
||||||
|
req.session.messageType = 'danger';
|
||||||
|
res.redirect('/admin/customer/view/' + req.body.customerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for existing customer
|
||||||
|
const customer = await db.customers.findOne({ _id: common.getId(req.body.customerId) });
|
||||||
|
if(!customer){
|
||||||
|
if(req.apiAuthenticated){
|
||||||
|
res.status(400).json({
|
||||||
|
err: 'Customer not found'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.session.message = 'Customer not found';
|
||||||
|
req.session.messageType = 'danger';
|
||||||
|
res.redirect('/admin/customer/view/' + req.body.customerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Update customer
|
||||||
|
try{
|
||||||
|
const updatedCustomer = await db.customers.findOneAndUpdate(
|
||||||
|
{ _id: common.getId(req.body.customerId) },
|
||||||
|
{
|
||||||
|
$set: customerObj
|
||||||
|
}, { multi: false, returnOriginal: false }
|
||||||
|
);
|
||||||
|
if(req.apiAuthenticated){
|
||||||
|
const returnCustomer = updatedCustomer.value;
|
||||||
|
delete returnCustomer.password;
|
||||||
|
res.status(200).json({ message: 'Customer updated', customer: updatedCustomer.value });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// show the view
|
||||||
|
req.session.message = 'Customer updated';
|
||||||
|
req.session.messageType = 'success';
|
||||||
|
res.redirect('/admin/customer/view/' + req.body.customerId);
|
||||||
|
}catch(ex){
|
||||||
|
console.error(colors.red('Failed updating customer: ' + ex));
|
||||||
|
if(req.apiAuthenticated){
|
||||||
|
res.status(400).json({ message: 'Failed to update customer' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
req.session.message = 'Failed to update customer';
|
||||||
|
req.session.messageType = 'danger';
|
||||||
|
res.redirect('/admin/customer/view/' + req.body.userId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// render the customer view
|
// render the customer view
|
||||||
router.get('/admin/customer/view/:id?', restrict, async (req, res) => {
|
router.get('/admin/customer/view/:id?', restrict, async (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
|
@ -53,7 +53,7 @@ test('[Fail] Try create a duplicate customer', async t => {
|
||||||
t.deepEqual(res.body.err, 'A customer already exists with that email address');
|
t.deepEqual(res.body.err, 'A customer already exists with that email address');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[Fail] Try invalid email address', async t => {
|
test('[Fail] Create with invalid email address', async t => {
|
||||||
const customer = {
|
const customer = {
|
||||||
email: 'sarah.jones@test',
|
email: 'sarah.jones@test',
|
||||||
firstName: 'Sarah',
|
firstName: 'Sarah',
|
||||||
|
@ -75,6 +75,37 @@ test('[Fail] Try invalid email address', async t => {
|
||||||
t.deepEqual(res.body[0].message, 'should match format "emailAddress"');
|
t.deepEqual(res.body[0].message, 'should match format "emailAddress"');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('[Success] Update existing customer', async t => {
|
||||||
|
const customer = {
|
||||||
|
customerId: g.customers[1]._id,
|
||||||
|
email: 'sarah.jones@test.com',
|
||||||
|
firstName: 'Sarah',
|
||||||
|
lastName: 'Jones',
|
||||||
|
address1: '1 Sydney Street',
|
||||||
|
address2: '',
|
||||||
|
country: 'Australia',
|
||||||
|
state: 'NSW',
|
||||||
|
postcode: '2000',
|
||||||
|
phone: '0444444444'
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await g.request
|
||||||
|
.post('/admin/customer/update')
|
||||||
|
.send(customer)
|
||||||
|
.set('apiKey', g.users[0].apiKey)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
t.deepEqual(res.body.message, 'Customer updated');
|
||||||
|
t.deepEqual(res.body.customer.email, customer.email);
|
||||||
|
t.deepEqual(res.body.customer.firstName, customer.firstName);
|
||||||
|
t.deepEqual(res.body.customer.lastName, customer.lastName);
|
||||||
|
t.deepEqual(res.body.customer.address1, customer.address1);
|
||||||
|
t.deepEqual(res.body.customer.country, customer.country);
|
||||||
|
t.deepEqual(res.body.customer.state, customer.state);
|
||||||
|
t.deepEqual(res.body.customer.postcode, customer.postcode);
|
||||||
|
t.deepEqual(res.body.customer.phone, customer.phone);
|
||||||
|
});
|
||||||
|
|
||||||
test('[Success] Get customer list', async t => {
|
test('[Success] Get customer list', async t => {
|
||||||
const res = await g.request
|
const res = await g.request
|
||||||
.get('/admin/customers')
|
.get('/admin/customers')
|
||||||
|
@ -82,7 +113,7 @@ test('[Success] Get customer list', async t => {
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
// Check the returned customers length
|
// Check the returned customers length
|
||||||
t.deepEqual(2, res.body.length);
|
t.deepEqual(3, res.body.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[Success] Filter customers', async t => {
|
test('[Success] Filter customers', async t => {
|
||||||
|
@ -92,7 +123,7 @@ test('[Success] Filter customers', async t => {
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
// Check the returned customers length
|
// Check the returned customers length
|
||||||
t.deepEqual(2, res.body.length);
|
t.deepEqual(3, res.body.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('[Success] Get single customer', async t => {
|
test('[Success] Get single customer', async t => {
|
||||||
|
@ -109,7 +140,7 @@ test('[Fail] Customer login with incorrect email', async t => {
|
||||||
const res = await g.request
|
const res = await g.request
|
||||||
.post('/customer/login_action')
|
.post('/customer/login_action')
|
||||||
.send({
|
.send({
|
||||||
loginEmail: 'test1@test.com',
|
loginEmail: 'test1111@test.com',
|
||||||
loginPassword: 'test'
|
loginPassword: 'test'
|
||||||
})
|
})
|
||||||
.expect(400);
|
.expect(400);
|
||||||
|
|
|
@ -1,49 +1,84 @@
|
||||||
{{> partials/menu}}
|
{{> partials/menu}}
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<form method="post" class="form-horizontal" id="update_form" action="/admin/customer/update" data-toggle="validator">
|
||||||
<h2>Customer</h2>
|
<div class="col-xs-12 col-md-12">
|
||||||
</div>
|
<div class="page-header">
|
||||||
<div class="col-xs-12 col-md-12">
|
<div class="pull-right">
|
||||||
<table class="table-bordered">
|
<button id="frm_edit_product_save" class="btn btn-success">Save customer <i class="fa fa-floppy-o"></i></button>
|
||||||
<tr>
|
</div>
|
||||||
<td><span class="text-info">Email:</span></td>
|
<h2>Customer</h2>
|
||||||
<td>{{result.email}}</td>
|
</div>
|
||||||
</tr>
|
<div class="form-group">
|
||||||
<tr>
|
<label class="col-sm-2 control-label">Email *</label>
|
||||||
<td><span class="text-info">{{ @root.__ "Name" }}:</span></td>
|
<div class="col-sm-10">
|
||||||
<td>{{result.firstName}} {{result.lastName}}</td>
|
<input type="text" class="form-control" name="email" value={{result.email}} required>
|
||||||
</tr>
|
</div>
|
||||||
<tr>
|
</div>
|
||||||
<td><span class="text-info">{{ @root.__ "Address 1" }}:</span></td>
|
<div class="form-group">
|
||||||
<td>{{result.address1}}</td>
|
<label class="col-sm-2 control-label">{{ @root.__ "First name" }} *</label>
|
||||||
</tr>
|
<div class="col-sm-10">
|
||||||
<tr>
|
<input type="text" class="form-control" name="firstName" value={{result.firstName}} required>
|
||||||
<td><span class="text-info">{{ @root.__ "Address 2" }}:</span></td>
|
</div>
|
||||||
<td>{{result.address2}}</td>
|
</div>
|
||||||
</tr>
|
<div class="form-group">
|
||||||
<tr>
|
<label class="col-sm-2 control-label">{{ @root.__ "Last name" }} *</label>
|
||||||
<td><span class="text-info">{{ @root.__ "Country" }}:</span></td>
|
<div class="col-sm-10">
|
||||||
<td>{{result.country}}</td>
|
<input type="text" class="form-control" name="lastName" value={{result.lastName}} required>
|
||||||
</tr>
|
</div>
|
||||||
<tr>
|
</div>
|
||||||
<td><span class="text-info">{{ @root.__ "State" }}:</span></td>
|
<div class="form-group">
|
||||||
<td>{{result.state}}</td>
|
<label class="col-sm-2 control-label">{{ @root.__ "Address 1" }} *</label>
|
||||||
</tr>
|
<div class="col-sm-10">
|
||||||
<tr>
|
<input type="text" class="form-control" name="address1" value={{result.address1}} required>
|
||||||
<td><span class="text-info">{{ @root.__ "Postcode" }}:</span></td>
|
</div>
|
||||||
<td>{{result.postcode}}</td>
|
</div>
|
||||||
</tr>
|
<div class="form-group">
|
||||||
<tr>
|
<label class="col-sm-2 control-label">{{ @root.__ "Address 2" }}</label>
|
||||||
<td><span class="text-info">{{ @root.__ "Phone number" }}:</span></td>
|
<div class="col-sm-10">
|
||||||
<td>{{result.phone}}</td>
|
<input type="text" class="form-control" name="address2" value={{result.address2}}>
|
||||||
</tr>
|
</div>
|
||||||
<tr>
|
</div>
|
||||||
<td><span class="text-info">{{ @root.__ "Creation date" }}:</span></td>
|
<div class="form-group">
|
||||||
<td>{{formatDate result.created "DD/MM/YYYY hh:mmA"}}</td>
|
<label class="col-sm-2 control-label">{{ @root.__ "Country" }} *</label>
|
||||||
</tr>
|
<div class="col-sm-10">
|
||||||
</table>
|
<input type="text" class="form-control" name="country" value={{result.country}} required>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">{{ @root.__ "State" }} *</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" name="state" value={{result.state}} required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">{{ @root.__ "Postcode" }} *</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" name="postcode" value={{result.postcode}} required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">{{ @root.__ "Phone number" }} *</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" name="phone" value={{result.phone}} required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">{{ @root.__ "Password" }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="password" class="form-control" name="password">
|
||||||
|
<p class="help-block">Only populate if wanting to reset the customers password</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">{{ @root.__ "Creation date" }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" value="{{formatDate result.created "DD/MM/YYYY hh:mmA"}}" readonly>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="customerId" value="{{result._id}}">
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" id="productId" value="{{result._id}}">
|
|
||||||
</div>
|
</div>
|
Loading…
Reference in New Issue