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