Added support for returning customers
parent
3730f84796
commit
6076455d06
1
app.js
1
app.js
|
@ -288,6 +288,7 @@ MongoClient.connect(config.databaseConnectionString, {}, (err, client) => {
|
||||||
db.orders = db.collection('orders');
|
db.orders = db.collection('orders');
|
||||||
db.pages = db.collection('pages');
|
db.pages = db.collection('pages');
|
||||||
db.menu = db.collection('menu');
|
db.menu = db.collection('menu');
|
||||||
|
db.customers = db.collection('customers');
|
||||||
|
|
||||||
// add db to app for routes
|
// add db to app for routes
|
||||||
app.db = db;
|
app.db = db;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"nodemailer": "^4.4.1",
|
"nodemailer": "^4.4.1",
|
||||||
"numeral": "^2.0.6",
|
"numeral": "^2.0.6",
|
||||||
"paypal-rest-sdk": "^1.6.9",
|
"paypal-rest-sdk": "^1.6.9",
|
||||||
|
"rand-token": "^0.4.0",
|
||||||
"rimraf": "^2.6.2",
|
"rimraf": "^2.6.2",
|
||||||
"sitemap": "^1.6.0",
|
"sitemap": "^1.6.0",
|
||||||
"stripe": "^5.4.0",
|
"stripe": "^5.4.0",
|
||||||
|
|
|
@ -294,6 +294,79 @@ $(document).ready(function (){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#customerLogout').on('click', function(e){
|
||||||
|
$.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/customer/logout',
|
||||||
|
data: {}
|
||||||
|
})
|
||||||
|
.done(function(msg){
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#createCustomerAccount').validator().on('click', function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
if($('#shipping-form').validator('validate').has('.has-error').length === 0){
|
||||||
|
$.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/customer/create',
|
||||||
|
data: {
|
||||||
|
email: $('#shipEmail').val(),
|
||||||
|
firstName: $('#shipFirstname').val(),
|
||||||
|
lastName: $('#shipLastname').val(),
|
||||||
|
address1: $('#shipAddr1').val(),
|
||||||
|
address2: $('#shipAddr2').val(),
|
||||||
|
country: $('#shipCountry').val(),
|
||||||
|
state: $('#shipState').val(),
|
||||||
|
postcode: $('#shipPostcode').val(),
|
||||||
|
phone: $('#shipPhoneNumber').val(),
|
||||||
|
password: $('#newCustomerPassword').val()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.done(function(msg){
|
||||||
|
// Just reload to fill in the form from session
|
||||||
|
location.reload();
|
||||||
|
})
|
||||||
|
.fail(function(msg){
|
||||||
|
showNotification(msg.responseJSON.err, 'danger');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// call update settings API
|
||||||
|
$('#customerLogin').on('click', function(e){
|
||||||
|
if(!e.isDefaultPrevented()){
|
||||||
|
e.preventDefault();
|
||||||
|
$.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/customer/login_action',
|
||||||
|
data: {
|
||||||
|
loginEmail: $('#customerLoginEmail').val(),
|
||||||
|
loginPassword: $('#customerLoginPassword').val()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.done(function(msg){
|
||||||
|
var customer = msg.customer;
|
||||||
|
// Fill in customer form
|
||||||
|
$('#shipEmail').val(customer.email);
|
||||||
|
$('#shipFirstname').val(customer.firstName);
|
||||||
|
$('#shipLastname').val(customer.lastName);
|
||||||
|
$('#shipAddr1').val(customer.address1);
|
||||||
|
$('#shipAddr2').val(customer.address2);
|
||||||
|
$('#shipCountry').val(customer.country);
|
||||||
|
$('#shipState').val(customer.state);
|
||||||
|
$('#shipPostcode').val(customer.postcode);
|
||||||
|
$('#shipPhoneNumber').val(customer.phone);
|
||||||
|
location.reload();
|
||||||
|
})
|
||||||
|
.fail(function(msg){
|
||||||
|
showNotification(msg.responseJSON.err, 'danger');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
$(document).on('click', '.image-next', function(e){
|
$(document).on('click', '.image-next', function(e){
|
||||||
var thumbnails = $('.thumbnail-image');
|
var thumbnails = $('.thumbnail-image');
|
||||||
var index = 0;
|
var index = 0;
|
||||||
|
@ -473,7 +546,7 @@ $(document).ready(function (){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// applies an product filter
|
// applies an product filter
|
||||||
$(document).on('click', '#btn_product_filter', function(e){
|
$(document).on('click', '#btn_product_filter', function(e){
|
||||||
if($('#product_filter').val() !== ''){
|
if($('#product_filter').val() !== ''){
|
||||||
window.location.href = '/admin/products/filter/' + $('#product_filter').val();
|
window.location.href = '/admin/products/filter/' + $('#product_filter').val();
|
||||||
|
@ -491,22 +564,21 @@ $(document).ready(function (){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// applies an product filter
|
||||||
|
$(document).on('click', '#btn_customer_filter', function(e){
|
||||||
|
if($('#customer_filter').val() !== ''){
|
||||||
|
window.location.href = '/admin/customers/filter/' + $('#customer_filter').val();
|
||||||
|
}else{
|
||||||
|
showNotification('Please enter a keyword to filter', 'danger');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// resets the order filter
|
// resets the order filter
|
||||||
$(document).on('click', '#btn_search_reset', function(e){
|
$(document).on('click', '#btn_search_reset', function(e){
|
||||||
window.location.replace('/');
|
window.location.replace('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
// resets the product filter
|
// search button click event
|
||||||
$(document).on('click', '#btn_product_reset', function(e){
|
|
||||||
window.location.href = '/admin/products';
|
|
||||||
});
|
|
||||||
|
|
||||||
// resets the order filter
|
|
||||||
$(document).on('click', '#btn_order_reset', function(e){
|
|
||||||
window.location.href = '/admin/orders';
|
|
||||||
});
|
|
||||||
|
|
||||||
// search button click event
|
|
||||||
$(document).on('click', '#btn_search', function(e){
|
$(document).on('click', '#btn_search', function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if($('#frm_search').val().trim() === ''){
|
if($('#frm_search').val().trim() === ''){
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -6,59 +6,93 @@
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<div class="panel panel-default" style="margin-top: 30px;">
|
<div class="panel panel-default" style="margin-top: 30px;">
|
||||||
<div class="panel-heading">Customer details</div>
|
<div class="panel-heading">Customer details</div>
|
||||||
|
{{#unless session.customer}}
|
||||||
|
<div class="panel-body customer-details-login">
|
||||||
|
<p>Existing customer</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="email" class="form-control" id="customerLoginEmail" name="loginEmail" minlength="5" placeholder="Email address" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="password" class="form-control" id="customerLoginPassword" name="loginPassword" minlength="5" placeholder="Password" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<a href="/customer/forgotten" class="btn btn-default pull-left">Forgotten</a>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button id="customerLogin" class="btn btn-success pull-right" type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
<div class="panel-body customer-details">
|
<div class="panel-body customer-details">
|
||||||
|
{{#if session.customer}}
|
||||||
|
<div class="col-xs-12 col-md-12">
|
||||||
|
<button id="customerLogout" class="btn btn-sm btn-success pull-right">Change customer</button>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
<form id="shipping-form" class="shipping-form" action="/{{config.paymentGateway}}/checkout_action" method="post" role="form" data-toggle="validator" novalidate="false">
|
<form id="shipping-form" class="shipping-form" action="/{{config.paymentGateway}}/checkout_action" method="post" role="form" data-toggle="validator" novalidate="false">
|
||||||
<div class="col-xs-12 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="email" class="form-control customerDetails" id="shipEmail" name="shipEmail" minlength="5" placeholder="Email address" required>
|
<input type="email" class="form-control customerDetails" id="shipEmail" name="shipEmail" minlength="5" placeholder="Email address" value="{{session.customer.email}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-6">
|
<div class="col-xs-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipFirstname" name="shipFirstname" placeholder="First name" required>
|
<input type="text" class="form-control customerDetails" id="shipFirstname" name="shipFirstname" placeholder="First name" value="{{session.customer.firstName}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-6">
|
<div class="col-xs-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipLastname" name="shipLastname" placeholder="Last name" required>
|
<input type="text" class="form-control customerDetails" id="shipLastname" name="shipLastname" placeholder="Last name" value="{{session.customer.lastName}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipAddr1" name="shipAddr1" placeholder="Address 1" required>
|
<input type="text" class="form-control customerDetails" id="shipAddr1" name="shipAddr1" placeholder="Address 1" value="{{session.customer.address1}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipAddr2" name="shipAddr2" placeholder="Address 2 (optional)">
|
<input type="text" class="form-control customerDetails" id="shipAddr2" name="shipAddr2" placeholder="Address 2 (optional)" value="{{session.customer.address1}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-4">
|
<div class="col-xs-12 col-md-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipCountry" name="shipCountry" placeholder="Country" required>
|
<input type="text" class="form-control customerDetails" id="shipCountry" name="shipCountry" placeholder="Country" value="{{session.customer.country}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-4">
|
<div class="col-xs-12 col-md-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipState" name="shipState" placeholder="State" required>
|
<input type="text" class="form-control customerDetails" id="shipState" name="shipState" placeholder="State" value="{{session.customer.state}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-4">
|
<div class="col-xs-12 col-md-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="number" class="form-control customerDetails" id="shipPostcode" name="shipPostcode" placeholder="Post code" required>
|
<input type="text" class="form-control customerDetails" id="shipPostcode" name="shipPostcode" placeholder="Post code" value="{{session.customer.postcode}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="number" class="form-control customerDetails" id="shipPhoneNumber" name="shipPhoneNumber" placeholder="Phone number (optional)">
|
<input type="number" class="form-control customerDetails" id="shipPhoneNumber" name="shipPhoneNumber" placeholder="Phone number" value="{{session.customer.phone}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{#if session.customer}}
|
||||||
{{#ifCond config.paymentGateway '==' 'paypal'}}
|
{{#ifCond config.paymentGateway '==' 'paypal'}}
|
||||||
<div class="paypal_button col-xs-12 col-md-12 text-center">
|
<div class="paypal_button col-xs-12 col-md-12 text-center">
|
||||||
<button id="checkout_paypal" class="btn btn-success" type="submit"><i class="fa fa-cc-paypal fa-lg" aria-hidden="true"></i> Pay with PayPal <i class="fa fa-cc-paypal fa-lg" aria-hidden="true"></i></button>
|
<button id="checkout_paypal" class="btn btn-success" type="submit"><i class="fa fa-cc-paypal fa-lg" aria-hidden="true"></i> Pay with PayPal <i class="fa fa-cc-paypal fa-lg" aria-hidden="true"></i></button>
|
||||||
</div>
|
</div>
|
||||||
{{/ifCond}}
|
{{/ifCond}}
|
||||||
|
{{/if}}
|
||||||
|
{{#unless session.customer}}
|
||||||
|
<div class="col-xs-12 col-md-12">
|
||||||
|
<p class="text-muted">Enter a password to create an account for next time</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="password" class="form-control customerDetails" id="newCustomerPassword" name="newCustomerPassword" placeholder="Password" required>
|
||||||
|
</div>
|
||||||
|
<a id="createCustomerAccount" class="btn btn-success pull-right">Create account</a>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
</form>
|
</form>
|
||||||
|
{{#if session.customer}}
|
||||||
{{#ifCond config.paymentGateway '==' 'stripe'}}
|
{{#ifCond config.paymentGateway '==' 'stripe'}}
|
||||||
<div class="col-xs-12 col-md-12 text-center">
|
<div class="col-xs-12 col-md-12 text-center">
|
||||||
<form method="POST" id="payment-form">
|
<form method="POST" id="payment-form">
|
||||||
|
@ -82,6 +116,8 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{/ifCond}}
|
{{/ifCond}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
138
routes/admin.js
138
routes/admin.js
|
@ -13,7 +13,7 @@ router.get('/', common.restrict, (req, res, next) => {
|
||||||
|
|
||||||
// Admin section
|
// Admin section
|
||||||
router.get('/orders', common.restrict, (req, res, next) => {
|
router.get('/orders', common.restrict, (req, res, next) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
// Top 10 products
|
// Top 10 products
|
||||||
common.dbQuery(db.orders, {}, {'orderDate': -1}, 10, (err, orders) => {
|
common.dbQuery(db.orders, {}, {'orderDate': -1}, 10, (err, orders) => {
|
||||||
|
@ -35,7 +35,7 @@ router.get('/orders', common.restrict, (req, res, next) => {
|
||||||
|
|
||||||
// Admin section
|
// Admin section
|
||||||
router.get('/orders/bystatus/:orderstatus', common.restrict, (req, res, next) => {
|
router.get('/orders/bystatus/:orderstatus', common.restrict, (req, res, next) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
if(typeof req.params.orderstatus === 'undefined'){
|
if(typeof req.params.orderstatus === 'undefined'){
|
||||||
res.redirect('/admin/orders');
|
res.redirect('/admin/orders');
|
||||||
|
@ -65,7 +65,7 @@ router.get('/orders/bystatus/:orderstatus', common.restrict, (req, res, next) =>
|
||||||
|
|
||||||
// render the editor
|
// render the editor
|
||||||
router.get('/order/view/:id', common.restrict, (req, res) => {
|
router.get('/order/view/:id', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
db.orders.findOne({_id: common.getId(req.params.id)}, (err, result) => {
|
db.orders.findOne({_id: common.getId(req.params.id)}, (err, result) => {
|
||||||
if(err){
|
if(err){
|
||||||
console.info(err.stack);
|
console.info(err.stack);
|
||||||
|
@ -91,7 +91,7 @@ router.get('/order/view/:id', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// Admin section
|
// Admin section
|
||||||
router.get('/orders/filter/:search', common.restrict, (req, res, next) => {
|
router.get('/orders/filter/:search', common.restrict, (req, res, next) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let searchTerm = req.params.search;
|
let searchTerm = req.params.search;
|
||||||
let ordersIndex = req.app.ordersIndex;
|
let ordersIndex = req.app.ordersIndex;
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ router.get('/orders/filter/:search', common.restrict, (req, res, next) => {
|
||||||
|
|
||||||
// order product
|
// order product
|
||||||
router.get('/order/delete/:id', common.restrict, (req, res) => {
|
router.get('/order/delete/:id', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
// remove the article
|
// remove the article
|
||||||
db.orders.remove({_id: common.getId(req.params.id)}, {}, (err, numRemoved) => {
|
db.orders.remove({_id: common.getId(req.params.id)}, {}, (err, numRemoved) => {
|
||||||
|
@ -141,7 +141,7 @@ router.get('/order/delete/:id', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// update order status
|
// update order status
|
||||||
router.post('/order/statusupdate', common.restrict, (req, res) => {
|
router.post('/order/statusupdate', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
db.orders.update({_id: common.getId(req.body.order_id)}, {$set: {orderStatus: req.body.status}}, {multi: false}, (err, numReplaced) => {
|
db.orders.update({_id: common.getId(req.body.order_id)}, {$set: {orderStatus: req.body.status}}, {multi: false}, (err, numReplaced) => {
|
||||||
if(err){
|
if(err){
|
||||||
console.info(err.stack);
|
console.info(err.stack);
|
||||||
|
@ -152,7 +152,7 @@ router.post('/order/statusupdate', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// Admin section
|
// Admin section
|
||||||
router.get('/products', common.restrict, (req, res, next) => {
|
router.get('/products', common.restrict, (req, res, next) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
// get the top results
|
// get the top results
|
||||||
common.dbQuery(db.products, {}, {'productAddedDate': -1}, 10, (err, topResults) => {
|
common.dbQuery(db.products, {}, {'productAddedDate': -1}, 10, (err, topResults) => {
|
||||||
if(err){
|
if(err){
|
||||||
|
@ -173,7 +173,7 @@ router.get('/products', common.restrict, (req, res, next) => {
|
||||||
|
|
||||||
// Admin section
|
// Admin section
|
||||||
router.post('/product/addtocart', (req, res, next) => {
|
router.post('/product/addtocart', (req, res, next) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let productQuantity = req.body.productQuantity ? parseInt(req.body.productQuantity) : 1;
|
let productQuantity = req.body.productQuantity ? parseInt(req.body.productQuantity) : 1;
|
||||||
|
|
||||||
// setup cart object if it doesn't exist
|
// setup cart object if it doesn't exist
|
||||||
|
@ -240,7 +240,7 @@ router.post('/product/addtocart', (req, res, next) => {
|
||||||
|
|
||||||
// Updates a single product quantity
|
// Updates a single product quantity
|
||||||
router.post('/product/updatecart', (req, res, next) => {
|
router.post('/product/updatecart', (req, res, next) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let cartItems = JSON.parse(req.body.items);
|
let cartItems = JSON.parse(req.body.items);
|
||||||
let hasError = false;
|
let hasError = false;
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ router.post('/product/emptycart', (req, res, next) => {
|
||||||
|
|
||||||
// Admin section
|
// Admin section
|
||||||
router.get('/products/filter/:search', common.restrict, (req, res, next) => {
|
router.get('/products/filter/:search', common.restrict, (req, res, next) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let searchTerm = req.params.search;
|
let searchTerm = req.params.search;
|
||||||
let productsIndex = req.app.productsIndex;
|
let productsIndex = req.app.productsIndex;
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@ router.get('/product/new', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// insert new product form action
|
// insert new product form action
|
||||||
router.post('/product/insert', common.restrict, (req, res) => {
|
router.post('/product/insert', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
let doc = {
|
let doc = {
|
||||||
productPermalink: req.body.frmProductPermalink,
|
productPermalink: req.body.frmProductPermalink,
|
||||||
|
@ -429,7 +429,7 @@ router.post('/product/insert', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// render the editor
|
// render the editor
|
||||||
router.get('/product/edit/:id', common.restrict, (req, res) => {
|
router.get('/product/edit/:id', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
common.getImages(req.params.id, req, res, (images) => {
|
common.getImages(req.params.id, req, res, (images) => {
|
||||||
db.products.findOne({_id: common.getId(req.params.id)}, (err, result) => {
|
db.products.findOne({_id: common.getId(req.params.id)}, (err, result) => {
|
||||||
|
@ -460,7 +460,7 @@ router.get('/product/edit/:id', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// Update an existing product form action
|
// Update an existing product form action
|
||||||
router.post('/product/update', common.restrict, (req, res) => {
|
router.post('/product/update', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
db.products.findOne({_id: common.getId(req.body.frmProductId)}, (err, product) => {
|
db.products.findOne({_id: common.getId(req.body.frmProductId)}, (err, product) => {
|
||||||
if(err){
|
if(err){
|
||||||
|
@ -540,7 +540,7 @@ router.post('/product/update', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// delete product
|
// delete product
|
||||||
router.get('/product/delete/:id', common.restrict, (req, res) => {
|
router.get('/product/delete/:id', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let rimraf = require('rimraf');
|
let rimraf = require('rimraf');
|
||||||
|
|
||||||
// remove the article
|
// remove the article
|
||||||
|
@ -568,7 +568,7 @@ router.get('/product/delete/:id', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// users
|
// users
|
||||||
router.get('/users', common.restrict, (req, res) => {
|
router.get('/users', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
db.users.find({}).toArray((err, users) => {
|
db.users.find({}).toArray((err, users) => {
|
||||||
if(err){
|
if(err){
|
||||||
console.info(err.stack);
|
console.info(err.stack);
|
||||||
|
@ -589,7 +589,7 @@ router.get('/users', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// edit user
|
// edit user
|
||||||
router.get('/user/edit/:id', common.restrict, (req, res) => {
|
router.get('/user/edit/:id', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
db.users.findOne({_id: common.getId(req.params.id)}, (err, user) => {
|
db.users.findOne({_id: common.getId(req.params.id)}, (err, user) => {
|
||||||
if(err){
|
if(err){
|
||||||
console.info(err.stack);
|
console.info(err.stack);
|
||||||
|
@ -618,7 +618,7 @@ router.get('/user/edit/:id', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// update a user
|
// update a user
|
||||||
router.post('/user/update', common.restrict, (req, res) => {
|
router.post('/user/update', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let bcrypt = req.bcrypt;
|
let bcrypt = req.bcrypt;
|
||||||
|
|
||||||
let isAdmin = req.body.user_admin === 'on' ? 'true' : 'false';
|
let isAdmin = req.body.user_admin === 'on' ? 'true' : 'false';
|
||||||
|
@ -666,7 +666,7 @@ router.post('/user/update', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// insert a user
|
// insert a user
|
||||||
router.post('/setup_action', (req, res) => {
|
router.post('/setup_action', (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let bcrypt = req.bcrypt;
|
let bcrypt = req.bcrypt;
|
||||||
|
|
||||||
let doc = {
|
let doc = {
|
||||||
|
@ -704,7 +704,7 @@ router.post('/setup_action', (req, res) => {
|
||||||
|
|
||||||
// insert a user
|
// insert a user
|
||||||
router.post('/user/insert', common.restrict, (req, res) => {
|
router.post('/user/insert', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let bcrypt = req.bcrypt;
|
let bcrypt = req.bcrypt;
|
||||||
let url = require('url');
|
let url = require('url');
|
||||||
|
|
||||||
|
@ -765,6 +765,79 @@ router.post('/user/insert', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// render the customer view
|
||||||
|
router.get('/customer/view/:id?', common.restrict, (req, res) => {
|
||||||
|
const db = req.app.db;
|
||||||
|
|
||||||
|
console.log('here');
|
||||||
|
|
||||||
|
db.customers.findOne({_id: common.getId(req.params.id)}, (err, result) => {
|
||||||
|
if(err){
|
||||||
|
console.info(err.stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.render('customer', {
|
||||||
|
title: 'View customer',
|
||||||
|
result: result,
|
||||||
|
admin: true,
|
||||||
|
session: req.session,
|
||||||
|
message: common.clearSessionValue(req.session, 'message'),
|
||||||
|
messageType: common.clearSessionValue(req.session, 'messageType'),
|
||||||
|
config: common.getConfig(),
|
||||||
|
editor: true,
|
||||||
|
helpers: req.handlebars.helpers
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// customers list
|
||||||
|
router.get('/customers', common.restrict, (req, res) => {
|
||||||
|
const db = req.app.db;
|
||||||
|
|
||||||
|
db.customers.find({}).limit(20).sort({created: -1}).toArray((err, customers) => {
|
||||||
|
res.render('customers', {
|
||||||
|
title: 'Customers - List',
|
||||||
|
admin: true,
|
||||||
|
customers: customers,
|
||||||
|
session: req.session,
|
||||||
|
helpers: req.handlebars.helpers,
|
||||||
|
message: common.clearSessionValue(req.session, 'message'),
|
||||||
|
messageType: common.clearSessionValue(req.session, 'messageType'),
|
||||||
|
config: common.getConfig()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filtered customers list
|
||||||
|
router.get('/customers/filter/:search', common.restrict, (req, res, next) => {
|
||||||
|
const db = req.app.db;
|
||||||
|
let searchTerm = req.params.search;
|
||||||
|
let customersIndex = req.app.customersIndex;
|
||||||
|
|
||||||
|
let lunrIdArray = [];
|
||||||
|
customersIndex.search(searchTerm).forEach((id) => {
|
||||||
|
lunrIdArray.push(common.getId(id.ref));
|
||||||
|
});
|
||||||
|
|
||||||
|
// we search on the lunr indexes
|
||||||
|
db.customers.find({_id: {$in: lunrIdArray}}).sort({created: -1}).toArray((err, customers) => {
|
||||||
|
if(err){
|
||||||
|
console.error(colors.red('Error searching', err));
|
||||||
|
}
|
||||||
|
res.render('customers', {
|
||||||
|
title: 'Customer results',
|
||||||
|
customers: customers,
|
||||||
|
admin: true,
|
||||||
|
config: common.getConfig(),
|
||||||
|
session: req.session,
|
||||||
|
searchTerm: searchTerm,
|
||||||
|
message: common.clearSessionValue(req.session, 'message'),
|
||||||
|
messageType: common.clearSessionValue(req.session, 'messageType'),
|
||||||
|
helpers: req.handlebars.helpers
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// users new
|
// users new
|
||||||
router.get('/user/new', common.restrict, (req, res) => {
|
router.get('/user/new', common.restrict, (req, res) => {
|
||||||
res.render('user_new', {
|
res.render('user_new', {
|
||||||
|
@ -780,7 +853,7 @@ router.get('/user/new', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// delete user
|
// delete user
|
||||||
router.get('/user/delete/:id', common.restrict, (req, res) => {
|
router.get('/user/delete/:id', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
if(req.session.isAdmin === 'true'){
|
if(req.session.isAdmin === 'true'){
|
||||||
db.users.remove({_id: common.getId(req.params.id)}, {}, (err, numRemoved) => {
|
db.users.remove({_id: common.getId(req.params.id)}, {}, (err, numRemoved) => {
|
||||||
if(err){
|
if(err){
|
||||||
|
@ -825,7 +898,7 @@ router.post('/settings/update', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// settings update
|
// settings update
|
||||||
router.post('/settings/option/remove', common.restrict, (req, res) => {
|
router.post('/settings/option/remove', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
db.products.findOne({_id: common.getId(req.body.productId)}, (err, product) => {
|
db.products.findOne({_id: common.getId(req.body.productId)}, (err, product) => {
|
||||||
if(err){
|
if(err){
|
||||||
console.info(err.stack);
|
console.info(err.stack);
|
||||||
|
@ -852,7 +925,7 @@ router.post('/settings/option/remove', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// settings update
|
// settings update
|
||||||
router.get('/settings/menu', common.restrict, async (req, res) => {
|
router.get('/settings/menu', common.restrict, async (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
res.render('settings_menu', {
|
res.render('settings_menu', {
|
||||||
title: 'Cart menu',
|
title: 'Cart menu',
|
||||||
session: req.session,
|
session: req.session,
|
||||||
|
@ -867,7 +940,7 @@ router.get('/settings/menu', common.restrict, async (req, res) => {
|
||||||
|
|
||||||
// settings page list
|
// settings page list
|
||||||
router.get('/settings/pages', common.restrict, (req, res) => {
|
router.get('/settings/pages', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
common.dbQuery(db.pages, {}, null, null, async (err, pages) => {
|
common.dbQuery(db.pages, {}, null, null, async (err, pages) => {
|
||||||
if(err){
|
if(err){
|
||||||
console.info(err.stack);
|
console.info(err.stack);
|
||||||
|
@ -889,7 +962,7 @@ router.get('/settings/pages', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// settings pages new
|
// settings pages new
|
||||||
router.get('/settings/pages/new', common.restrict, async (req, res) => {
|
router.get('/settings/pages/new', common.restrict, async (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
res.render('settings_page_edit', {
|
res.render('settings_page_edit', {
|
||||||
title: 'Static pages',
|
title: 'Static pages',
|
||||||
|
@ -906,7 +979,7 @@ router.get('/settings/pages/new', common.restrict, async (req, res) => {
|
||||||
|
|
||||||
// settings pages editor
|
// settings pages editor
|
||||||
router.get('/settings/pages/edit/:page', common.restrict, (req, res) => {
|
router.get('/settings/pages/edit/:page', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
db.pages.findOne({_id: common.getId(req.params.page)}, async (err, page) => {
|
db.pages.findOne({_id: common.getId(req.params.page)}, async (err, page) => {
|
||||||
if(err){
|
if(err){
|
||||||
console.info(err.stack);
|
console.info(err.stack);
|
||||||
|
@ -942,7 +1015,7 @@ router.get('/settings/pages/edit/:page', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// settings update page
|
// settings update page
|
||||||
router.post('/settings/pages/update', common.restrict, (req, res) => {
|
router.post('/settings/pages/update', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
let doc = {
|
let doc = {
|
||||||
pageName: req.body.pageName,
|
pageName: req.body.pageName,
|
||||||
|
@ -982,7 +1055,7 @@ router.post('/settings/pages/update', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// settings delete page
|
// settings delete page
|
||||||
router.get('/settings/pages/delete/:page', common.restrict, (req, res) => {
|
router.get('/settings/pages/delete/:page', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
db.pages.remove({_id: common.getId(req.params.page)}, {}, (err, numRemoved) => {
|
db.pages.remove({_id: common.getId(req.params.page)}, {}, (err, numRemoved) => {
|
||||||
if(err){
|
if(err){
|
||||||
req.session.message = 'Error deleting page. Please try again.';
|
req.session.message = 'Error deleting page. Please try again.';
|
||||||
|
@ -1040,7 +1113,7 @@ router.post('/settings/menu/save_order', common.restrict, (req, res) => {
|
||||||
router.post('/api/validate_permalink', (req, res) => {
|
router.post('/api/validate_permalink', (req, res) => {
|
||||||
// if doc id is provided it checks for permalink in any products other that one provided,
|
// if doc id is provided it checks for permalink in any products other that one provided,
|
||||||
// else it just checks for any products with that permalink
|
// else it just checks for any products with that permalink
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
let query = {};
|
let query = {};
|
||||||
if(typeof req.body.docId === 'undefined' || req.body.docId === ''){
|
if(typeof req.body.docId === 'undefined' || req.body.docId === ''){
|
||||||
|
@ -1065,7 +1138,7 @@ router.post('/api/validate_permalink', (req, res) => {
|
||||||
|
|
||||||
// update the published state based on an ajax call from the frontend
|
// update the published state based on an ajax call from the frontend
|
||||||
router.post('/product/published_state', common.restrict, (req, res) => {
|
router.post('/product/published_state', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
db.products.update({_id: common.getId(req.body.id)}, {$set: {productPublished: req.body.state}}, {multi: false}, (err, numReplaced) => {
|
db.products.update({_id: common.getId(req.body.id)}, {$set: {productPublished: req.body.state}}, {multi: false}, (err, numReplaced) => {
|
||||||
if(err){
|
if(err){
|
||||||
|
@ -1081,7 +1154,7 @@ router.post('/product/published_state', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// set as main product image
|
// set as main product image
|
||||||
router.post('/product/setasmainimage', common.restrict, (req, res) => {
|
router.post('/product/setasmainimage', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
// update the productImage to the db
|
// update the productImage to the db
|
||||||
db.products.update({_id: common.getId(req.body.product_id)}, {$set: {productImage: req.body.productImage}}, {multi: false}, (err, numReplaced) => {
|
db.products.update({_id: common.getId(req.body.product_id)}, {$set: {productImage: req.body.productImage}}, {multi: false}, (err, numReplaced) => {
|
||||||
|
@ -1095,7 +1168,7 @@ router.post('/product/setasmainimage', common.restrict, (req, res) => {
|
||||||
|
|
||||||
// deletes a product image
|
// deletes a product image
|
||||||
router.post('/product/deleteimage', common.restrict, (req, res) => {
|
router.post('/product/deleteimage', common.restrict, (req, res) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let fs = require('fs');
|
let fs = require('fs');
|
||||||
let path = require('path');
|
let path = require('path');
|
||||||
|
|
||||||
|
@ -1136,7 +1209,7 @@ router.post('/product/deleteimage', common.restrict, (req, res) => {
|
||||||
let multer = require('multer');
|
let multer = require('multer');
|
||||||
let upload = multer({dest: 'public/uploads/'});
|
let upload = multer({dest: 'public/uploads/'});
|
||||||
router.post('/file/upload', common.restrict, upload.single('upload_file'), (req, res, next) => {
|
router.post('/file/upload', common.restrict, upload.single('upload_file'), (req, res, next) => {
|
||||||
let db = req.app.db;
|
const db = req.app.db;
|
||||||
let fs = require('fs');
|
let fs = require('fs');
|
||||||
let path = require('path');
|
let path = require('path');
|
||||||
|
|
||||||
|
@ -1195,6 +1268,7 @@ router.post('/file/upload', common.restrict, upload.single('upload_file'), (req,
|
||||||
// delete a file via ajax request
|
// delete a file via ajax request
|
||||||
router.post('/testEmail', common.restrict, (req, res) => {
|
router.post('/testEmail', common.restrict, (req, res) => {
|
||||||
let config = common.getConfig();
|
let config = common.getConfig();
|
||||||
|
// TODO: Should fix this to properly handle result
|
||||||
common.sendEmail(config.emailAddress, 'expressCart test email', 'Your email settings are working');
|
common.sendEmail(config.emailAddress, 'expressCart test email', 'Your email settings are working');
|
||||||
res.status(200).json('Test email sent');
|
res.status(200).json('Test email sent');
|
||||||
});
|
});
|
||||||
|
|
206
routes/index.js
206
routes/index.js
|
@ -2,6 +2,7 @@ const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const colors = require('colors');
|
const colors = require('colors');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const randtoken = require('rand-token');
|
||||||
const common = require('./common');
|
const common = require('./common');
|
||||||
|
|
||||||
router.get('/payment/:orderId', async (req, res, next) => {
|
router.get('/payment/:orderId', async (req, res, next) => {
|
||||||
|
@ -236,6 +237,211 @@ router.post('/login_action', (req, res) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// insert a customer
|
||||||
|
router.post('/customer/create', (req, res) => {
|
||||||
|
const db = req.app.db;
|
||||||
|
const bcrypt = req.bcrypt;
|
||||||
|
|
||||||
|
let doc = {
|
||||||
|
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,
|
||||||
|
password: bcrypt.hashSync(req.body.password),
|
||||||
|
created: new Date()
|
||||||
|
};
|
||||||
|
|
||||||
|
// check for existing customer
|
||||||
|
db.customers.findOne({email: req.body.email}, (err, customer) => {
|
||||||
|
if(customer){
|
||||||
|
res.status(404).json({
|
||||||
|
err: 'A customer already exists with that email address'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// email is ok to be used.
|
||||||
|
db.customers.insertOne(doc, (err, newCustomer) => {
|
||||||
|
if(err){
|
||||||
|
if(newCustomer){
|
||||||
|
console.error(colors.red('Failed to insert customer: ' + err));
|
||||||
|
res.status(400).json({
|
||||||
|
err: 'A customer already exists with that email address'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.error(colors.red('Failed to insert customer: ' + err));
|
||||||
|
res.status(400).json({
|
||||||
|
err: 'Customer creation failed.'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customer creation successful
|
||||||
|
req.session.customer = newCustomer.ops[0];
|
||||||
|
res.status(200).json({
|
||||||
|
message: 'Successfully logged in',
|
||||||
|
customer: newCustomer
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// login the customer and check the password
|
||||||
|
router.post('/customer/login_action', (req, res) => {
|
||||||
|
let db = req.app.db;
|
||||||
|
let bcrypt = req.bcrypt;
|
||||||
|
|
||||||
|
db.customers.findOne({email: req.body.loginEmail}, (err, customer) => {
|
||||||
|
if(err){
|
||||||
|
// An error accurred
|
||||||
|
return res.status(400).json({
|
||||||
|
err: 'Access denied. Check password and try again.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if customer exists with that email
|
||||||
|
if(customer === undefined || customer === null){
|
||||||
|
return res.status(400).json({
|
||||||
|
err: 'A customer with that email does not exist.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// we have a customer under that email so we compare the password
|
||||||
|
if(bcrypt.compareSync(req.body.loginPassword, customer.password) === false){
|
||||||
|
// password is not correct
|
||||||
|
return res.status(400).json({
|
||||||
|
err: 'Access denied. Check password and try again.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customer login successful
|
||||||
|
req.session.customer = customer;
|
||||||
|
return res.status(200).json({
|
||||||
|
message: 'Successfully logged in',
|
||||||
|
customer: customer
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// customer forgotten password
|
||||||
|
router.get('/customer/forgotten', (req, res) => {
|
||||||
|
res.render('forgotten', {
|
||||||
|
title: 'Forgotten',
|
||||||
|
route: 'customer',
|
||||||
|
forgotType: 'customer',
|
||||||
|
config: common.getConfig(),
|
||||||
|
helpers: req.handlebars.helpers,
|
||||||
|
message: common.clearSessionValue(req.session, 'message'),
|
||||||
|
messageType: common.clearSessionValue(req.session, 'messageType'),
|
||||||
|
showFooter: 'showFooter'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// forgotten password
|
||||||
|
router.post('/customer/forgotten_action', (req, res) => {
|
||||||
|
const db = req.app.db;
|
||||||
|
const config = common.getConfig();
|
||||||
|
let passwordToken = randtoken.generate(30);
|
||||||
|
|
||||||
|
// find the user
|
||||||
|
db.customers.findOne({email: req.body.email}, (err, customer) => {
|
||||||
|
// if we have a customer, set a token, expiry and email it
|
||||||
|
if(customer){
|
||||||
|
let tokenExpiry = Date.now() + 3600000;
|
||||||
|
db.customers.update({email: req.body.email}, {$set: {resetToken: passwordToken, resetTokenExpiry: tokenExpiry}}, {multi: false}, (err, numReplaced) => {
|
||||||
|
// send forgotten password email
|
||||||
|
let mailOpts = {
|
||||||
|
to: req.body.email,
|
||||||
|
subject: 'Forgotten password request',
|
||||||
|
body: `You are receiving this because you (or someone else) have requested the reset of the password for your user account.\n\n
|
||||||
|
Please click on the following link, or paste this into your browser to complete the process:\n\n
|
||||||
|
${config.baseUrl}/customer/reset/${passwordToken}\n\n
|
||||||
|
If you did not request this, please ignore this email and your password will remain unchanged.\n`
|
||||||
|
};
|
||||||
|
|
||||||
|
// send the email with token to the user
|
||||||
|
// TODO: Should fix this to properly handle result
|
||||||
|
common.sendEmail(mailOpts.to, mailOpts.subject, mailOpts.body);
|
||||||
|
req.session.message = 'An email has been sent to ' + req.body.email + ' with further instructions';
|
||||||
|
req.session.message_type = 'success';
|
||||||
|
return res.redirect('/customer/forgotten');
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
req.session.message = 'Account does not exist';
|
||||||
|
res.redirect('/customer/forgotten');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// reset password form
|
||||||
|
router.get('/customer/reset/:token', (req, res) => {
|
||||||
|
const db = req.app.db;
|
||||||
|
|
||||||
|
// Find the customer using the token
|
||||||
|
db.customers.findOne({resetToken: req.params.token, resetTokenExpiry: {$gt: Date.now()}}, (err, customer) => {
|
||||||
|
if(!customer){
|
||||||
|
req.session.message = 'Password reset token is invalid or has expired';
|
||||||
|
req.session.message_type = 'danger';
|
||||||
|
res.redirect('/forgot');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show the password reset form
|
||||||
|
res.render('reset', {
|
||||||
|
title: 'Reset password',
|
||||||
|
token: req.params.token,
|
||||||
|
route: 'customer',
|
||||||
|
config: common.getConfig(),
|
||||||
|
message: common.clearSessionValue(req.session, 'message'),
|
||||||
|
message_type: common.clearSessionValue(req.session, 'message_type'),
|
||||||
|
show_footer: 'show_footer',
|
||||||
|
helpers: req.handlebars.helpers
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// reset password action
|
||||||
|
router.post('/customer/reset/:token', (req, res) => {
|
||||||
|
const db = req.app.db;
|
||||||
|
let bcrypt = req.bcrypt;
|
||||||
|
|
||||||
|
// get the customer
|
||||||
|
db.customers.findOne({resetToken: req.params.token, resetTokenExpiry: {$gt: Date.now()}}, (err, customer) => {
|
||||||
|
if(!customer){
|
||||||
|
req.session.message = 'Password reset token is invalid or has expired';
|
||||||
|
req.session.message_type = 'danger';
|
||||||
|
return res.redirect('/forgot');
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the password and remove the token
|
||||||
|
let newPassword = bcrypt.hashSync(req.body.password);
|
||||||
|
db.customers.update({email: customer.email}, {$set: {password: newPassword, resetToken: undefined, resetTokenExpiry: undefined}}, {multi: false}, (err, numReplaced) => {
|
||||||
|
let mailOpts = {
|
||||||
|
to: customer.email,
|
||||||
|
subject: 'Password successfully reset',
|
||||||
|
body: 'This is a confirmation that the password for your account ' + customer.email + ' has just been changed successfully.\n'
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Should fix this to properly handle result
|
||||||
|
common.sendEmail(mailOpts.to, mailOpts.subject, mailOpts.body);
|
||||||
|
req.session.message = 'Password successfully updated';
|
||||||
|
req.session.message_type = 'success';
|
||||||
|
return res.redirect('/pay');
|
||||||
|
});
|
||||||
|
return'';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// logout the customer
|
||||||
|
router.post('/customer/logout', (req, res) => {
|
||||||
|
req.session.customer = null;
|
||||||
|
res.status(200).json({});
|
||||||
|
});
|
||||||
|
|
||||||
// search products
|
// search products
|
||||||
router.get('/search/:searchTerm/:pageNum?', (req, res) => {
|
router.get('/search/:searchTerm/:pageNum?', (req, res) => {
|
||||||
let db = req.app.db;
|
let db = req.app.db;
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
{{> menu}}
|
||||||
|
<div class="col-lg-9">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<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">Name:</span></td>
|
||||||
|
<td>{{result.firstName}} {{result.lastName}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="text-info">Address 1:</span></td>
|
||||||
|
<td>{{result.address1}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="text-info">Address 2:</span></td>
|
||||||
|
<td>{{result.address2}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="text-info">Country:</span></td>
|
||||||
|
<td>{{result.country}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="text-info">State:</span></td>
|
||||||
|
<td>{{result.state}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="text-info">Postcode:</span></td>
|
||||||
|
<td>{{result.postcode}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="text-info">Phone number:</span></td>
|
||||||
|
<td>{{result.phone}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class="text-info">Creation date:</span></td>
|
||||||
|
<td>{{formatDate result.created "DD/MM/YYYY hh:mmA"}}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" id="productId" value="{{result._id}}">
|
||||||
|
</div>
|
|
@ -0,0 +1,64 @@
|
||||||
|
{{> menu}}
|
||||||
|
<div class="col-lg-9">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<h2>Customers</h2>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-12 search_bar">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" name="customer_filter" id="customer_filter" class="form-control input-lg" placeholder="Filter customers">
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-success btn-lg" id="btn_customer_filter">Filter</button>
|
||||||
|
<a href="/admin/customers" class="hidden-xs btn btn-warning btn-lg"><i class="fa fa-times" aria-hidden="true"></i></a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-warning top-pad-10">Customers can be filtered by: email, name or phone numnber</p>
|
||||||
|
</div>
|
||||||
|
{{#if customers}}
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<strong>
|
||||||
|
Customers
|
||||||
|
{{#if searchTerm}}
|
||||||
|
- <span class="text-danger">Filtered term: {{searchTerm}} </span>
|
||||||
|
{{/if}}
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h5 class="text-info"><strong>Email address</strong></h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h5 class="text-info"><strong>Name</strong></h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h5 class="text-info"><strong>Phone number</strong></h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{#each customers}}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<div class="row">
|
||||||
|
<a href="/admin/customer/view/{{this._id}}">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h5 class="">{{this.email}}</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h5 class="">{{this.firstName}} {{this.lastName}}</h5>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<h5 class="">{{this.phone}}</h5>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<h4 class="text-center">
|
||||||
|
No orders found
|
||||||
|
</h4>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="col-md-offset-4 col-md-4 col-lg-offset-4 col-lg-4" style="padding-top: 100px" >
|
||||||
|
<form class="form-signin" action="/{{route}}/forgotten_action" method="post" role="form" data-toggle="validator">
|
||||||
|
<h2 class="form-signin-heading">Please enter your email address</h2>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="email" name="email" class="form-control" placeholder="email address" required autofocus>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-lg btn-primary btn-block" type="submit">Reset</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -6,6 +6,8 @@
|
||||||
<li class="list-group-item"><i class="fa fa-list fa-icon" aria-hidden="true"></i> <a href="/admin/products">List</a></li>
|
<li class="list-group-item"><i class="fa fa-list fa-icon" aria-hidden="true"></i> <a href="/admin/products">List</a></li>
|
||||||
<li class="list-group-item"><strong>Orders</strong></li>
|
<li class="list-group-item"><strong>Orders</strong></li>
|
||||||
<li class="list-group-item"><i class="fa fa-cube fa-icon" aria-hidden="true"></i> <a href="/admin/orders">List</a></li>
|
<li class="list-group-item"><i class="fa fa-cube fa-icon" aria-hidden="true"></i> <a href="/admin/orders">List</a></li>
|
||||||
|
<li class="list-group-item"><strong>Customers</strong></li>
|
||||||
|
<li class="list-group-item"><i class="fa fa-users fa-icon" aria-hidden="true"></i> <a href="/admin/customers">List</a></li>
|
||||||
<li class="list-group-item"><strong>Users</strong></li>
|
<li class="list-group-item"><strong>Users</strong></li>
|
||||||
<li class="list-group-item"><i class="fa fa-user-plus fa-icon" aria-hidden="true"></i> <a href="/admin/user/new">New</a></li>
|
<li class="list-group-item"><i class="fa fa-user-plus fa-icon" aria-hidden="true"></i> <a href="/admin/user/new">New</a></li>
|
||||||
<li class="list-group-item"><i class="fa fa-user fa-icon" aria-hidden="true"></i> <a href="/admin/users">Edit</a></li>
|
<li class="list-group-item"><i class="fa fa-user fa-icon" aria-hidden="true"></i> <a href="/admin/users">Edit</a></li>
|
||||||
|
|
|
@ -6,64 +6,93 @@
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<div class="panel panel-default" style="margin-top: 30px;">
|
<div class="panel panel-default" style="margin-top: 30px;">
|
||||||
<div class="panel-heading">Customer details</div>
|
<div class="panel-heading">Customer details</div>
|
||||||
|
{{#unless session.customer}}
|
||||||
|
<div class="panel-body customer-details-login">
|
||||||
|
<p>Existing customer</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="email" class="form-control" id="customerLoginEmail" name="loginEmail" minlength="5" placeholder="Email address" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="password" class="form-control" id="customerLoginPassword" name="loginPassword" minlength="5" placeholder="Password" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<a href="/customer/forgotten" class="btn btn-default pull-left">Forgotten</a>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button id="customerLogin" class="btn btn-success pull-right" type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
<div class="panel-body customer-details">
|
<div class="panel-body customer-details">
|
||||||
|
{{#if session.customer}}
|
||||||
|
<div class="col-xs-12 col-md-12">
|
||||||
|
<button id="customerLogout" class="btn btn-sm btn-success pull-right">Change customer</button>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
<form id="shipping-form" class="shipping-form" action="/{{config.paymentGateway}}/checkout_action" method="post" role="form" data-toggle="validator" novalidate="false">
|
<form id="shipping-form" class="shipping-form" action="/{{config.paymentGateway}}/checkout_action" method="post" role="form" data-toggle="validator" novalidate="false">
|
||||||
<div class="col-xs-12 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="email" class="form-control customerDetails" id="shipEmail" name="shipEmail" minlength="5" placeholder="Email address" required>
|
<input type="email" class="form-control customerDetails" id="shipEmail" name="shipEmail" minlength="5" placeholder="Email address" value="{{session.customer.email}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-6">
|
<div class="col-xs-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipFirstname" name="shipFirstname" placeholder="First name" required>
|
<input type="text" class="form-control customerDetails" id="shipFirstname" name="shipFirstname" placeholder="First name" value="{{session.customer.firstName}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-6">
|
<div class="col-xs-12 col-md-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipLastname" name="shipLastname" placeholder="Last name" required>
|
<input type="text" class="form-control customerDetails" id="shipLastname" name="shipLastname" placeholder="Last name" value="{{session.customer.lastName}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipAddr1" name="shipAddr1" placeholder="Address 1" required>
|
<input type="text" class="form-control customerDetails" id="shipAddr1" name="shipAddr1" placeholder="Address 1" value="{{session.customer.address1}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipAddr2" name="shipAddr2" placeholder="Address 2 (optional)">
|
<input type="text" class="form-control customerDetails" id="shipAddr2" name="shipAddr2" placeholder="Address 2 (optional)" value="{{session.customer.address1}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-4">
|
<div class="col-xs-12 col-md-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipCountry" name="shipCountry" placeholder="Country" required>
|
<input type="text" class="form-control customerDetails" id="shipCountry" name="shipCountry" placeholder="Country" value="{{session.customer.country}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-4">
|
<div class="col-xs-12 col-md-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control customerDetails" id="shipState" name="shipState" placeholder="State" required>
|
<input type="text" class="form-control customerDetails" id="shipState" name="shipState" placeholder="State" value="{{session.customer.state}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-4">
|
<div class="col-xs-12 col-md-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="number" class="form-control customerDetails" id="shipPostcode" name="shipPostcode" placeholder="Post code" required>
|
<input type="text" class="form-control customerDetails" id="shipPostcode" name="shipPostcode" placeholder="Post code" value="{{session.customer.postcode}}" required>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="number" class="form-control customerDetails" id="shipPostcode" name="shipPostcode" placeholder="Post code" required>
|
<input type="number" class="form-control customerDetails" id="shipPhoneNumber" name="shipPhoneNumber" placeholder="Phone number" value="{{session.customer.phone}}" required>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-md-12">
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="number" class="form-control customerDetails" id="shipPhoneNumber" name="shipPhoneNumber" placeholder="Phone number (optional)">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{#if session.customer}}
|
||||||
{{#ifCond config.paymentGateway '==' 'paypal'}}
|
{{#ifCond config.paymentGateway '==' 'paypal'}}
|
||||||
<div class="paypal_button col-xs-12 col-md-12 text-center">
|
<div class="paypal_button col-xs-12 col-md-12 text-center">
|
||||||
<button id="checkout_paypal" class="btn btn-success" type="submit"><i class="fa fa-cc-paypal fa-lg" aria-hidden="true"></i> Pay with PayPal <i class="fa fa-cc-paypal fa-lg" aria-hidden="true"></i></button>
|
<button id="checkout_paypal" class="btn btn-success" type="submit"><i class="fa fa-cc-paypal fa-lg" aria-hidden="true"></i> Pay with PayPal <i class="fa fa-cc-paypal fa-lg" aria-hidden="true"></i></button>
|
||||||
</div>
|
</div>
|
||||||
{{/ifCond}}
|
{{/ifCond}}
|
||||||
|
{{/if}}
|
||||||
|
{{#unless session.customer}}
|
||||||
|
<div class="col-xs-12 col-md-12">
|
||||||
|
<p class="text-muted">Enter a password to create an account for next time</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="password" class="form-control customerDetails" id="newCustomerPassword" name="newCustomerPassword" placeholder="Password" required>
|
||||||
|
</div>
|
||||||
|
<a id="createCustomerAccount" class="btn btn-success pull-right">Create account</a>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
</form>
|
</form>
|
||||||
|
{{#if session.customer}}
|
||||||
{{#ifCond config.paymentGateway '==' 'stripe'}}
|
{{#ifCond config.paymentGateway '==' 'stripe'}}
|
||||||
<div class="col-xs-12 col-md-12 text-center">
|
<div class="col-xs-12 col-md-12 text-center">
|
||||||
<form method="POST" id="payment-form">
|
<form method="POST" id="payment-form">
|
||||||
|
@ -87,6 +116,7 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{/ifCond}}
|
{{/ifCond}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<div class="col-md-offset-4 col-md-4 col-lg-offset-4 col-lg-4">
|
||||||
|
<form class="form-signin" action="/{{route}}/reset/{{token}}" method="post" role="form" data-toggle="validator">
|
||||||
|
<h2 class="form-signin-heading">Password reset</h2>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="user_password">Password *</label>
|
||||||
|
<input type="password" class="form-control" id="user_password" name="password" placeholder="Password" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="frm_user_password_confirm">Confirm password *</label>
|
||||||
|
<input type="password" data-match="#user_password" placeholder="Confirm password" class="form-control" name="frm_user_password_confirm" required>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-lg btn-success btn-block" type="submit">Update password</button>
|
||||||
|
</br>
|
||||||
|
</form>
|
||||||
|
</div>
|
Loading…
Reference in New Issue