Added permission validation to non admin users
parent
bf67621a86
commit
4533e23993
2
app.js
2
app.js
|
@ -235,7 +235,7 @@ app.use('/', customer);
|
||||||
app.use('/', product);
|
app.use('/', product);
|
||||||
app.use('/', order);
|
app.use('/', order);
|
||||||
app.use('/', user);
|
app.use('/', user);
|
||||||
app.use('/admin', admin);
|
app.use('/', admin);
|
||||||
app.use('/paypal', paypal);
|
app.use('/paypal', paypal);
|
||||||
app.use('/stripe', stripe);
|
app.use('/stripe', stripe);
|
||||||
app.use('/authorizenet', authorizenet);
|
app.use('/authorizenet', authorizenet);
|
||||||
|
|
|
@ -11,7 +11,35 @@ const nodemailer = require('nodemailer');
|
||||||
const escape = require('html-entities').AllHtmlEntities;
|
const escape = require('html-entities').AllHtmlEntities;
|
||||||
let ObjectId = require('mongodb').ObjectID;
|
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'}
|
||||||
|
];
|
||||||
|
|
||||||
// common functions
|
// common functions
|
||||||
|
exports.restrict = (req, res, next) => {
|
||||||
|
exports.checkLogin(req, res, next);
|
||||||
|
};
|
||||||
|
|
||||||
exports.checkLogin = (req, res, next) => {
|
exports.checkLogin = (req, res, next) => {
|
||||||
// if not protecting we check for public pages and don't checkLogin
|
// if not protecting we check for public pages and don't checkLogin
|
||||||
if(req.session.needsSetup === true){
|
if(req.session.needsSetup === true){
|
||||||
|
@ -26,6 +54,26 @@ exports.checkLogin = (req, res, next) => {
|
||||||
res.redirect('/admin/login');
|
res.redirect('/admin/login');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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) => {
|
exports.showCartCloseBtn = (page) => {
|
||||||
let showCartCloseButton = true;
|
let showCartCloseButton = true;
|
||||||
if(page === 'checkout' || page === 'pay'){
|
if(page === 'checkout' || page === 'pay'){
|
||||||
|
@ -64,10 +112,6 @@ exports.addSitemapProducts = (req, res, cb) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.restrict = (req, res, next) => {
|
|
||||||
exports.checkLogin(req, res, next);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.clearSessionValue = (session, sessionVar) => {
|
exports.clearSessionValue = (session, sessionVar) => {
|
||||||
let temp;
|
let temp;
|
||||||
if(session){
|
if(session){
|
||||||
|
|
|
@ -50,7 +50,7 @@ $(document).ready(function (){
|
||||||
showNotification(msg, 'success');
|
showNotification(msg, 'success');
|
||||||
})
|
})
|
||||||
.fail(function(msg){
|
.fail(function(msg){
|
||||||
showNotification(msg.responseText, 'danger');
|
showNotification(msg.responseJSON.message, 'danger');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -118,10 +118,10 @@ $(document).ready(function (){
|
||||||
data: {id: this.id, state: this.checked}
|
data: {id: this.id, state: this.checked}
|
||||||
})
|
})
|
||||||
.done(function(msg){
|
.done(function(msg){
|
||||||
showNotification(msg, 'success');
|
showNotification(msg.message, 'success');
|
||||||
})
|
})
|
||||||
.fail(function(msg){
|
.fail(function(msg){
|
||||||
showNotification(msg.responseText, 'danger');
|
showNotification(msg.responseJSON.message, 'danger');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -540,7 +540,7 @@ $(document).ready(function (){
|
||||||
showNotification(msg, 'success');
|
showNotification(msg, 'success');
|
||||||
})
|
})
|
||||||
.fail(function(msg){
|
.fail(function(msg){
|
||||||
showNotification(msg.responseText, 'danger');
|
showNotification(msg.responseJSON.message, 'danger');
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
showNotification('Please enter a permalink to validate', 'danger');
|
showNotification('Please enter a permalink to validate', 'danger');
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -10,12 +10,12 @@ const glob = require('glob');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
// Admin section
|
// Admin section
|
||||||
router.get('/', common.restrict, (req, res, next) => {
|
router.get('/admin', common.restrict, (req, res, next) => {
|
||||||
res.redirect('/admin/orders');
|
res.redirect('/admin/orders');
|
||||||
});
|
});
|
||||||
|
|
||||||
// logout
|
// logout
|
||||||
router.get('/logout', (req, res) => {
|
router.get('/admin/logout', (req, res) => {
|
||||||
req.session.user = null;
|
req.session.user = null;
|
||||||
req.session.message = null;
|
req.session.message = null;
|
||||||
req.session.messageType = null;
|
req.session.messageType = null;
|
||||||
|
@ -23,7 +23,7 @@ router.get('/logout', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// login form
|
// login form
|
||||||
router.get('/login', (req, res) => {
|
router.get('/admin/login', (req, res) => {
|
||||||
let db = req.app.db;
|
let db = req.app.db;
|
||||||
|
|
||||||
db.users.count({}, (err, userCount) => {
|
db.users.count({}, (err, userCount) => {
|
||||||
|
@ -54,7 +54,7 @@ router.get('/login', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// login the user and check the password
|
// login the user and check the password
|
||||||
router.post('/login_action', (req, res) => {
|
router.post('/admin/login_action', (req, res) => {
|
||||||
let db = req.app.db;
|
let db = req.app.db;
|
||||||
|
|
||||||
db.users.findOne({userEmail: req.body.email}, (err, user) => {
|
db.users.findOne({userEmail: req.body.email}, (err, user) => {
|
||||||
|
@ -92,7 +92,7 @@ router.post('/login_action', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// setup form is shown when there are no users setup in the DB
|
// setup form is shown when there are no users setup in the DB
|
||||||
router.get('/setup', (req, res) => {
|
router.get('/admin/setup', (req, res) => {
|
||||||
let db = req.app.db;
|
let db = req.app.db;
|
||||||
|
|
||||||
db.users.count({}, (err, userCount) => {
|
db.users.count({}, (err, userCount) => {
|
||||||
|
@ -119,7 +119,7 @@ router.get('/setup', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// insert a user
|
// insert a user
|
||||||
router.post('/setup_action', (req, res) => {
|
router.post('/admin/setup_action', (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
let doc = {
|
let doc = {
|
||||||
|
@ -156,7 +156,7 @@ router.post('/setup_action', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// settings update
|
// settings update
|
||||||
router.get('/settings', common.restrict, (req, res) => {
|
router.get('/admin/settings', common.restrict, (req, res) => {
|
||||||
res.render('settings', {
|
res.render('settings', {
|
||||||
title: 'Cart settings',
|
title: 'Cart settings',
|
||||||
session: req.session,
|
session: req.session,
|
||||||
|
@ -172,7 +172,7 @@ router.get('/settings', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// settings update
|
// settings update
|
||||||
router.post('/settings/update', common.restrict, (req, res) => {
|
router.post('/admin/settings/update', common.restrict, common.checkAccess, (req, res) => {
|
||||||
let result = common.updateConfig(req.body);
|
let result = common.updateConfig(req.body);
|
||||||
if(result === true){
|
if(result === true){
|
||||||
res.status(200).json({message: 'Settings successfully updated'});
|
res.status(200).json({message: 'Settings successfully updated'});
|
||||||
|
@ -182,7 +182,7 @@ router.post('/settings/update', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// settings update
|
// settings update
|
||||||
router.post('/settings/option/remove', common.restrict, (req, res) => {
|
router.post('/admin/settings/option/remove', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const 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){
|
||||||
|
@ -209,7 +209,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('/admin/settings/menu', common.restrict, async (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
res.render('settings_menu', {
|
res.render('settings_menu', {
|
||||||
title: 'Cart menu',
|
title: 'Cart menu',
|
||||||
|
@ -224,7 +224,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('/admin/settings/pages', common.restrict, (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
db.pages.find({}).toArray(async (err, pages) => {
|
db.pages.find({}).toArray(async (err, pages) => {
|
||||||
if(err){
|
if(err){
|
||||||
|
@ -246,7 +246,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('/admin/settings/pages/new', common.restrict, common.checkAccess, async (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
res.render('settings_page_edit', {
|
res.render('settings_page_edit', {
|
||||||
|
@ -263,7 +263,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('/admin/settings/pages/edit/:page', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const 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){
|
||||||
|
@ -299,7 +299,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('/admin/settings/pages/update', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
let doc = {
|
let doc = {
|
||||||
|
@ -339,7 +339,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('/admin/settings/pages/delete/:page', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const 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){
|
||||||
|
@ -355,7 +355,7 @@ router.get('/settings/pages/delete/:page', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// new menu item
|
// new menu item
|
||||||
router.post('/settings/menu/new', common.restrict, (req, res) => {
|
router.post('/admin/settings/menu/new', common.restrict, common.checkAccess, (req, res) => {
|
||||||
let result = common.newMenu(req, res);
|
let result = common.newMenu(req, res);
|
||||||
if(result === false){
|
if(result === false){
|
||||||
req.session.message = 'Failed creating menu.';
|
req.session.message = 'Failed creating menu.';
|
||||||
|
@ -365,7 +365,7 @@ router.post('/settings/menu/new', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// update existing menu item
|
// update existing menu item
|
||||||
router.post('/settings/menu/update', common.restrict, (req, res) => {
|
router.post('/admin/settings/menu/update', common.restrict, common.checkAccess, (req, res) => {
|
||||||
let result = common.updateMenu(req, res);
|
let result = common.updateMenu(req, res);
|
||||||
if(result === false){
|
if(result === false){
|
||||||
req.session.message = 'Failed updating menu.';
|
req.session.message = 'Failed updating menu.';
|
||||||
|
@ -375,7 +375,7 @@ router.post('/settings/menu/update', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// delete menu item
|
// delete menu item
|
||||||
router.get('/settings/menu/delete/:menuid', common.restrict, (req, res) => {
|
router.get('/admin/settings/menu/delete/:menuid', common.restrict, common.checkAccess, (req, res) => {
|
||||||
let result = common.deleteMenu(req, res, req.params.menuid);
|
let result = common.deleteMenu(req, res, req.params.menuid);
|
||||||
if(result === false){
|
if(result === false){
|
||||||
req.session.message = 'Failed deleting menu.';
|
req.session.message = 'Failed deleting menu.';
|
||||||
|
@ -385,7 +385,7 @@ router.get('/settings/menu/delete/:menuid', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// We call this via a Ajax call to save the order from the sortable list
|
// We call this via a Ajax call to save the order from the sortable list
|
||||||
router.post('/settings/menu/save_order', common.restrict, (req, res) => {
|
router.post('/admin/settings/menu/save_order', common.restrict, common.checkAccess, (req, res) => {
|
||||||
let result = common.orderMenu(req, res);
|
let result = common.orderMenu(req, res);
|
||||||
if(result === false){
|
if(result === false){
|
||||||
res.status(400).json({message: 'Failed saving menu order'});
|
res.status(400).json({message: 'Failed saving menu order'});
|
||||||
|
@ -395,7 +395,7 @@ router.post('/settings/menu/save_order', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// validate the permalink
|
// validate the permalink
|
||||||
router.post('/api/validate_permalink', (req, res) => {
|
router.post('/admin/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
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
@ -412,18 +412,16 @@ router.post('/api/validate_permalink', (req, res) => {
|
||||||
console.info(err.stack);
|
console.info(err.stack);
|
||||||
}
|
}
|
||||||
if(products > 0){
|
if(products > 0){
|
||||||
res.writeHead(400, {'Content-Type': 'application/text'});
|
res.status(400).json({message: 'Permalink already exists'});
|
||||||
res.end('Permalink already exists');
|
|
||||||
}else{
|
}else{
|
||||||
res.writeHead(200, {'Content-Type': 'application/text'});
|
res.status(200).json({message: 'Permalink validated successfully'});
|
||||||
res.end('Permalink validated successfully');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// upload the file
|
// upload the file
|
||||||
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('/admin/file/upload', common.restrict, common.checkAccess, upload.single('upload_file'), (req, res, next) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
if(req.file){
|
if(req.file){
|
||||||
|
@ -479,15 +477,15 @@ 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('/admin/testEmail', common.restrict, (req, res) => {
|
||||||
let config = common.getConfig();
|
let config = common.getConfig();
|
||||||
// TODO: Should fix this to properly handle result
|
// 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({message: 'Test email sent'});
|
||||||
});
|
});
|
||||||
|
|
||||||
// delete a file via ajax request
|
// delete a file via ajax request
|
||||||
router.post('/file/delete', common.restrict, (req, res) => {
|
router.post('/admin/file/delete', common.restrict, common.checkAccess, (req, res) => {
|
||||||
req.session.message = null;
|
req.session.message = null;
|
||||||
req.session.messageType = null;
|
req.session.messageType = null;
|
||||||
|
|
||||||
|
@ -503,7 +501,7 @@ router.post('/file/delete', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/files', common.restrict, (req, res) => {
|
router.get('/admin/files', common.restrict, (req, res) => {
|
||||||
// loop files in /public/uploads/
|
// loop files in /public/uploads/
|
||||||
glob('public/uploads/**', {nosort: true}, (er, files) => {
|
glob('public/uploads/**', {nosort: true}, (er, files) => {
|
||||||
// sort array
|
// sort array
|
||||||
|
|
|
@ -131,7 +131,7 @@ router.get('/admin/order/delete/:id', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// update order status
|
// update order status
|
||||||
router.post('/admin/order/statusupdate', common.restrict, (req, res) => {
|
router.post('/admin/order/statusupdate', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const 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){
|
||||||
|
|
|
@ -74,7 +74,7 @@ router.get('/admin/product/new', common.restrict, common.checkAccess, (req, res)
|
||||||
});
|
});
|
||||||
|
|
||||||
// insert new product form action
|
// insert new product form action
|
||||||
router.post('/admin/product/insert', common.restrict, (req, res) => {
|
router.post('/admin/product/insert', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
let doc = {
|
let doc = {
|
||||||
|
@ -145,7 +145,7 @@ router.post('/admin/product/insert', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// render the editor
|
// render the editor
|
||||||
router.get('/admin/product/edit/:id', common.restrict, (req, res) => {
|
router.get('/admin/product/edit/:id', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const 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) => {
|
||||||
|
@ -176,7 +176,7 @@ router.get('/admin/product/edit/:id', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update an existing product form action
|
// Update an existing product form action
|
||||||
router.post('/admin/product/update', common.restrict, (req, res) => {
|
router.post('/admin/product/update', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const 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) => {
|
||||||
|
@ -256,7 +256,7 @@ router.post('/admin/product/update', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// delete product
|
// delete product
|
||||||
router.get('/admin/product/delete/:id', common.restrict, (req, res) => {
|
router.get('/admin/product/delete/:id', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
// remove the article
|
// remove the article
|
||||||
|
@ -283,23 +283,21 @@ router.get('/admin/product/delete/:id', common.restrict, (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('/admin/product/published_state', common.restrict, (req, res) => {
|
router.post('/admin/product/published_state', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const 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){
|
||||||
console.error(colors.red('Failed to update the published state: ' + err));
|
console.error(colors.red('Failed to update the published state: ' + err));
|
||||||
res.writeHead(400, {'Content-Type': 'application/text'});
|
res.status(400).json('Published state not updated');
|
||||||
res.end('Published state not updated');
|
|
||||||
}else{
|
}else{
|
||||||
res.writeHead(200, {'Content-Type': 'application/text'});
|
res.status(200).json('Published state updated');
|
||||||
res.end('Published state updated');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// set as main product image
|
// set as main product image
|
||||||
router.post('/admin/product/setasmainimage', common.restrict, (req, res) => {
|
router.post('/admin/product/setasmainimage', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
// update the productImage to the db
|
// update the productImage to the db
|
||||||
|
@ -313,7 +311,7 @@ router.post('/admin/product/setasmainimage', common.restrict, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// deletes a product image
|
// deletes a product image
|
||||||
router.post('/admin/product/deleteimage', common.restrict, (req, res) => {
|
router.post('/admin/product/deleteimage', common.restrict, common.checkAccess, (req, res) => {
|
||||||
const db = req.app.db;
|
const db = req.app.db;
|
||||||
|
|
||||||
// get the productImage from the db
|
// get the productImage from the db
|
||||||
|
|
|
@ -2,15 +2,19 @@
|
||||||
<h2>Menu</h2>
|
<h2>Menu</h2>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item"><strong>Products</strong></li>
|
<li class="list-group-item"><strong>Products</strong></li>
|
||||||
|
{{#ifCond session.isAdmin '===' 'true'}}
|
||||||
<li class="list-group-item"><i class="fa fa-plus-square-o fa-icon" aria-hidden="true"></i> <a href="/admin/product/new">New</a></li>
|
<li class="list-group-item"><i class="fa fa-plus-square-o fa-icon" aria-hidden="true"></i> <a href="/admin/product/new">New</a></li>
|
||||||
|
{{/ifCond}}
|
||||||
<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"><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"><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>
|
||||||
|
{{#ifCond session.isAdmin '===' 'true'}}
|
||||||
<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>
|
||||||
|
{{/ifCond}}
|
||||||
<li class="list-group-item"><i class="fa fa-user-circle-o fa-icon" aria-hidden="true"></i> <a href="/admin/user/edit/{{session.userId}}">My Account</a></li>
|
<li class="list-group-item"><i class="fa fa-user-circle-o fa-icon" aria-hidden="true"></i> <a href="/admin/user/edit/{{session.userId}}">My Account</a></li>
|
||||||
<li class="list-group-item"><strong>Settings</strong></li>
|
<li class="list-group-item"><strong>Settings</strong></li>
|
||||||
<li class="list-group-item"><i class="fa fa-cog fa-icon" aria-hidden="true"></i> <a href="/admin/settings">General settings</a></li>
|
<li class="list-group-item"><i class="fa fa-cog fa-icon" aria-hidden="true"></i> <a href="/admin/settings">General settings</a></li>
|
||||||
|
|
|
@ -1,145 +1,159 @@
|
||||||
{{> menu}}
|
{{> menu}}
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-10">
|
<div class="col-md-10">
|
||||||
<form method="post" id="settingsForm" action="/admin/settings/update" data-toggle="validator">
|
<form method="post" id="settingsForm" action="/admin/settings/update" data-toggle="validator">
|
||||||
<h2 class="clearfix">General Settings <div class="pull-right"><button type="submit" id="btnSettingsUpdate" class="btn btn-success">Update</button></h2>
|
<h2 class="clearfix">General Settings
|
||||||
<div class="form-group">
|
<div class="pull-right">
|
||||||
<label>Cart name *</label>
|
<button type="submit" id="btnSettingsUpdate" class="btn btn-success">Update</button>
|
||||||
<input type="text" class="form-control" name="cartTitle" value="{{config.cartTitle}}" required>
|
</h2>
|
||||||
<p class="help-block">
|
<div class="form-group">
|
||||||
This element is critical for search engine optimisation. Cart title is displayed if your logo is hidden.
|
<label>Cart name *</label>
|
||||||
</p>
|
<input type="text" class="form-control" name="cartTitle" value="{{config.cartTitle}}" required>
|
||||||
</div>
|
<p class="help-block">
|
||||||
<div class="form-group">
|
This element is critical for search engine optimisation. Cart title is displayed if your logo is hidden.
|
||||||
<label>Cart description *</label>
|
</p>
|
||||||
<input type="text" class="form-control" name="cartDescription" value="{{config.cartDescription}}" required>
|
</div>
|
||||||
<p class="help-block">This description shows when your website is listed in search engine results.</p>
|
<div class="form-group">
|
||||||
</div>
|
<label>Cart description *</label>
|
||||||
<div class="form-group">
|
<input type="text" class="form-control" name="cartDescription" value="{{config.cartDescription}}" required>
|
||||||
<label>Cart image/logo</label>
|
<p class="help-block">This description shows when your website is listed in search engine results.</p>
|
||||||
<input type="text" class="form-control" name="cartLogo" value="{{config.cartLogo}}">
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label>Cart image/logo</label>
|
||||||
<label>Cart URL *</label>
|
<input type="text" class="form-control" name="cartLogo" value="{{config.cartLogo}}">
|
||||||
<input type="text" class="form-control" name="baseUrl" value="{{config.baseUrl}}" required>
|
</div>
|
||||||
<p class="help-block">This URL is used in sitemaps and when your customer returns from completing their payment.</p>
|
<div class="form-group">
|
||||||
</div>
|
<label>Cart URL *</label>
|
||||||
<div class="form-group">
|
<input type="text" class="form-control" name="baseUrl" value="{{config.baseUrl}}" required>
|
||||||
<label>Cart Email *</label>
|
<p class="help-block">This URL is used in sitemaps and when your customer returns from completing their payment.</p>
|
||||||
<input type="email" class="form-control" name="emailAddress" value="{{config.emailAddress}}" required>
|
</div>
|
||||||
<p class="help-block">This is used as the "from" email when sending receipts to your customers.</p>
|
<div class="form-group">
|
||||||
</div>
|
<label>Cart Email *</label>
|
||||||
<div class="form-group">
|
<input type="email" class="form-control" name="emailAddress" value="{{config.emailAddress}}" required>
|
||||||
<label>Flat shipping rate *</label>
|
<p class="help-block">This is used as the "from" email when sending receipts to your customers.</p>
|
||||||
<input type="text" class="form-control" name="flatShipping" value="{{config.flatShipping}}" required>
|
</div>
|
||||||
<p class="help-block">A flat shipping rate applied to all orders.</p>
|
<div class="form-group">
|
||||||
</div>
|
<label>Flat shipping rate *</label>
|
||||||
<div class="form-group">
|
<input type="text" class="form-control" name="flatShipping" value="{{config.flatShipping}}" required>
|
||||||
<label>Free shipping threshold</label>
|
<p class="help-block">A flat shipping rate applied to all orders.</p>
|
||||||
<input type="text" class="form-control" name="freeShippingAmount" value="{{config.freeShippingAmount}}">
|
</div>
|
||||||
<p class="help-block">Orders over this value will mean the shipped will the FREE. Set to high value if you always want to charge shipping.</p>
|
<div class="form-group">
|
||||||
</div>
|
<label>Free shipping threshold</label>
|
||||||
<div class="form-group">
|
<input type="text" class="form-control" name="freeShippingAmount" value="{{config.freeShippingAmount}}">
|
||||||
<label>Payment gateway</label>
|
<p class="help-block">Orders over this value will mean the shipped will the FREE. Set to high value if you always want to charge
|
||||||
<select class="form-control" name="paymentGateway">
|
shipping.</p>
|
||||||
<option {{selectState 'paypal' config.paymentGateway}} value="paypal">Paypal</option>
|
</div>
|
||||||
<option {{selectState 'stripe' config.paymentGateway}} value="stripe">Stripe</option>
|
<div class="form-group">
|
||||||
</select>
|
<label>Payment gateway</label>
|
||||||
<p class="help-block">You will also need to configure your payment gateway credentials in the `/config/<gateway_name>.json` file.</p>
|
<select class="form-control" name="paymentGateway">
|
||||||
</div>
|
<option {{selectState 'paypal' config.paymentGateway}} value="paypal">Paypal</option>
|
||||||
<div class="form-group">
|
<option {{selectState 'stripe' config.paymentGateway}} value="stripe">Stripe</option>
|
||||||
<label>Currency symbol</label>
|
</select>
|
||||||
<input type="text" class="form-control" name="currencySymbol" value="{{currencySymbol config.currencySymbol}}">
|
<p class="help-block">You will also need to configure your payment gateway credentials in the `/config/<gateway_name>.json`
|
||||||
<p class="help-block">Set this to your currency symbol. Eg: $, £, €</p>
|
file.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Theme</label>
|
<label>Currency symbol</label>
|
||||||
<select class="form-control" name="theme">
|
<input type="text" class="form-control" name="currencySymbol" value="{{currencySymbol config.currencySymbol}}">
|
||||||
<option {{selectState '' config.theme}} value="">Default</option>
|
<p class="help-block">Set this to your currency symbol. Eg: $, £, €</p>
|
||||||
{{#each themes}}
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Theme</label>
|
||||||
|
<select class="form-control" name="theme">
|
||||||
|
<option {{selectState '' config.theme}} value="">Default</option>
|
||||||
|
{{#each themes}}
|
||||||
<option {{selectState this ../config.theme}} value="{{this}}">{{this}}</option>
|
<option {{selectState this ../config.theme}} value="{{this}}">{{this}}</option>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</select>
|
</select>
|
||||||
<p class="help-block">Themes are loaded from `/public/themes/`</p>
|
<p class="help-block">Themes are loaded from `/public/themes/`</p>
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Products per row</label>
|
|
||||||
<select class="form-control" name="productsPerRow">
|
|
||||||
<option value="{{config.productsPerRow}}" hidden="hidden" selected="selected">{{config.productsPerRow}}</option>
|
|
||||||
<option {{selectState '1' config.productsPerRow}}>1</option>
|
|
||||||
<option {{selectState '2' config.productsPerRow}}>2</option>
|
|
||||||
<option {{selectState '3' config.productsPerRow}}>3</option>
|
|
||||||
<option {{selectState '4' config.productsPerRow}}>4</option>
|
|
||||||
</select>
|
|
||||||
<p class="help-block">The number of products to be displayed across the page.</p>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Products per page</label>
|
|
||||||
<input type="number" class="form-control" name="productsPerPage" value="{{config.productsPerPage}}">
|
|
||||||
<p class="help-block">The number of products to be displayed on each page.</p>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Menu Enabled: </label>
|
|
||||||
<div class="checkbox">
|
|
||||||
<label><input class="settingsMenuEnabled" type="checkbox" {{checkedState config.menuEnabled}} id="menuEnabled" name="menuEnabled"></label>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">If a menu is set you can set it up <a href="/admin/settings/menu">here</a>.</p>
|
<div class="form-group">
|
||||||
</div>
|
<label>Products per row</label>
|
||||||
<div class="form-group">
|
<select class="form-control" name="productsPerRow">
|
||||||
<label>Menu header</label>
|
<option value="{{config.productsPerRow}}" hidden="hidden" selected="selected">{{config.productsPerRow}}</option>
|
||||||
<input type="text" class="form-control" name="menuTitle" value="{{config.menuTitle}}" placeholder="Menu">
|
<option {{selectState '1' config.productsPerRow}}>1</option>
|
||||||
<p class="help-block">The heading text for your menu.</p>
|
<option {{selectState '2' config.productsPerRow}}>2</option>
|
||||||
</div>
|
<option {{selectState '3' config.productsPerRow}}>3</option>
|
||||||
<div class="form-group">
|
<option {{selectState '4' config.productsPerRow}}>4</option>
|
||||||
<label>Menu location: </label>
|
</select>
|
||||||
<select class="form-control" name="menuLocation">
|
<p class="help-block">The number of products to be displayed across the page.</p>
|
||||||
<option {{selectState 'top' config.menuLocation}}>top</option>
|
|
||||||
<option {{selectState 'side' config.menuLocation}}>side</option>
|
|
||||||
</select>
|
|
||||||
<p class="help-block">The location of your menu.</p>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Footer HTML</label>
|
|
||||||
<textarea class="form-control codemirrorArea" rows="5" id="footerHtml" name="footerHtml">{{footerHtml}}</textarea>
|
|
||||||
<input type="hidden" id="footerHtml_input" name="footerHtml_input">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Google analytics</label>
|
|
||||||
<textarea class="form-control" rows="3" id="googleAnalytics" name="googleAnalytics">{{googleAnalytics}}</textarea>
|
|
||||||
<input type="hidden" id="googleAnalytics_input" name="googleAnalytics_input">
|
|
||||||
<p class="help-block">Your Google Analytics code. Please also inlude the "script" tags - <a href="https://support.google.com/analytics/answer/1032385?hl=en" target="_blank">Help</a></p>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Custom CSS</label>
|
|
||||||
<textarea class="form-control" rows="10" id="customCss" name="customCss">{{config.customCss}}</textarea>
|
|
||||||
<input type="hidden" id="customCss_input" name="customCss_input">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Email SMTP Host</label>
|
|
||||||
<input type="text" class="form-control" name="emailHost" value="{{config.emailHost}}" autocomplete="off" required>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Email SMTP Port</label>
|
|
||||||
<input type="text" class="form-control" name="emailPort" value="{{config.emailPort}}" autocomplete="off" required>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Email SMTP secure </label>
|
|
||||||
<div class="checkbox">
|
|
||||||
<label><input class="settingsMenuEnabled" type="checkbox" {{checkedState config.emailSecure}} name="emailSecure"></label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label>Products per page</label>
|
||||||
<label>Email SMTP Username</label>
|
<input type="number" class="form-control" name="productsPerPage" value="{{config.productsPerPage}}">
|
||||||
<input type="text" class="form-control" name="emailUser" value="{{config.emailUser}}" autocomplete="off" required>
|
<p class="help-block">The number of products to be displayed on each page.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Email SMTP Password</label>
|
<label>Menu Enabled: </label>
|
||||||
<input type="password" class="form-control" name="emailPassword" value="{{config.emailPassword}}" autocomplete="off" required>
|
<div class="checkbox">
|
||||||
</div>
|
<label>
|
||||||
<div class="form-group">
|
<input class="settingsMenuEnabled" type="checkbox" {{checkedState config.menuEnabled}} id="menuEnabled"
|
||||||
<button id="sendTestEmail" class="btn btn-success">Send test email</button>
|
name="menuEnabled">
|
||||||
</div>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<p class="help-block">If a menu is set you can set it up
|
||||||
</div>
|
<a href="/admin/settings/menu">here</a>.</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Menu header</label>
|
||||||
|
<input type="text" class="form-control" name="menuTitle" value="{{config.menuTitle}}" placeholder="Menu">
|
||||||
|
<p class="help-block">The heading text for your menu.</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Menu location: </label>
|
||||||
|
<select class="form-control" name="menuLocation">
|
||||||
|
<option {{selectState 'top' config.menuLocation}}>top</option>
|
||||||
|
<option {{selectState 'side' config.menuLocation}}>side</option>
|
||||||
|
</select>
|
||||||
|
<p class="help-block">The location of your menu.</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Footer HTML</label>
|
||||||
|
<textarea class="form-control codemirrorArea" rows="5" id="footerHtml" name="footerHtml">{{footerHtml}}</textarea>
|
||||||
|
<input type="hidden" id="footerHtml_input" name="footerHtml_input">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Google analytics</label>
|
||||||
|
<textarea class="form-control" rows="3" id="googleAnalytics" name="googleAnalytics">{{googleAnalytics}}</textarea>
|
||||||
|
<input type="hidden" id="googleAnalytics_input" name="googleAnalytics_input">
|
||||||
|
<p class="help-block">Your Google Analytics code. Please also inlude the "script" tags -
|
||||||
|
<a href="https://support.google.com/analytics/answer/1032385?hl=en"
|
||||||
|
target="_blank">Help</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Custom CSS</label>
|
||||||
|
<textarea class="form-control" rows="10" id="customCss" name="customCss">{{config.customCss}}</textarea>
|
||||||
|
<input type="hidden" id="customCss_input" name="customCss_input">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Email SMTP Host</label>
|
||||||
|
<input type="text" class="form-control" name="emailHost" value="{{config.emailHost}}" autocomplete="off" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Email SMTP Port</label>
|
||||||
|
<input type="text" class="form-control" name="emailPort" value="{{config.emailPort}}" autocomplete="off" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Email SMTP secure </label>
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input class="settingsMenuEnabled" type="checkbox" {{checkedState config.emailSecure}} name="emailSecure">
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Email SMTP Username</label>
|
||||||
|
<input type="text" class="form-control" name="emailUser" value="{{config.emailUser}}" autocomplete="off" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Email SMTP Password</label>
|
||||||
|
<input type="password" class="form-control" name="emailPassword" value="{{config.emailPassword}}" autocomplete="off" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button id="sendTestEmail" class="btn btn-success">Send test email</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
Loading…
Reference in New Issue