Update customer route and tests
parent
f779ee4baf
commit
a6645e9d81
|
@ -90,10 +90,22 @@
|
|||
"address1" : "1 test street",
|
||||
"address2" : "testvile",
|
||||
"country" : "Netherlands",
|
||||
"state" : "",
|
||||
"state" : "NL",
|
||||
"postcode" : "2000TW",
|
||||
"phone" : "123456789",
|
||||
"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": [
|
||||
|
|
|
@ -18,6 +18,14 @@ const addSchemas = () => {
|
|||
// Amount format
|
||||
const amountRegex = /^[1-9]\d*(\.\d+)?$/;
|
||||
ajv.addFormat('amount', amountRegex);
|
||||
|
||||
ajv.addKeyword('isNotEmpty', {
|
||||
type: 'string',
|
||||
validate: (schema, data) => {
|
||||
return typeof data === 'string' && data.trim() !== '';
|
||||
},
|
||||
errors: false
|
||||
});
|
||||
};
|
||||
|
||||
const validateJson = (schema, json) => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"$id": "customer",
|
||||
"$id": "editCustomer",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": {
|
||||
|
@ -7,28 +7,35 @@
|
|||
"format": "emailAddress"
|
||||
},
|
||||
"firstName": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"isNotEmpty": true
|
||||
},
|
||||
"lastName": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"isNotEmpty": true
|
||||
},
|
||||
"address1": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"isNotEmpty": true
|
||||
},
|
||||
"address2": {
|
||||
"type": "string"
|
||||
},
|
||||
"country": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"isNotEmpty": true
|
||||
},
|
||||
"state": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"isNotEmpty": true
|
||||
},
|
||||
"postcode": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"isNotEmpty": true
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"isNotEmpty": true
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
|
@ -39,11 +46,9 @@
|
|||
"firstName",
|
||||
"lastName",
|
||||
"address1",
|
||||
"address2",
|
||||
"country",
|
||||
"state",
|
||||
"postcode",
|
||||
"phone",
|
||||
"password"
|
||||
"phone"
|
||||
]
|
||||
}
|
|
@ -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()
|
||||
};
|
||||
|
||||
const schemaResult = validateJson('customer', customerObj);
|
||||
const schemaResult = validateJson('newCustomer', customerObj);
|
||||
if(!schemaResult.result){
|
||||
res.status(400).json(schemaResult.errors);
|
||||
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
|
||||
router.get('/admin/customer/view/:id?', restrict, async (req, res) => {
|
||||
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');
|
||||
});
|
||||
|
||||
test('[Fail] Try invalid email address', async t => {
|
||||
test('[Fail] Create with invalid email address', async t => {
|
||||
const customer = {
|
||||
email: 'sarah.jones@test',
|
||||
firstName: 'Sarah',
|
||||
|
@ -75,6 +75,37 @@ test('[Fail] Try invalid email address', async t => {
|
|||
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 => {
|
||||
const res = await g.request
|
||||
.get('/admin/customers')
|
||||
|
@ -82,7 +113,7 @@ test('[Success] Get customer list', async t => {
|
|||
.expect(200);
|
||||
|
||||
// Check the returned customers length
|
||||
t.deepEqual(2, res.body.length);
|
||||
t.deepEqual(3, res.body.length);
|
||||
});
|
||||
|
||||
test('[Success] Filter customers', async t => {
|
||||
|
@ -92,7 +123,7 @@ test('[Success] Filter customers', async t => {
|
|||
.expect(200);
|
||||
|
||||
// Check the returned customers length
|
||||
t.deepEqual(2, res.body.length);
|
||||
t.deepEqual(3, res.body.length);
|
||||
});
|
||||
|
||||
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
|
||||
.post('/customer/login_action')
|
||||
.send({
|
||||
loginEmail: 'test1@test.com',
|
||||
loginEmail: 'test1111@test.com',
|
||||
loginPassword: 'test'
|
||||
})
|
||||
.expect(400);
|
||||
|
|
|
@ -1,49 +1,84 @@
|
|||
{{> partials/menu}}
|
||||
<div class="col-lg-9">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<form method="post" class="form-horizontal" id="update_form" action="/admin/customer/update" data-toggle="validator">
|
||||
<div class="col-xs-12 col-md-12">
|
||||
<div class="page-header">
|
||||
<div class="pull-right">
|
||||
<button id="frm_edit_product_save" class="btn btn-success">Save customer <i class="fa fa-floppy-o"></i></button>
|
||||
</div>
|
||||
<h2>Customer</h2>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-12">
|
||||
<table class="table-bordered">
|
||||
<tr>
|
||||
<td><span class="text-info">Email:</span></td>
|
||||
<td>{{result.email}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="text-info">{{ @root.__ "Name" }}:</span></td>
|
||||
<td>{{result.firstName}} {{result.lastName}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="text-info">{{ @root.__ "Address 1" }}:</span></td>
|
||||
<td>{{result.address1}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="text-info">{{ @root.__ "Address 2" }}:</span></td>
|
||||
<td>{{result.address2}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="text-info">{{ @root.__ "Country" }}:</span></td>
|
||||
<td>{{result.country}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="text-info">{{ @root.__ "State" }}:</span></td>
|
||||
<td>{{result.state}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="text-info">{{ @root.__ "Postcode" }}:</span></td>
|
||||
<td>{{result.postcode}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="text-info">{{ @root.__ "Phone number" }}:</span></td>
|
||||
<td>{{result.phone}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="text-info">{{ @root.__ "Creation date" }}:</span></td>
|
||||
<td>{{formatDate result.created "DD/MM/YYYY hh:mmA"}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">Email *</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="email" value={{result.email}} required>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" id="productId" value="{{result._id}}">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{{ @root.__ "First name" }} *</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="firstName" value={{result.firstName}} required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{{ @root.__ "Last name" }} *</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="lastName" value={{result.lastName}} required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{{ @root.__ "Address 1" }} *</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="address1" value={{result.address1}} required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{{ @root.__ "Address 2" }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="address2" value={{result.address2}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{{ @root.__ "Country" }} *</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="country" value={{result.country}} required>
|
||||
</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>
|
Loading…
Reference in New Issue