Linting and refactoring

master
Mark Moffat 2019-06-15 14:16:08 +09:30
parent 83f5c1f159
commit 291a044d0b
15 changed files with 501 additions and 446 deletions

View File

@ -17,7 +17,7 @@
},
"rules": {
"quotes": ["error", "single"],
"prefer-arrow-callback": 2,
"prefer-arrow-callback": [ "error", { "allowNamedFunctions": true } ],
"consistent-return": 2,
"no-var" : 2,
"new-cap" : 0,
@ -27,11 +27,16 @@
"space-unary-ops" : 2,
"no-undef": 1,
"no-unused-vars": 1,
"keyword-spacing": ["error", { "before": false, "after": false }],
"keyword-spacing": [
"error", {
"before": false, "after": false, "overrides": {
"const": { "after": true }
}
}],
"space-before-function-paren": 0,
"space-before-blocks": ["error", "never"],
"camelcase": 0,
"handle-callback-err": ["error", "none"],
"object-curly-spacing": ["error", "never"]
"object-curly-spacing": ["error", "always"]
}
}

11
app.js
View File

@ -12,12 +12,13 @@ const helmet = require('helmet');
const colors = require('colors');
const cron = require('node-cron');
const common = require('./lib/common');
const{initDb} = require('./lib/db');
const { runIndexing } = require('./lib/indexing');
const { initDb } = require('./lib/db');
let handlebars = require('express-handlebars');
// Validate our settings schema
const Ajv = require('ajv');
const ajv = new Ajv({useDefaults: true});
const ajv = new Ajv({ useDefaults: true });
const baseConfig = ajv.validate(require('./config/baseSchema'), require('./config/settings.json'));
if(baseConfig === false){
@ -226,7 +227,7 @@ app.use(helmet());
app.set('port', process.env.PORT || 1111);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('5TOCyfH3HuszKGzFZntk'));
app.use(session({
resave: true,
@ -345,7 +346,7 @@ initDb(config.databaseConnectionString, async (err, db) => {
// Remove any invalid cart holds
await db.cart.remove({
sessionId: {$nin: validSessionIds}
sessionId: { $nin: validSessionIds }
});
});
@ -357,7 +358,7 @@ initDb(config.databaseConnectionString, async (err, db) => {
// We index when not in test env
if(process.env.NODE_ENV !== 'test'){
try{
await common.runIndexing(app);
await runIndexing(app);
}catch(ex){
console.error(colors.red('Error setting up indexes:' + err));
}

92
lib/auth.js Normal file
View File

@ -0,0 +1,92 @@
const ObjectId = require('mongodb').ObjectID;
const _ = require('lodash');
const restrictedRoutes = [
{ route: '/admin/product/new', response: 'redirect' },
{ route: '/admin/product/insert', response: 'redirect' },
{ route: '/admin/product/edit/:id', response: 'redirect' },
{ route: '/admin/product/update', response: 'redirect' },
{ route: '/admin/product/delete/:id', response: 'redirect' },
{ route: '/admin/product/published_state', response: 'json' },
{ route: '/admin/product/setasmainimage', response: 'json' },
{ route: '/admin/product/deleteimage', response: 'json' },
{ route: '/admin/order/statusupdate', response: 'json' },
{ route: '/admin/settings/update', response: 'json' },
{ route: '/admin/settings/option/remove', response: 'json' },
{ route: '/admin/settings/pages/new', response: 'redirect' },
{ route: '/admin/settings/pages/edit/:page', response: 'redirect' },
{ route: '/admin/settings/pages/update', response: 'json' },
{ route: '/admin/settings/pages/delete/:page', response: 'redirect' },
{ route: '/admin/settings/menu/new', response: 'redirect' },
{ route: '/admin/settings/menu/update', response: 'redirect' },
{ route: '/admin/settings/menu/delete/:menuid', response: 'redirect' },
{ route: '/admin/settings/menu/save_order', response: 'json' },
{ route: '/admin/file/upload', response: 'redirect' },
{ route: '/admin/file/delete', response: 'json' }
];
const restrict = (req, res, next) => {
checkLogin(req, res, next);
};
const checkLogin = async (req, res, next) => {
const db = req.app.db;
// if not protecting we check for public pages and don't checkLogin
if(req.session.needsSetup === true){
res.redirect('/admin/setup');
return;
}
// If API key, check for a user
if(req.headers.apikey){
try{
const user = await db.users.findOne({
apiKey: ObjectId(req.headers.apikey),
isAdmin: true
});
if(!user){
res.status(400).json({ message: 'Access denied' });
return;
}
// Set API authenticated in the req
req.apiAuthenticated = true;
next();
return;
}catch(ex){
res.status(400).json({ message: 'Access denied' });
return;
}
}
if(req.session.user){
next();
return;
}
res.redirect('/admin/login');
};
// Middleware to check for admin access for certain route
const checkAccess = (req, res, next) => {
const routeCheck = _.find(restrictedRoutes, { 'route': req.route.path });
// If the user is not an admin and route is restricted, show message and redirect to /admin
if(req.session.isAdmin === false && routeCheck){
if(routeCheck.response === 'redirect'){
req.session.message = 'Unauthorised. Please refer to administrator.';
req.session.messageType = 'danger';
res.redirect('/admin');
return;
}
if(routeCheck.response === 'json'){
res.status(400).json({ message: 'Unauthorised. Please refer to administrator.' });
}
}else{
next();
}
};
module.exports = {
restrict,
checkLogin,
checkAccess
};

View File

@ -1,7 +1,6 @@
const _ = require('lodash');
const uglifycss = require('uglifycss');
const colors = require('colors');
const lunr = require('lunr');
const cheerio = require('cheerio');
const fs = require('fs');
const path = require('path');
@ -11,34 +10,10 @@ const nodemailer = require('nodemailer');
const sanitizeHtml = require('sanitize-html');
const escape = require('html-entities').AllHtmlEntities;
const mkdirp = require('mkdirp');
let ObjectId = require('mongodb').ObjectID;
const restrictedRoutes = [
{route: '/admin/product/new', response: 'redirect'},
{route: '/admin/product/insert', response: 'redirect'},
{route: '/admin/product/edit/:id', response: 'redirect'},
{route: '/admin/product/update', response: 'redirect'},
{route: '/admin/product/delete/:id', response: 'redirect'},
{route: '/admin/product/published_state', response: 'json'},
{route: '/admin/product/setasmainimage', response: 'json'},
{route: '/admin/product/deleteimage', response: 'json'},
{route: '/admin/order/statusupdate', response: 'json'},
{route: '/admin/settings/update', response: 'json'},
{route: '/admin/settings/option/remove', response: 'json'},
{route: '/admin/settings/pages/new', response: 'redirect'},
{route: '/admin/settings/pages/edit/:page', response: 'redirect'},
{route: '/admin/settings/pages/update', response: 'json'},
{route: '/admin/settings/pages/delete/:page', response: 'redirect'},
{route: '/admin/settings/menu/new', response: 'redirect'},
{route: '/admin/settings/menu/update', response: 'redirect'},
{route: '/admin/settings/menu/delete/:menuid', response: 'redirect'},
{route: '/admin/settings/menu/save_order', response: 'json'},
{route: '/admin/file/upload', response: 'redirect'},
{route: '/admin/file/delete', response: 'json'}
];
const ObjectId = require('mongodb').ObjectID;
// Allowed mime types for product images
exports.allowedMimeType = [
const allowedMimeType = [
'image/jpeg',
'image/png',
'image/gif',
@ -46,54 +21,14 @@ exports.allowedMimeType = [
'image/webp'
];
exports.fileSizeLimit = 10485760;
const fileSizeLimit = 10485760;
// common functions
exports.restrict = (req, res, next) => {
exports.checkLogin(req, res, next);
};
exports.checkLogin = async (req, res, next) => {
const db = req.app.db;
// if not protecting we check for public pages and don't checkLogin
if(req.session.needsSetup === true){
res.redirect('/admin/setup');
return;
}
// If API key, check for a user
if(req.headers.apikey){
try{
const user = await db.users.findOne({
apiKey: ObjectId(req.headers.apikey),
isAdmin: true
});
if(!user){
res.status(400).json({message: 'Access denied'});
return;
}
// Set API authenticated in the req
req.apiAuthenticated = true;
next();
return;
}catch(ex){
res.status(400).json({message: 'Access denied'});
return;
}
}
if(req.session.user){
next();
return;
}
res.redirect('/admin/login');
};
exports.cleanHtml = (html) => {
const cleanHtml = (html) => {
return sanitizeHtml(html);
};
exports.mongoSanitize = (param) => {
const mongoSanitize = (param) => {
if(param instanceof Object){
for(const key in param){
if(/^\$/.test(key)){
@ -104,34 +39,14 @@ exports.mongoSanitize = (param) => {
return param;
};
exports.checkboxBool = (param) => {
const checkboxBool = (param) => {
if(param && param === 'on'){
return true;
}
return false;
};
// Middleware to check for admin access for certain route
exports.checkAccess = (req, res, next) => {
const routeCheck = _.find(restrictedRoutes, {'route': req.route.path});
// If the user is not an admin and route is restricted, show message and redirect to /admin
if(req.session.isAdmin === false && routeCheck){
if(routeCheck.response === 'redirect'){
req.session.message = 'Unauthorised. Please refer to administrator.';
req.session.messageType = 'danger';
res.redirect('/admin');
return;
}
if(routeCheck.response === 'json'){
res.status(400).json({message: 'Unauthorised. Please refer to administrator.'});
}
}else{
next();
}
};
exports.showCartCloseBtn = (page) => {
const showCartCloseBtn = (page) => {
let showCartCloseButton = true;
if(page === 'checkout' || page === 'pay'){
showCartCloseButton = false;
@ -141,13 +56,13 @@ exports.showCartCloseBtn = (page) => {
};
// adds products to sitemap.xml
exports.addSitemapProducts = (req, res, cb) => {
const addSitemapProducts = (req, res, cb) => {
let db = req.app.db;
let config = exports.getConfig();
let config = getConfig();
let hostname = config.baseUrl;
db.products.find({productPublished: 'true'}).toArray((err, products) => {
db.products.find({ productPublished: 'true' }).toArray((err, products) => {
let posts = [];
if(err){
cb(null, posts);
@ -169,7 +84,7 @@ exports.addSitemapProducts = (req, res, cb) => {
});
};
exports.clearSessionValue = (session, sessionVar) => {
const clearSessionValue = (session, sessionVar) => {
let temp;
if(session){
temp = session[sessionVar];
@ -178,8 +93,8 @@ exports.clearSessionValue = (session, sessionVar) => {
return temp;
};
exports.updateTotalCartAmount = (req, res) => {
let config = exports.getConfig();
const updateTotalCartAmount = (req, res) => {
let config = getConfig();
req.session.totalCartAmount = 0;
@ -196,7 +111,7 @@ exports.updateTotalCartAmount = (req, res) => {
}
};
exports.checkDirectorySync = (directory) => {
const checkDirectorySync = (directory) => {
try{
fs.statSync(directory);
}catch(e){
@ -208,20 +123,20 @@ exports.checkDirectorySync = (directory) => {
}
};
exports.getThemes = () => {
const getThemes = () => {
return fs.readdirSync(path.join(__dirname, '../', 'views', 'themes')).filter(file => fs.statSync(path.join(path.join(__dirname, '../', 'views', 'themes'), file)).isDirectory());
};
exports.getImages = (dir, req, res, callback) => {
const getImages = (dir, req, res, callback) => {
let db = req.app.db;
db.products.findOne({_id: exports.getId(dir)}, (err, product) => {
db.products.findOne({ _id: getId(dir) }, (err, product) => {
if(err){
console.error(colors.red('Error getting images', err));
}
// loop files in /public/uploads/
glob('public/uploads/' + product.productPermalink + '/**', {nosort: true}, (er, files) => {
glob('public/uploads/' + product.productPermalink + '/**', { nosort: true }, (er, files) => {
// sort array
files.sort();
@ -249,7 +164,7 @@ exports.getImages = (dir, req, res, callback) => {
});
};
exports.getConfigFilename = () => {
const getConfigFilename = () => {
let filename = path.join(__dirname, '../config', 'settings-local.json');
if(fs.existsSync(filename)){
return filename;
@ -257,8 +172,8 @@ exports.getConfigFilename = () => {
return path.join(__dirname, '../config', 'settings.json');
};
exports.getConfig = () => {
let config = JSON.parse(fs.readFileSync(exports.getConfigFilename(), 'utf8'));
const getConfig = () => {
let config = JSON.parse(fs.readFileSync(getConfigFilename(), '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;
@ -283,8 +198,8 @@ exports.getConfig = () => {
return config;
};
exports.getPaymentConfig = () => {
let siteConfig = this.getConfig();
const getPaymentConfig = () => {
let siteConfig = getConfig();
const gateConfigFile = path.join(__dirname, '../config', `${siteConfig.paymentGateway}.json`);
let config = [];
@ -302,8 +217,8 @@ exports.getPaymentConfig = () => {
return config;
};
exports.updateConfig = (fields) => {
let settingsFile = exports.getConfig();
const updateConfig = (fields) => {
let settingsFile = getConfig();
_.forEach(fields, (value, key) => {
settingsFile[key] = value;
@ -359,21 +274,21 @@ exports.updateConfig = (fields) => {
// write file
try{
fs.writeFileSync(exports.getConfigFilename(), JSON.stringify(settingsFile, null, 4));
fs.writeFileSync(getConfigFilename(), JSON.stringify(settingsFile, null, 4));
return true;
}catch(exception){
return false;
}
};
exports.getMenu = (db) => {
const getMenu = (db) => {
return db.menu.findOne({});
};
// creates a new menu item
exports.newMenu = (req, res) => {
const newMenu = (req, res) => {
const db = req.app.db;
return exports.getMenu(db)
return getMenu(db)
.then((menu) => {
// if no menu present
if(!menu){
@ -387,7 +302,7 @@ exports.newMenu = (req, res) => {
};
menu.items.push(newNav);
return db.menu.updateOne({}, {$set: {items: menu.items}}, {upsert: true})
return db.menu.updateOne({}, { $set: { items: menu.items } }, { upsert: true })
.then(() => {
return true;
});
@ -399,13 +314,13 @@ exports.newMenu = (req, res) => {
};
// delete a menu item
exports.deleteMenu = (req, res, menuIndex) => {
const deleteMenu = (req, res, menuIndex) => {
const db = req.app.db;
return exports.getMenu(db)
return getMenu(db)
.then((menu) => {
// Remove menu item
menu.items.splice(menuIndex, 1);
return db.menu.updateOne({}, {$set: {items: menu.items}}, {upsert: true})
return db.menu.updateOne({}, { $set: { items: menu.items } }, { upsert: true })
.then(() => {
return true;
});
@ -416,15 +331,15 @@ exports.deleteMenu = (req, res, menuIndex) => {
};
// updates and existing menu item
exports.updateMenu = (req, res) => {
const updateMenu = (req, res) => {
const db = req.app.db;
return exports.getMenu(db)
return getMenu(db)
.then((menu) => {
// find menu item and update it
let menuIndex = _.findIndex(menu.items, ['title', req.body.navId]);
menu.items[menuIndex].title = req.body.navMenu;
menu.items[menuIndex].link = req.body.navLink;
return db.menu.updateOne({}, {$set: {items: menu.items}}, {upsert: true})
return db.menu.updateOne({}, { $set: { items: menu.items } }, { upsert: true })
.then(() => {
return true;
});
@ -434,7 +349,7 @@ exports.updateMenu = (req, res) => {
});
};
exports.sortMenu = (menu) => {
const sortMenu = (menu) => {
if(menu && menu.items){
menu.items = _.sortBy(menu.items, 'order');
return menu;
@ -443,15 +358,15 @@ exports.sortMenu = (menu) => {
};
// orders the menu
exports.orderMenu = (req, res) => {
const orderMenu = (req, res) => {
const db = req.app.db;
return exports.getMenu(db)
return getMenu(db)
.then((menu) => {
// update the order
for(let i = 0; i < req.body.navId.length; i++){
_.find(menu.items, ['title', req.body.navId[i]]).order = i;
}
return db.menu.updateOne({}, {$set: {items: menu.items}}, {upsert: true})
return db.menu.updateOne({}, { $set: { items: menu.items } }, { upsert: true })
.then(() => {
return true;
});
@ -461,8 +376,8 @@ exports.orderMenu = (req, res) => {
});
};
exports.getEmailTemplate = (result) => {
let config = this.getConfig();
const getEmailTemplate = (result) => {
let config = getConfig();
let template = fs.readFileSync(path.join(__dirname, '../public/email_template.html'), 'utf8');
@ -480,8 +395,8 @@ exports.getEmailTemplate = (result) => {
return $.html();
};
exports.sendEmail = (to, subject, body) => {
let config = this.getConfig();
const sendEmail = (to, subject, body) => {
let config = getConfig();
let emailSettings = {
host: config.emailHost,
@ -495,7 +410,7 @@ exports.sendEmail = (to, subject, body) => {
// outlook needs this setting
if(config.emailHost === 'smtp-mail.outlook.com'){
emailSettings.tls = {ciphers: 'SSLv3'};
emailSettings.tls = { ciphers: 'SSLv3' };
}
let transporter = nodemailer.createTransport(emailSettings);
@ -516,7 +431,7 @@ exports.sendEmail = (to, subject, body) => {
};
// gets the correct type of index ID
exports.getId = (id) => {
const getId = (id) => {
if(id){
if(id.length !== 24){
return id;
@ -525,9 +440,9 @@ exports.getId = (id) => {
return ObjectId(id);
};
exports.getData = (req, page, query) => {
const getData = (req, page, query) => {
let db = req.app.db;
let config = exports.getConfig();
let config = getConfig();
let numberProducts = config.productsPerPage ? config.productsPerPage : 6;
let skip = 0;
@ -547,7 +462,7 @@ exports.getData = (req, page, query) => {
db.products.count(query)
])
.then((result) => {
const returnData = {data: result[0], totalProducts: result[1]};
const returnData = { data: result[0], totalProducts: result[1] };
return returnData;
})
.catch((err) => {
@ -555,134 +470,31 @@ exports.getData = (req, page, query) => {
});
};
exports.indexProducts = (app) => {
// index all products in lunr on startup
return new Promise((resolve, reject) => {
app.db.products.find({}).toArray((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.indexCustomers = (app) => {
// index all products in lunr on startup
return new Promise((resolve, reject) => {
app.db.customers.find({}).toArray((err, customerList) => {
if(err){
console.error(colors.red(err.stack));
reject(err);
}
// setup lunr indexing
const customersIndex = lunr(function(){
this.field('email', {boost: 10});
this.field('name', {boost: 5});
this.field('phone');
const lunrIndex = this;
// add to lunr index
customerList.forEach((customer) => {
let doc = {
'email': customer.email,
'name': `${customer.firstName} ${customer.lastName}`,
'phone': customer.phone,
'id': customer._id
};
lunrIndex.add(doc);
});
});
app.customersIndex = customersIndex;
console.log(colors.cyan('- Customer indexing complete'));
resolve();
});
});
};
exports.indexOrders = (app, cb) => {
// index all orders in lunr on startup
return new Promise((resolve, reject) => {
app.db.orders.find({}).toArray((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();
});
});
};
exports.fixProductDates = (products) => {
let index = 0;
products.forEach((product) => {
products[index].productAddedDate = new Date();
index++;
});
return products;
};
// start indexing products and orders
exports.runIndexing = (app) => {
console.info(colors.yellow('Setting up indexes..'));
return Promise.all([
exports.indexProducts(app),
exports.indexOrders(app),
exports.indexCustomers(app)
])
.catch((err) => {
console.info(colors.yellow('Error setting up indexes', err));
process.exit(2);
});
module.exports = {
allowedMimeType,
fileSizeLimit,
cleanHtml,
mongoSanitize,
checkboxBool,
showCartCloseBtn,
addSitemapProducts,
clearSessionValue,
updateTotalCartAmount,
checkDirectorySync,
getThemes,
getImages,
getConfigFilename,
getConfig,
getPaymentConfig,
updateConfig,
getMenu,
newMenu,
deleteMenu,
updateMenu,
sortMenu,
orderMenu,
getEmailTemplate,
sendEmail,
getId,
getData
};

142
lib/indexing.js Normal file
View File

@ -0,0 +1,142 @@
const colors = require('colors');
const lunr = require('lunr');
const indexProducts = (app) => {
// index all products in lunr on startup
return new Promise((resolve, reject) => {
app.db.products.find({}).toArray((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();
});
});
};
const indexCustomers = (app) => {
// index all products in lunr on startup
return new Promise((resolve, reject) => {
app.db.customers.find({}).toArray((err, customerList) => {
if(err){
console.error(colors.red(err.stack));
reject(err);
}
// setup lunr indexing
const customersIndex = lunr(function(){
this.field('email', { boost: 10 });
this.field('name', { boost: 5 });
this.field('phone');
const lunrIndex = this;
// add to lunr index
customerList.forEach((customer) => {
let doc = {
'email': customer.email,
'name': `${customer.firstName} ${customer.lastName}`,
'phone': customer.phone,
'id': customer._id
};
lunrIndex.add(doc);
});
});
app.customersIndex = customersIndex;
console.log(colors.cyan('- Customer indexing complete'));
resolve();
});
});
};
const indexOrders = (app, cb) => {
// index all orders in lunr on startup
return new Promise((resolve, reject) => {
app.db.orders.find({}).toArray((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();
});
});
};
const fixProductDates = (products) => {
let index = 0;
products.forEach(() => {
products[index].productAddedDate = new Date();
index++;
});
return products;
};
// start indexing products and orders
const runIndexing = (app) => {
console.info(colors.yellow('Setting up indexes..'));
return Promise.all([
indexProducts(app),
indexOrders(app),
indexCustomers(app)
])
.catch((err) => {
console.info(colors.yellow('Error setting up indexes', err));
process.exit(2);
});
};
module.exports = {
indexProducts,
indexCustomers,
indexOrders,
fixProductDates,
runIndexing
};

View File

@ -1,5 +1,6 @@
const common = require('./common');
const{initDb} = require('./db');
const { getConfig } = require('./common');
const { initDb } = require('./db');
const { fixProductDates } = require('./indexing');
const fs = require('fs');
const path = require('path');
@ -7,7 +8,7 @@ const testData = fs.readFileSync(path.join(__dirname, '..', 'bin', 'testdata.jso
const jsonData = JSON.parse(testData);
// get config
let config = common.getConfig();
let config = getConfig();
initDb(config.databaseConnectionString, (err, db) => {
Promise.all([
@ -20,7 +21,7 @@ initDb(config.databaseConnectionString, (err, db) => {
Promise.all([
db.users.insertMany(jsonData.users),
db.customers.insertMany(jsonData.customers),
db.products.insertMany(common.fixProductDates(jsonData.products)),
db.products.insertMany(fixProductDates(jsonData.products)),
db.menu.insertOne(jsonData.menu)
])
.then(() => {

View File

@ -120,7 +120,7 @@ $(document).ready(function (){
$.ajax({
method: 'POST',
url: '/admin/product/published_state',
data: {id: this.id, state: this.checked}
data: { id: this.id, state: this.checked }
})
.done(function(msg){
showNotification(msg.message, 'success');
@ -226,7 +226,7 @@ $(document).ready(function (){
$.ajax({
method: 'POST',
url: '/admin/settings/option/remove/',
data: {productId: $('#frmProductId').val(), optName: name}
data: { productId: $('#frmProductId').val(), optName: name }
})
.done(function(msg){
showNotification(msg.message, 'success', true);
@ -467,7 +467,7 @@ $(document).ready(function (){
$.ajax({
method: 'POST',
url: '/admin/order/statusupdate',
data: {order_id: $('#order_id').val(), status: $('#orderStatus').val()}
data: { order_id: $('#order_id').val(), status: $('#orderStatus').val() }
})
.done(function(msg){
showNotification(msg.message, 'success', true);
@ -524,7 +524,7 @@ $(document).ready(function (){
$.ajax({
method: 'POST',
url: '/product/addtocart',
data: {productId: $(this).attr('data-id')}
data: { productId: $(this).attr('data-id') }
})
.done(function(msg){
$('#cart-count').text(msg.totalCartItems);
@ -567,7 +567,7 @@ $(document).ready(function (){
$.ajax({
method: 'POST',
url: '/admin/product/setasmainimage',
data: {product_id: $('#frmProductId').val(), productImage: $(this).attr('data-id')}
data: { product_id: $('#frmProductId').val(), productImage: $(this).attr('data-id') }
})
.done(function(msg){
showNotification(msg.message, 'success', true);
@ -581,7 +581,7 @@ $(document).ready(function (){
$.ajax({
method: 'POST',
url: '/admin/product/deleteimage',
data: {product_id: $('#frmProductId').val(), productImage: $(this).attr('data-id')}
data: { product_id: $('#frmProductId').val(), productImage: $(this).attr('data-id') }
})
.done(function(msg){
showNotification(msg.message, 'success', true);
@ -597,7 +597,7 @@ $(document).ready(function (){
$.ajax({
method: 'POST',
url: '/admin/api/validate_permalink',
data: {'permalink': $('#frmProductPermalink').val(), 'docId': $('#frmProductId').val()}
data: { 'permalink': $('#frmProductPermalink').val(), 'docId': $('#frmProductId').val() }
})
.done(function(msg){
showNotification(msg, 'success');
@ -677,7 +677,7 @@ function deleteFromCart(element){
$.ajax({
method: 'POST',
url: '/product/removefromcart',
data: {cartId: element.attr('data-id')}
data: { cartId: element.attr('data-id') }
})
.done(function(msg){
$('#cart-count').text(msg.totalCartItems);
@ -740,7 +740,7 @@ function updateCart(){
$.ajax({
method: 'POST',
url: '/product/updatecart',
data: {items: JSON.stringify(cartItems)}
data: { items: JSON.stringify(cartItems) }
})
.done(function(msg){
// update cart items
@ -758,7 +758,7 @@ function updateCartDiv(){
$.ajax({
method: 'GET',
url: '/cartPartial',
data: {path: path}
data: { path: path }
})
.done(function(msg){
// update cart div

View File

@ -1,5 +1,6 @@
const express = require('express');
const common = require('../lib/common');
const { restrict, checkAccess } = require('../lib/auth');
const escape = require('html-entities').AllHtmlEntities;
const colors = require('colors');
const bcrypt = require('bcryptjs');
@ -12,7 +13,7 @@ const ObjectId = require('mongodb').ObjectID;
const router = express.Router();
// Admin section
router.get('/admin', common.restrict, (req, res, next) => {
router.get('/admin', restrict, (req, res, next) => {
res.redirect('/admin/orders');
});
@ -59,15 +60,15 @@ router.get('/admin/login', (req, res) => {
router.post('/admin/login_action', (req, res) => {
let db = req.app.db;
db.users.findOne({userEmail: common.mongoSanitize(req.body.email)}, (err, user) => {
db.users.findOne({ userEmail: common.mongoSanitize(req.body.email) }, (err, user) => {
if(err){
res.status(400).json({message: 'A user with that email does not exist.'});
res.status(400).json({ message: 'A user with that email does not exist.' });
return;
}
// check if user exists with that email
if(user === undefined || user === null){
res.status(400).json({message: 'A user with that email does not exist.'});
res.status(400).json({ message: 'A user with that email does not exist.' });
}else{
// we have a user under that email so we compare the password
bcrypt.compare(req.body.password, user.userPassword)
@ -77,10 +78,10 @@ router.post('/admin/login_action', (req, res) => {
req.session.usersName = user.usersName;
req.session.userId = user._id.toString();
req.session.isAdmin = user.isAdmin;
res.status(200).json({message: 'Login successful'});
res.status(200).json({ message: 'Login successful' });
}else{
// password is not correct
res.status(400).json({message: 'Access denied. Check password and try again.'});
res.status(400).json({ message: 'Access denied. Check password and try again.' });
}
});
}
@ -152,7 +153,7 @@ router.post('/admin/setup_action', (req, res) => {
});
// settings update
router.get('/admin/settings', common.restrict, (req, res) => {
router.get('/admin/settings', restrict, (req, res) => {
res.render('settings', {
title: 'Cart settings',
session: req.session,
@ -168,7 +169,7 @@ router.get('/admin/settings', common.restrict, (req, res) => {
});
// settings update
router.post('/admin/createApiKey', common.restrict, common.checkAccess, async (req, res) => {
router.post('/admin/createApiKey', restrict, checkAccess, async (req, res) => {
const db = req.app.db;
let result = await db.users.findOneAndUpdate({
_id: ObjectId(req.session.userId),
@ -182,27 +183,27 @@ router.post('/admin/createApiKey', common.restrict, common.checkAccess, async (r
});
if(result.value && result.value.apiKey){
res.status(200).json({message: 'API Key generated', apiKey: result.value.apiKey});
res.status(200).json({ message: 'API Key generated', apiKey: result.value.apiKey });
return;
}
res.status(400).json({message: 'Failed to generate API Key'});
res.status(400).json({ message: 'Failed to generate API Key' });
});
// settings update
router.post('/admin/settings/update', common.restrict, common.checkAccess, (req, res) => {
router.post('/admin/settings/update', restrict, checkAccess, (req, res) => {
let result = common.updateConfig(req.body);
if(result === true){
res.status(200).json({message: 'Settings successfully updated'});
res.status(200).json({ message: 'Settings successfully updated' });
res.configDirty = true;
return;
}
res.status(400).json({message: 'Permission denied'});
res.status(400).json({ message: 'Permission denied' });
});
// settings update
router.post('/admin/settings/option/remove', common.restrict, common.checkAccess, (req, res) => {
router.post('/admin/settings/option/remove', restrict, checkAccess, (req, res) => {
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){
console.info(err.stack);
}
@ -210,24 +211,24 @@ router.post('/admin/settings/option/remove', common.restrict, common.checkAccess
let optJson = JSON.parse(product.productOptions);
delete optJson[req.body.optName];
db.products.update({_id: common.getId(req.body.productId)}, {$set: {productOptions: JSON.stringify(optJson)}}, (err, numReplaced) => {
db.products.update({ _id: common.getId(req.body.productId) }, { $set: { productOptions: JSON.stringify(optJson) } }, (err, numReplaced) => {
if(err){
console.info(err.stack);
}
if(numReplaced.result.nModified === 1){
res.status(200).json({message: 'Option successfully removed'});
res.status(200).json({ message: 'Option successfully removed' });
}else{
res.status(400).json({message: 'Failed to remove option. Please try again.'});
res.status(400).json({ message: 'Failed to remove option. Please try again.' });
}
});
}else{
res.status(400).json({message: 'Product not found. Try saving before removing.'});
res.status(400).json({ message: 'Product not found. Try saving before removing.' });
}
});
});
// settings update
router.get('/admin/settings/menu', common.restrict, async (req, res) => {
router.get('/admin/settings/menu', restrict, async (req, res) => {
const db = req.app.db;
res.render('settings_menu', {
title: 'Cart menu',
@ -242,7 +243,7 @@ router.get('/admin/settings/menu', common.restrict, async (req, res) => {
});
// settings page list
router.get('/admin/settings/pages', common.restrict, (req, res) => {
router.get('/admin/settings/pages', restrict, (req, res) => {
const db = req.app.db;
db.pages.find({}).toArray(async (err, pages) => {
if(err){
@ -264,7 +265,7 @@ router.get('/admin/settings/pages', common.restrict, (req, res) => {
});
// settings pages new
router.get('/admin/settings/pages/new', common.restrict, common.checkAccess, async (req, res) => {
router.get('/admin/settings/pages/new', restrict, checkAccess, async (req, res) => {
const db = req.app.db;
res.render('settings_page_edit', {
@ -281,9 +282,9 @@ router.get('/admin/settings/pages/new', common.restrict, common.checkAccess, asy
});
// settings pages editor
router.get('/admin/settings/pages/edit/:page', common.restrict, common.checkAccess, (req, res) => {
router.get('/admin/settings/pages/edit/:page', restrict, checkAccess, (req, res) => {
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){
console.info(err.stack);
}
@ -317,7 +318,7 @@ router.get('/admin/settings/pages/edit/:page', common.restrict, common.checkAcce
});
// settings update page
router.post('/admin/settings/pages/update', common.restrict, common.checkAccess, (req, res) => {
router.post('/admin/settings/pages/update', restrict, checkAccess, (req, res) => {
const db = req.app.db;
let doc = {
@ -329,37 +330,37 @@ router.post('/admin/settings/pages/update', common.restrict, common.checkAccess,
if(req.body.page_id){
// existing page
db.pages.findOne({_id: common.getId(req.body.page_id)}, (err, page) => {
db.pages.findOne({ _id: common.getId(req.body.page_id) }, (err, page) => {
if(err){
console.info(err.stack);
}
if(page){
db.pages.update({_id: common.getId(req.body.page_id)}, {$set: doc}, {}, (err, numReplaced) => {
db.pages.update({ _id: common.getId(req.body.page_id) }, { $set: doc }, {}, (err, numReplaced) => {
if(err){
console.info(err.stack);
}
res.status(200).json({message: 'Page updated successfully', page_id: req.body.page_id});
res.status(200).json({ message: 'Page updated successfully', page_id: req.body.page_id });
});
}else{
res.status(400).json({message: 'Page not found'});
res.status(400).json({ message: 'Page not found' });
}
});
}else{
// insert page
db.pages.insert(doc, (err, newDoc) => {
if(err){
res.status(400).json({message: 'Error creating page. Please try again.'});
res.status(400).json({ message: 'Error creating page. Please try again.' });
}else{
res.status(200).json({message: 'New page successfully created', page_id: newDoc._id});
res.status(200).json({ message: 'New page successfully created', page_id: newDoc._id });
}
});
}
});
// settings delete page
router.get('/admin/settings/pages/delete/:page', common.restrict, common.checkAccess, (req, res) => {
router.get('/admin/settings/pages/delete/:page', restrict, checkAccess, (req, res) => {
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){
req.session.message = 'Error deleting page. Please try again.';
req.session.messageType = 'danger';
@ -373,7 +374,7 @@ router.get('/admin/settings/pages/delete/:page', common.restrict, common.checkAc
});
// new menu item
router.post('/admin/settings/menu/new', common.restrict, common.checkAccess, (req, res) => {
router.post('/admin/settings/menu/new', restrict, checkAccess, (req, res) => {
let result = common.newMenu(req, res);
if(result === false){
req.session.message = 'Failed creating menu.';
@ -383,7 +384,7 @@ router.post('/admin/settings/menu/new', common.restrict, common.checkAccess, (re
});
// update existing menu item
router.post('/admin/settings/menu/update', common.restrict, common.checkAccess, (req, res) => {
router.post('/admin/settings/menu/update', restrict, checkAccess, (req, res) => {
let result = common.updateMenu(req, res);
if(result === false){
req.session.message = 'Failed updating menu.';
@ -393,7 +394,7 @@ router.post('/admin/settings/menu/update', common.restrict, common.checkAccess,
});
// delete menu item
router.get('/admin/settings/menu/delete/:menuid', common.restrict, common.checkAccess, (req, res) => {
router.get('/admin/settings/menu/delete/:menuid', restrict, checkAccess, (req, res) => {
let result = common.deleteMenu(req, res, req.params.menuid);
if(result === false){
req.session.message = 'Failed deleting menu.';
@ -403,10 +404,10 @@ router.get('/admin/settings/menu/delete/:menuid', common.restrict, common.checkA
});
// We call this via a Ajax call to save the order from the sortable list
router.post('/admin/settings/menu/save_order', common.restrict, common.checkAccess, (req, res) => {
router.post('/admin/settings/menu/save_order', restrict, checkAccess, (req, res) => {
let result = common.orderMenu(req, res);
if(result === false){
res.status(400).json({message: 'Failed saving menu order'});
res.status(400).json({ message: 'Failed saving menu order' });
return;
}
res.status(200);
@ -420,9 +421,9 @@ router.post('/admin/api/validate_permalink', (req, res) => {
let query = {};
if(typeof req.body.docId === 'undefined' || req.body.docId === ''){
query = {productPermalink: req.body.permalink};
query = { productPermalink: req.body.permalink };
}else{
query = {productPermalink: req.body.permalink, _id: {$ne: common.getId(req.body.docId)}};
query = { productPermalink: req.body.permalink, _id: { $ne: common.getId(req.body.docId) } };
}
db.products.count(query, (err, products) => {
@ -430,16 +431,16 @@ router.post('/admin/api/validate_permalink', (req, res) => {
console.info(err.stack);
}
if(products > 0){
res.status(400).json({message: 'Permalink already exists'