From a6645e9d81d7eae10fb990ef2d4be5583747db86 Mon Sep 17 00:00:00 2001 From: Mark Moffat Date: Sat, 16 Nov 2019 21:27:48 +1030 Subject: [PATCH] Update customer route and tests --- bin/testdata.json | 14 +- lib/schema.js | 8 ++ .../{customer.json => editCustomer.json} | 27 ++-- lib/schemas/newCustomer.json | 56 ++++++++ routes/customer.js | 79 ++++++++++- test/specs/customers.js | 39 +++++- views/customer.hbs | 123 +++++++++++------- 7 files changed, 285 insertions(+), 61 deletions(-) rename lib/schemas/{customer.json => editCustomer.json} (58%) create mode 100644 lib/schemas/newCustomer.json diff --git a/bin/testdata.json b/bin/testdata.json index e83f171..9131901 100644 --- a/bin/testdata.json +++ b/bin/testdata.json @@ -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": [ diff --git a/lib/schema.js b/lib/schema.js index 03d9e46..591b625 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -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) => { diff --git a/lib/schemas/customer.json b/lib/schemas/editCustomer.json similarity index 58% rename from lib/schemas/customer.json rename to lib/schemas/editCustomer.json index 7d3d10c..585b91e 100644 --- a/lib/schemas/customer.json +++ b/lib/schemas/editCustomer.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" ] } \ No newline at end of file diff --git a/lib/schemas/newCustomer.json b/lib/schemas/newCustomer.json new file mode 100644 index 0000000..2ac7338 --- /dev/null +++ b/lib/schemas/newCustomer.json @@ -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" + ] +} \ No newline at end of file diff --git a/routes/customer.js b/routes/customer.js index 24cea83..bb6990e 100644 --- a/routes/customer.js +++ b/routes/customer.js @@ -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; diff --git a/test/specs/customers.js b/test/specs/customers.js index c1ff5d6..b467131 100644 --- a/test/specs/customers.js +++ b/test/specs/customers.js @@ -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); diff --git a/views/customer.hbs b/views/customer.hbs index 3d0a68d..0a40970 100644 --- a/views/customer.hbs +++ b/views/customer.hbs @@ -1,49 +1,84 @@ {{> partials/menu}}
-
-

Customer

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Email:{{result.email}}
{{ @root.__ "Name" }}:{{result.firstName}} {{result.lastName}}
{{ @root.__ "Address 1" }}:{{result.address1}}
{{ @root.__ "Address 2" }}:{{result.address2}}
{{ @root.__ "Country" }}:{{result.country}}
{{ @root.__ "State" }}:{{result.state}}
{{ @root.__ "Postcode" }}:{{result.postcode}}
{{ @root.__ "Phone number" }}:{{result.phone}}
{{ @root.__ "Creation date" }}:{{formatDate result.created "DD/MM/YYYY hh:mmA"}}
-
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +

Only populate if wanting to reset the customers password

+
+
+
+ +
+ +
+
+
+ +
- +
\ No newline at end of file