2018-01-07 06:07:10 +10:00
|
|
|
const _ = require('lodash');
|
|
|
|
const uglifycss = require('uglifycss');
|
|
|
|
const colors = require('colors');
|
|
|
|
const lunr = require('lunr');
|
2018-01-07 23:10:16 +10:00
|
|
|
const fs = require('fs');
|
2018-01-07 06:07:10 +10:00
|
|
|
const escape = require('html-entities').AllHtmlEntities;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
|
|
|
// common functions
|
|
|
|
exports.checkLogin = function(req, res, next){
|
|
|
|
// if not protecting we check for public pages and don't checkLogin
|
|
|
|
if(req.session.needsSetup === true){
|
|
|
|
res.redirect('/setup');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(req.session.user){
|
|
|
|
next();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
res.redirect('/login');
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.showCartCloseBtn = function(page){
|
|
|
|
let showCartCloseButton = true;
|
|
|
|
if(page === 'checkout' || page === 'pay'){
|
|
|
|
showCartCloseButton = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return showCartCloseButton;
|
|
|
|
};
|
|
|
|
|
|
|
|
// adds products to sitemap.xml
|
|
|
|
exports.addSitemapProducts = function(req, res, cb){
|
|
|
|
let db = req.app.db;
|
|
|
|
let async = require('async');
|
2018-01-07 05:35:49 +10:00
|
|
|
let config = exports.getConfig();
|
2018-01-07 04:55:48 +10:00
|
|
|
let hostname = config.baseUrl;
|
|
|
|
|
|
|
|
exports.dbQuery(db.products, {productPublished: 'true'}, null, null, (err, products) => {
|
|
|
|
let posts = [];
|
|
|
|
if(err){
|
|
|
|
cb(null, posts);
|
|
|
|
}
|
|
|
|
async.eachSeries(products, (item, callback) => {
|
|
|
|
let post = {};
|
|
|
|
let url = item._id;
|
|
|
|
if(item.productPermalink){
|
|
|
|
url = item.productPermalink;
|
|
|
|
}
|
|
|
|
post.url = hostname + '/' + url;
|
|
|
|
post.changefreq = 'weekly';
|
|
|
|
post.priority = 0.7;
|
|
|
|
posts.push(post);
|
|
|
|
callback(null, posts);
|
|
|
|
}, () => {
|
|
|
|
cb(null, posts);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.restrict = function(req, res, next){
|
|
|
|
exports.checkLogin(req, res, next);
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.clearSessionValue = function(session, sessionVar){
|
|
|
|
let temp;
|
|
|
|
if(session){
|
|
|
|
temp = session[sessionVar];
|
|
|
|
session[sessionVar] = null;
|
|
|
|
}
|
|
|
|
return temp;
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.updateTotalCartAmount = function(req, res){
|
2018-01-07 05:35:49 +10:00
|
|
|
let config = exports.getConfig();
|
2018-01-07 04:55:48 +10:00
|
|
|
|
|
|
|
req.session.totalCartAmount = 0;
|
|
|
|
|
|
|
|
_(req.session.cart).forEach((item) => {
|
|
|
|
req.session.totalCartAmount = req.session.totalCartAmount + item.totalItemPrice;
|
|
|
|
});
|
|
|
|
|
|
|
|
// under the free shipping threshold
|
|
|
|
if(req.session.totalCartAmount < config.freeShippingAmount){
|
|
|
|
req.session.totalCartAmount = req.session.totalCartAmount + parseInt(config.flatShipping);
|
|
|
|
req.session.shippingCostApplied = true;
|
|
|
|
}else{
|
|
|
|
req.session.shippingCostApplied = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.checkDirectorySync = function (directory){
|
|
|
|
let fs = require('fs');
|
|
|
|
try{
|
|
|
|
fs.statSync(directory);
|
|
|
|
}catch(e){
|
|
|
|
fs.mkdirSync(directory);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.getThemes = function (){
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
return fs.readdirSync(path.join('public', 'themes')).filter(file => fs.statSync(path.join(path.join('public', 'themes'), file)).isDirectory());
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.getImages = function (dir, req, res, callback){
|
|
|
|
let db = req.app.db;
|
|
|
|
let glob = require('glob');
|
|
|
|
let fs = require('fs');
|
|
|
|
|
|
|
|
db.products.findOne({_id: exports.getId(dir)}, (err, product) => {
|
|
|
|
if(err){
|
|
|
|
console.error(colors.red('Error getting images', err));
|
|
|
|
}
|
2018-01-07 23:10:16 +10:00
|
|
|
|
2018-01-07 04:55:48 +10:00
|
|
|
// loop files in /public/uploads/
|
2018-01-07 23:10:16 +10:00
|
|
|
glob('public/uploads/' + product.productPermalink + '/**', {nosort: true}, (er, files) => {
|
2018-01-07 04:55:48 +10:00
|
|
|
// sort array
|
|
|
|
files.sort();
|
|
|
|
|
|
|
|
// declare the array of objects
|
|
|
|
let fileList = [];
|
|
|
|
|
|
|
|
// loop these files
|
|
|
|
for(let i = 0; i < files.length; i++){
|
|
|
|
// only want files
|
|
|
|
if(fs.lstatSync(files[i]).isDirectory() === false){
|
|
|
|
// declare the file object and set its values
|
|
|
|
let file = {
|
|
|
|
id: i,
|
|
|
|
path: files[i].substring(6)
|
|
|
|
};
|
|
|
|
if(product.productImage === files[i].substring(6)){
|
|
|
|
file.productImage = true;
|
|
|
|
}
|
|
|
|
// push the file object into the array
|
|
|
|
fileList.push(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
callback(fileList);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.getConfig = function(){
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
|
|
|
|
let config = JSON.parse(fs.readFileSync(path.join(__dirname, '../config', 'settings.json'), 'utf8'));
|
|
|
|
config.customCss = typeof config.customCss !== 'undefined' ? escape.decode(config.customCss) : null;
|
|
|
|
config.footerHtml = typeof config.footerHtml !== 'undefined' ? escape.decode(config.footerHtml) : null;
|
|
|
|
config.googleAnalytics = typeof config.googleAnalytics !== 'undefined' ? escape.decode(config.googleAnalytics) : null;
|
|
|
|
|
|
|
|
// set the environment for files
|
|
|
|
config.env = '.min';
|
|
|
|
if(process.env.NODE_ENV === 'development' || process.env.NODE_ENV === undefined){
|
|
|
|
config.env = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup theme
|
|
|
|
config.themeViews = '';
|
|
|
|
if(typeof config.theme !== 'undefined' && config.theme !== ''){
|
|
|
|
config.themeViews = '../public/themes/' + config.theme + '/';
|
|
|
|
}
|
|
|
|
|
|
|
|
// if db set to mongodb override connection with MONGODB_CONNECTION_STRING env var
|
2018-01-07 05:35:49 +10:00
|
|
|
config.databaseConnectionString = process.env.MONGODB_CONNECTION_STRING || config.databaseConnectionString;
|
2018-01-07 04:55:48 +10:00
|
|
|
|
|
|
|
return config;
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.getPaymentConfig = function(){
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
let siteConfig = this.getConfig();
|
|
|
|
|
|
|
|
let config = [];
|
|
|
|
if(fs.existsSync(path.join(__dirname, '../config/' + siteConfig.paymentGateway + '.json'))){
|
|
|
|
config = JSON.parse(fs.readFileSync(path.join(__dirname, '../config/' + siteConfig.paymentGateway + '.json'), 'utf8'));
|
|
|
|
}
|
|
|
|
|
|
|
|
return config;
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.updateConfig = function(fields){
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
let settingsFile = JSON.parse(fs.readFileSync(path.join(__dirname, '../config/settings.json'), 'utf8'));
|
|
|
|
|
|
|
|
_.forEach(fields, (value, key) => {
|
|
|
|
settingsFile[key] = value;
|
|
|
|
if(key === 'customCss_input'){
|
|
|
|
settingsFile['customCss'] = escape.encode(uglifycss.processString(value));
|
|
|
|
}
|
|
|
|
if(key === 'footerHtml_input'){
|
|
|
|
let footerHtml = typeof value !== 'undefined' || value === '' ? escape.encode(value) : '';
|
|
|
|
settingsFile['footerHtml'] = footerHtml;
|
|
|
|
}
|
|
|
|
if(key === 'googleAnalytics_input'){
|
|
|
|
let googleAnalytics = typeof value !== 'undefined' ? escape.encode(value) : '';
|
|
|
|
settingsFile['googleAnalytics'] = googleAnalytics;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// delete settings
|
|
|
|
delete settingsFile['customCss_input'];
|
|
|
|
delete settingsFile['footerHtml_input'];
|
|
|
|
delete settingsFile['googleAnalytics_input'];
|
|
|
|
|
|
|
|
if(fields['emailSecure'] === 'on'){
|
|
|
|
settingsFile['emailSecure'] = true;
|
|
|
|
}else{
|
|
|
|
settingsFile['emailSecure'] = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!fields['menuEnabled']){
|
|
|
|
settingsFile['menuEnabled'] = 'false';
|
|
|
|
}else{
|
|
|
|
settingsFile['menuEnabled'] = 'true';
|
|
|
|
}
|
|
|
|
|
|
|
|
// write file
|
|
|
|
try{
|
|
|
|
fs.writeFileSync(path.join(__dirname, '../config/settings.json'), JSON.stringify(settingsFile, null, 4));
|
|
|
|
return true;
|
|
|
|
}catch(exception){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.getMenu = function(){
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
let menuFile = JSON.parse(fs.readFileSync(path.join(__dirname, '../config/menu.json'), 'utf8'));
|
|
|
|
|
|
|
|
menuFile.items = _.sortBy(menuFile.items, 'order');
|
|
|
|
return menuFile;
|
|
|
|
};
|
|
|
|
|
|
|
|
// creates a new menu item
|
|
|
|
exports.newMenu = function(req, res){
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
let menuJson = '../config/menu.json';
|
|
|
|
let menuFile = require(menuJson);
|
|
|
|
|
|
|
|
let newNav = {
|
|
|
|
title: req.body.navMenu,
|
|
|
|
link: req.body.navLink,
|
|
|
|
order: Object.keys(menuFile.items).length + 1
|
|
|
|
};
|
|
|
|
|
|
|
|
// add new menu item
|
|
|
|
menuFile.items.push(newNav);
|
|
|
|
|
|
|
|
// write file
|
|
|
|
try{
|
|
|
|
fs.writeFileSync(path.join(__dirname, '../config/menu.json'), JSON.stringify(menuFile));
|
|
|
|
return true;
|
|
|
|
}catch(e){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// delete a menu item
|
|
|
|
exports.deleteMenu = function(req, res, menuIndex){
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
let menuJson = '../config/menu.json';
|
|
|
|
let menuFile = require(menuJson);
|
|
|
|
|
|
|
|
delete menuFile.items[menuIndex];
|
|
|
|
|
|
|
|
// write file
|
|
|
|
try{
|
|
|
|
fs.writeFileSync(path.join(__dirname, '../config/menu.json'), JSON.stringify(menuFile));
|
|
|
|
return true;
|
|
|
|
}catch(e){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// updates and existing menu item
|
|
|
|
exports.updateMenu = function(req, res){
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
let menuJson = '../config/menu.json';
|
|
|
|
let menuFile = require(menuJson);
|
|
|
|
|
|
|
|
// find menu item and update it
|
|
|
|
let menuIndex = _.findIndex(menuFile.items, ['title', req.body.navId]);
|
|
|
|
menuFile.items[menuIndex].title = req.body.navMenu;
|
|
|
|
menuFile.items[menuIndex].link = req.body.navLink;
|
|
|
|
|
|
|
|
// write file
|
|
|
|
try{
|
|
|
|
fs.writeFileSync(path.join(__dirname, '../config/menu.json'), JSON.stringify(menuFile));
|
|
|
|
return true;
|
|
|
|
}catch(e){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.getEmailTemplate = function(result){
|
|
|
|
let cheerio = require('cheerio');
|
|
|
|
let config = this.getConfig();
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
|
|
|
|
let template = fs.readFileSync(path.join(__dirname, '../public/email_template.html'), 'utf8');
|
|
|
|
|
|
|
|
$ = cheerio.load(template);
|
|
|
|
$('#brand').text(config.cartTitle);
|
|
|
|
$('#paymentResult').text(result.message);
|
|
|
|
if(result.paymentApproved === true){
|
|
|
|
$('#paymentResult').addClass('text-success');
|
|
|
|
}else{
|
|
|
|
$('#paymentResult').addClass('text-danger');
|
|
|
|
}
|
|
|
|
$('#paymentMessage').text('Thanks for shopping with us. We hope you will shop with us again soon.');
|
|
|
|
$('#paymentDetails').html(result.paymentDetails);
|
|
|
|
|
|
|
|
return $.html();
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.sendEmail = function(to, subject, body){
|
|
|
|
let config = this.getConfig();
|
|
|
|
let nodemailer = require('nodemailer');
|
|
|
|
|
|
|
|
let emailSettings = {
|
|
|
|
host: config.emailHost,
|
|
|
|
port: config.emailPort,
|
|
|
|
secure: config.emailSecure,
|
|
|
|
auth: {
|
|
|
|
user: config.emailUser,
|
|
|
|
pass: config.emailPassword
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// outlook needs this setting
|
|
|
|
if(config.emailHost === 'smtp-mail.outlook.com'){
|
|
|
|
emailSettings.tls = {ciphers: 'SSLv3'};
|
|
|
|
}
|
|
|
|
|
|
|
|
let transporter = nodemailer.createTransport(emailSettings);
|
|
|
|
|
|
|
|
let mailOptions = {
|
|
|
|
from: config.emailAddress, // sender address
|
|
|
|
to: to, // list of receivers
|
|
|
|
subject: subject, // Subject line
|
|
|
|
html: body// html body
|
|
|
|
};
|
|
|
|
|
|
|
|
transporter.sendMail(mailOptions, (error, info) => {
|
|
|
|
if(error){
|
|
|
|
return console.error(colors.red(error));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// orders the menu
|
|
|
|
exports.orderMenu = function(req, res){
|
|
|
|
let fs = require('fs');
|
|
|
|
let path = require('path');
|
|
|
|
let menuJson = '../config/menu.json';
|
|
|
|
let menuFile = require(menuJson);
|
|
|
|
|
|
|
|
// update the order
|
|
|
|
for(let i = 0; i < req.body.navId.length; i++){
|
|
|
|
_.find(menuFile.items, ['title', req.body.navId[i]]).order = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write file
|
|
|
|
try{
|
|
|
|
fs.writeFileSync(path.join(__dirname, '../config/menu.json'), JSON.stringify(menuFile));
|
|
|
|
return true;
|
|
|
|
}catch(e){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// gets the correct type of index ID
|
|
|
|
exports.getId = function(id){
|
|
|
|
let ObjectID = require('mongodb').ObjectID;
|
|
|
|
if(id){
|
|
|
|
if(id.length !== 24){
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ObjectID(id);
|
|
|
|
};
|
|
|
|
|
|
|
|
// run the DB query
|
|
|
|
exports.dbQuery = function(db, query, sort, limit, callback){
|
|
|
|
if(sort && limit){
|
|
|
|
db.find(query).sort(sort).limit(parseInt(limit)).toArray((err, results) => {
|
|
|
|
if(err){
|
|
|
|
console.error(colors.red(err));
|
|
|
|
}
|
|
|
|
callback(null, results);
|
|
|
|
});
|
|
|
|
}else{
|
|
|
|
db.find(query).toArray((err, results) => {
|
|
|
|
if(err){
|
|
|
|
console.error(colors.red(err));
|
|
|
|
}
|
|
|
|
callback(null, results);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2018-01-07 06:07:10 +10:00
|
|
|
|
|
|
|
exports.indexProducts = (app) => {
|
|
|
|
// index all products in lunr on startup
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
exports.dbQuery(app.db.products, {}, null, null, (err, productsList) => {
|
|
|
|
if(err){
|
|
|
|
console.error(colors.red(err.stack));
|
|
|
|
reject(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup lunr indexing
|
|
|
|
const productsIndex = lunr(function (){
|
|
|
|
this.field('productTitle', {boost: 10});
|
|
|
|
this.field('productTags', {boost: 5});
|
|
|
|
this.field('productDescription');
|
|
|
|
|
|
|
|
const lunrIndex = this;
|
|
|
|
|
|
|
|
// add to lunr index
|
|
|
|
productsList.forEach((product) => {
|
|
|
|
let doc = {
|
|
|
|
'productTitle': product.productTitle,
|
|
|
|
'productTags': product.productTags,
|
|
|
|
'productDescription': product.productDescription,
|
|
|
|
'id': product._id
|
|
|
|
};
|
|
|
|
lunrIndex.add(doc);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
app.productsIndex = productsIndex;
|
|
|
|
console.log(colors.cyan('- Product indexing complete'));
|
|
|
|
resolve();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.indexOrders = (app, cb) => {
|
|
|
|
// index all orders in lunr on startup
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
exports.dbQuery(app.db.orders, {}, null, null, (err, ordersList) => {
|
|
|
|
if(err){
|
|
|
|
console.error(colors.red('Error setting up products index: ' + err));
|
|
|
|
reject(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup lunr indexing
|
|
|
|
const ordersIndex = lunr(function (){
|
|
|
|
this.field('orderEmail', {boost: 10});
|
|
|
|
this.field('orderLastname', {boost: 5});
|
|
|
|
this.field('orderPostcode');
|
|
|
|
|
|
|
|
const lunrIndex = this;
|
|
|
|
|
|
|
|
// add to lunr index
|
|
|
|
ordersList.forEach((order) => {
|
|
|
|
let doc = {
|
|
|
|
'orderLastname': order.orderLastname,
|
|
|
|
'orderEmail': order.orderEmail,
|
|
|
|
'orderPostcode': order.orderPostcode,
|
|
|
|
'id': order._id
|
|
|
|
};
|
|
|
|
lunrIndex.add(doc);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
app.ordersIndex = ordersIndex;
|
|
|
|
console.log(colors.cyan('- Order indexing complete'));
|
|
|
|
resolve();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// start indexing products and orders
|
|
|
|
exports.runIndexing = (app) => {
|
|
|
|
console.info(colors.yellow('Setting up indexes..'));
|
|
|
|
|
|
|
|
return Promise.all([
|
|
|
|
exports.indexProducts(app),
|
|
|
|
exports.indexOrders(app)
|
|
|
|
])
|
|
|
|
.catch((err) => {
|
|
|
|
process.exit(2);
|
|
|
|
});
|
|
|
|
};
|
2018-01-07 23:10:16 +10:00
|
|
|
|
|
|
|
exports.testData = (db) => {
|
|
|
|
db.products.count({})
|
|
|
|
.then((products) => {
|
|
|
|
if(products > 0){
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
|
|
|
console.info(colors.cyan('No products, inserting test data'));
|
|
|
|
|
|
|
|
const testdata = fs.readFileSync('./bin/testdata.json', 'utf-8');
|
|
|
|
return Promise.all([
|
|
|
|
db.products.insertMany(JSON.parse(testdata))
|
|
|
|
])
|
|
|
|
.catch((err) => {
|
|
|
|
console.info(colors.red('Error inserting test data. Check `/bin/testdata.json` is correctly formatted.', err));
|
|
|
|
process.exit(2);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|