expressCart/routes/index.js

920 lines
30 KiB
JavaScript
Raw Normal View History

2018-01-07 04:55:48 +10:00
const express = require('express');
const router = express.Router();
const colors = require('colors');
const hash = require('object-hash');
2020-01-23 20:58:21 +10:00
const stripHtml = require('string-strip-html');
const moment = require('moment');
2018-01-07 04:55:48 +10:00
const _ = require('lodash');
2019-06-15 15:52:32 +10:00
const {
getId,
hooker,
clearSessionValue,
sortMenu,
getMenu,
getPaymentConfig,
getImages,
2019-12-30 13:10:57 +10:00
updateTotalCart,
2020-01-02 15:23:39 +10:00
emptyCart,
updateSubscriptionCheck,
2020-03-19 16:32:22 +10:00
paginateData,
addSitemapProducts,
getCountryList
} = require('../lib/common');
const countryList = getCountryList();
2018-01-07 04:55:48 +10:00
2018-02-05 23:20:44 +10:00
// These is the customer facing routes
router.get('/payment/:orderId', async (req, res, next) => {
2019-07-12 18:06:34 +10:00
const db = req.app.db;
const config = req.app.config;
2018-01-07 04:55:48 +10:00
2019-10-26 11:08:53 +10:00
// Get the order
const order = await db.orders.findOne({ _id: getId(req.params.orderId) });
if(!order){
res.render('error', { title: 'Not found', message: 'Order not found', helpers: req.handlebars.helpers, config });
return;
}
2019-02-09 14:07:02 +10:00
2019-10-26 11:08:53 +10:00
// If stock management is turned on payment approved update stock level
if(config.trackStock && req.session.paymentApproved){
// Check to see if already updated to avoid duplicate updating of stock
if(order.productStockUpdated !== true){
Object.keys(order.orderProducts).forEach(async (productKey) => {
const product = order.orderProducts[productKey];
const dbProduct = await db.products.findOne({ _id: getId(product.productId) });
let newStockLevel = dbProduct.productStock - product.quantity;
if(newStockLevel < 1){
newStockLevel = 0;
2019-10-26 11:08:53 +10:00
}
// Update product stock
await db.products.updateOne({
_id: getId(product.productId)
}, {
$set: {
productStock: newStockLevel
}
}, { multi: false });
// Add stock updated flag to order
await db.orders.updateOne({
_id: getId(order._id)
}, {
$set: {
productStockUpdated: true
}
}, { multi: false });
});
console.info('Updated stock levels');
}
2019-10-26 11:08:53 +10:00
}
2019-02-09 14:07:02 +10:00
2019-10-26 11:08:53 +10:00
// If hooks are configured, send hook
if(config.orderHook){
await hooker(order);
};
let paymentView = `${config.themeViews}payment-complete`;
if(order.orderPaymentGateway === 'Blockonomics') paymentView = `${config.themeViews}payment-complete-blockonomics`;
res.render(paymentView, {
2019-10-26 11:08:53 +10:00
title: 'Payment complete',
config: req.app.config,
session: req.session,
result: order,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
helpers: req.handlebars.helpers,
showFooter: 'showFooter',
menu: sortMenu(await getMenu(db))
2018-01-07 04:55:48 +10:00
});
});
router.get('/emptycart', async (req, res, next) => {
emptyCart(req, res, '');
});
router.get('/checkout/information', async (req, res, next) => {
2019-07-12 18:06:34 +10:00
const config = req.app.config;
2018-01-07 04:55:48 +10:00
// if there is no items in the cart then render a failure
if(!req.session.cart){
req.session.message = 'The are no items in your cart. Please add some items before checking out';
req.session.messageType = 'danger';
res.redirect('/');
return;
}
let paymentType = '';
if(req.session.cartSubscription){
paymentType = '_subscription';
}
// render the payment page
res.render(`${config.themeViews}checkout-information`, {
2020-01-24 14:42:49 +10:00
title: 'Checkout - Information',
2018-02-23 03:41:24 +10:00
config: req.app.config,
2018-01-07 04:55:48 +10:00
session: req.session,
paymentType,
cartClose: false,
page: 'checkout-information',
countryList,
2019-06-15 15:52:32 +10:00
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
2018-01-07 04:55:48 +10:00
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
2018-01-07 04:55:48 +10:00
});
});
router.get('/checkout/shipping', async (req, res, next) => {
2018-02-23 03:41:24 +10:00
const config = req.app.config;
2018-01-07 04:55:48 +10:00
// if there is no items in the cart then render a failure
if(!req.session.cart){
req.session.message = 'The are no items in your cart. Please add some items before checking out';
req.session.messageType = 'danger';
res.redirect('/');
2018-01-07 04:55:48 +10:00
return;
}
if(!req.session.customerEmail){
req.session.message = 'Cannot proceed to shipping without customer information';
req.session.messageType = 'danger';
res.redirect('/checkout/information');
return;
}
// Net cart amount
const netCartAmount = req.session.totalCartAmount - req.session.totalCartShipping || 0;
// Recalculate shipping
config.modules.loaded.shipping.calculateShipping(
netCartAmount,
config,
req
);
2018-01-07 04:55:48 +10:00
// render the payment page
res.render(`${config.themeViews}checkout-shipping`, {
2020-01-24 14:42:49 +10:00
title: 'Checkout - Shipping',
2018-02-23 03:41:24 +10:00
config: req.app.config,
2018-01-07 04:55:48 +10:00
session: req.session,
cartClose: false,
cartReadOnly: true,
page: 'checkout-shipping',
countryList,
2019-06-15 15:52:32 +10:00
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
2018-01-07 04:55:48 +10:00
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
2018-01-07 04:55:48 +10:00
});
});
router.get('/checkout/cart', (req, res) => {
2018-02-23 03:41:24 +10:00
const config = req.app.config;
2018-02-14 06:21:22 +10:00
res.render(`${config.themeViews}checkout-cart`, {
2020-01-24 14:42:49 +10:00
title: 'Checkout - Cart',
2018-01-07 04:55:48 +10:00
page: req.query.path,
config,
session: req.session,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
2018-01-07 04:55:48 +10:00
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
});
});
2019-12-30 13:10:57 +10:00
router.get('/checkout/cartdata', (req, res) => {
const config = req.app.config;
res.status(200).json({
cart: req.session.cart,
session: req.session,
currencySymbol: config.currencySymbol || '$'
});
2019-12-30 13:10:57 +10:00
});
router.get('/checkout/payment', async (req, res) => {
const config = req.app.config;
// if there is no items in the cart then render a failure
if(!req.session.cart){
req.session.message = 'The are no items in your cart. Please add some items before checking out';
req.session.messageType = 'danger';
res.redirect('/');
return;
}
let paymentType = '';
if(req.session.cartSubscription){
paymentType = '_subscription';
}
// update total cart amount one last time before payment
await updateTotalCart(req, res);
res.render(`${config.themeViews}checkout-payment`, {
2020-01-24 14:42:49 +10:00
title: 'Checkout - Payment',
2018-02-23 03:41:24 +10:00
config: req.app.config,
paymentConfig: getPaymentConfig(),
session: req.session,
paymentPage: true,
paymentType,
cartClose: true,
cartReadOnly: true,
page: 'checkout-information',
countryList,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
2018-01-07 04:55:48 +10:00
});
});
router.get('/blockonomics_payment', (req, res, next) => {
const config = req.app.config;
let paymentType = '';
if(req.session.cartSubscription){
paymentType = '_subscription';
}
// show bitcoin address and wait for payment, subscribing to wss
res.render(`${config.themeViews}checkout-blockonomics`, {
title: 'Checkout - Payment',
config: req.app.config,
paymentConfig: getPaymentConfig(),
session: req.session,
paymentPage: true,
paymentType,
cartClose: true,
cartReadOnly: true,
page: 'checkout-information',
countryList,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
});
});
router.post('/checkout/adddiscountcode', async (req, res) => {
const config = req.app.config;
const db = req.app.db;
// if there is no items in the cart return a failure
if(!req.session.cart){
res.status(400).json({
message: 'The are no items in your cart.'
});
return;
}
// Check if the discount module is loaded
if(!config.modules.loaded.discount){
res.status(400).json({
message: 'Access denied.'
});
return;
}
// Check defined or null
if(!req.body.discountCode || req.body.discountCode === ''){
res.status(400).json({
message: 'Discount code is invalid or expired'
});
return;
}
// Validate discount code
const discount = await db.discounts.findOne({ code: req.body.discountCode });
if(!discount){
res.status(400).json({
message: 'Discount code is invalid or expired'
});
return;
}
// Validate date validity
if(!moment().isBetween(moment(discount.start), moment(discount.end))){
res.status(400).json({
message: 'Discount is expired'
});
return;
}
// Set the discount code
req.session.discountCode = discount.code;
// Update the cart amount
await updateTotalCart(req, res);
// Return the message
res.status(200).json({
message: 'Discount code applied'
});
});
router.post('/checkout/removediscountcode', async (req, res) => {
// if there is no items in the cart return a failure
if(!req.session.cart){
res.status(400).json({
message: 'The are no items in your cart.'
});
return;
}
// Delete the discount code
delete req.session.discountCode;
// update total cart amount
await updateTotalCart(req, res);
// Return the message
res.status(200).json({
message: 'Discount code removed'
});
});
2018-01-07 04:55:48 +10:00
// show an individual product
2019-10-26 11:08:53 +10:00
router.get('/product/:id', async (req, res) => {
2019-07-12 18:06:34 +10:00
const db = req.app.db;
const config = req.app.config;
2020-03-22 14:44:45 +10:00
const productsIndex = req.app.productsIndex;
2018-01-07 04:55:48 +10:00
2019-10-26 11:08:53 +10:00
const product = await db.products.findOne({ $or: [{ _id: getId(req.params.id) }, { productPermalink: req.params.id }] });
if(!product){
res.render('error', { title: 'Not found', message: 'Order not found', helpers: req.handlebars.helpers, config });
return;
}
if(product.productPublished === false){
res.render('error', { title: 'Not found', message: 'Product not found', helpers: req.handlebars.helpers, config });
return;
}
const productOptions = product.productOptions;
2018-01-07 04:55:48 +10:00
2019-10-26 11:08:53 +10:00
// If JSON query param return json instead
if(req.query.json === 'true'){
res.status(200).json(product);
return;
}
2018-02-23 03:41:24 +10:00
2019-10-26 11:08:53 +10:00
// show the view
const images = await getImages(product._id, req, res);
2020-03-22 14:44:45 +10:00
// Related products
let relatedProducts = {};
if(config.showRelatedProducts){
const lunrIdArray = [];
const productTags = product.productTags.split(',');
const productTitleWords = product.productTitle.split(' ');
const searchWords = productTags.concat(productTitleWords);
searchWords.forEach((word) => {
productsIndex.search(word).forEach((id) => {
lunrIdArray.push(getId(id.ref));
});
});
relatedProducts = await db.products.find({
_id: { $in: lunrIdArray, $ne: product._id }
}).limit(4).toArray();
}
2019-10-26 11:08:53 +10:00
res.render(`${config.themeViews}product`, {
title: product.productTitle,
result: product,
productOptions: productOptions,
images: images,
2020-03-22 14:44:45 +10:00
relatedProducts,
2020-01-23 20:58:21 +10:00
productDescription: stripHtml(product.productDescription),
2019-10-26 11:08:53 +10:00
metaDescription: config.cartTitle + ' - ' + product.productTitle,
config: config,
session: req.session,
pageUrl: config.baseUrl + req.originalUrl,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
helpers: req.handlebars.helpers,
showFooter: 'showFooter',
menu: sortMenu(await getMenu(db))
2018-01-07 04:55:48 +10:00
});
});
// Gets the current cart
router.get('/cart/retrieve', async (req, res, next) => {
const db = req.app.db;
// Get the cart from the DB using the session id
const cart = await db.cart.findOne({ sessionId: getId(req.session.id) });
res.status(200).json({ cart: cart.cart });
});
2018-02-04 01:23:59 +10:00
// Updates a single product quantity
2019-12-30 13:10:57 +10:00
router.post('/product/updatecart', async (req, res, next) => {
2018-02-04 01:23:59 +10:00
const db = req.app.db;
2019-02-09 20:46:41 +10:00
const config = req.app.config;
2019-12-30 13:10:57 +10:00
const cartItem = req.body;
// Check cart exists
if(!req.session.cart){
emptyCart(req, res, 'json', 'There are no items if your cart or your cart is expired');
return;
}
2020-03-20 13:10:45 +10:00
const product = await db.products.findOne({ _id: getId(cartItem.productId) });
if(!product){
res.status(400).json({ message: 'There was an error updating the cart', totalCartItems: Object.keys(req.session.cart).length });
return;
}
2019-12-30 13:10:57 +10:00
// Calculate the quantity to update
let productQuantity = cartItem.quantity ? cartItem.quantity : 1;
if(typeof productQuantity === 'string'){
productQuantity = parseInt(productQuantity);
}
2019-12-30 13:10:57 +10:00
if(productQuantity === 0){
// quantity equals zero so we remove the item
delete req.session.cart[cartItem.cartId];
2019-12-30 13:10:57 +10:00
res.status(400).json({ message: 'There was an error updating the cart', totalCartItems: Object.keys(req.session.cart).length });
return;
}
2019-12-30 13:10:57 +10:00
// If stock management on check there is sufficient stock for this product
2020-03-20 13:10:45 +10:00
if(config.trackStock && product.productStock){
2019-12-30 13:10:57 +10:00
if(productQuantity > product.productStock){
res.status(400).json({ message: 'There is insufficient stock of this product.', totalCartItems: Object.keys(req.session.cart).length });
return;
}
2019-12-30 13:10:57 +10:00
}
2019-12-30 13:10:57 +10:00
const productPrice = parseFloat(product.productPrice).toFixed(2);
if(!req.session.cart[cartItem.cartId]){
2019-12-30 13:10:57 +10:00
res.status(400).json({ message: 'There was an error updating the cart', totalCartItems: Object.keys(req.session.cart).length });
return;
}
2018-02-04 01:23:59 +10:00
2019-12-30 13:10:57 +10:00
// Update the cart
req.session.cart[cartItem.cartId].quantity = productQuantity;
req.session.cart[cartItem.cartId].totalItemPrice = productPrice * productQuantity;
2019-12-30 13:10:57 +10:00
// update total cart amount
await updateTotalCart(req, res);
2019-12-30 13:10:57 +10:00
// Update checking cart for subscription
updateSubscriptionCheck(req, res);
// Update cart to the DB
await db.cart.updateOne({ sessionId: req.session.id }, {
$set: { cart: req.session.cart }
2018-01-07 04:55:48 +10:00
});
2019-12-30 13:10:57 +10:00
res.status(200).json({ message: 'Cart successfully updated', totalCartItems: Object.keys(req.session.cart).length });
2018-01-07 04:55:48 +10:00
});
2018-02-04 01:23:59 +10:00
// Remove single product from cart
router.post('/product/removefromcart', async (req, res, next) => {
const db = req.app.db;
2019-12-30 13:10:57 +10:00
// Check for item in cart
if(!req.session.cart[req.body.cartId]){
2019-12-30 13:10:57 +10:00
return res.status(400).json({ message: 'Product not found in cart' });
}
2018-02-04 01:23:59 +10:00
// remove item from cart
delete req.session.cart[req.body.cartId];
2019-12-30 13:10:57 +10:00
// If not items in cart, empty it
if(Object.keys(req.session.cart).length === 0){
return emptyCart(req, res, 'json');
}
2019-06-11 15:12:07 +10:00
// Update cart in DB
await db.cart.updateOne({ sessionId: req.session.id }, {
$set: { cart: req.session.cart }
2018-01-07 04:55:48 +10:00
});
2019-12-30 13:10:57 +10:00
// update total cart
await updateTotalCart(req, res);
// Update checking cart for subscription
updateSubscriptionCheck(req, res);
return res.status(200).json({ message: 'Product successfully removed', totalCartItems: Object.keys(req.session.cart).length });
2018-01-07 04:55:48 +10:00
});
2018-02-04 01:23:59 +10:00
// Totally empty the cart
router.post('/product/emptycart', async (req, res, next) => {
emptyCart(req, res, 'json');
});
2018-02-04 01:23:59 +10:00
// Add item to cart
2019-10-26 11:08:53 +10:00
router.post('/product/addtocart', async (req, res, next) => {
2018-02-04 01:23:59 +10:00
const db = req.app.db;
2019-02-09 14:07:02 +10:00
const config = req.app.config;
2018-02-04 01:23:59 +10:00
let productQuantity = req.body.productQuantity ? parseInt(req.body.productQuantity) : 1;
const productComment = req.body.productComment ? req.body.productComment : null;
2018-02-04 01:23:59 +10:00
// If maxQuantity set, ensure the quantity doesn't exceed that value
if(config.maxQuantity && productQuantity > config.maxQuantity){
return res.status(400).json({
message: 'The quantity exceeds the max amount. Please contact us for larger orders.'
});
}
2018-05-21 23:36:12 +10:00
// Don't allow negative quantity
2020-01-07 21:03:35 +10:00
if(productQuantity < 1){
2018-05-21 23:36:12 +10:00
productQuantity = 1;
}
2018-02-04 01:23:59 +10:00
// setup cart object if it doesn't exist
if(!req.session.cart){
2019-12-30 13:10:57 +10:00
req.session.cart = {};
2018-02-04 01:23:59 +10:00
}
// Get the product from the DB
2019-10-26 11:08:53 +10:00
const product = await db.products.findOne({ _id: getId(req.body.productId) });
// No product found
if(!product){
return res.status(400).json({ message: 'Error updating cart. Please try again.' });
}
2018-02-04 01:23:59 +10:00
// If cart already has a subscription you cannot add anything else
if(req.session.cartSubscription){
return res.status(400).json({ message: 'Subscription already existing in cart. You cannot add more.' });
}
// If existing cart isn't empty check if product is a subscription
2019-12-30 13:10:57 +10:00
if(Object.keys(req.session.cart).length !== 0){
if(product.productSubscription){
2019-12-30 13:10:57 +10:00
return res.status(400).json({ message: 'You cannot combine subscription products with existing in your cart. Empty your cart and try again.' });
}
}
2019-10-26 11:08:53 +10:00
// If stock management on check there is sufficient stock for this product
2020-03-21 19:51:18 +10:00
if(config.trackStock){
2019-12-30 13:10:57 +10:00
// If there is more stock than total (ignoring held)
if(productQuantity > product.productStock){
return res.status(400).json({ message: 'There is insufficient stock of this product.' });
}
2019-10-26 11:08:53 +10:00
const stockHeld = await db.cart.aggregate(
{
$match: {
cart: { $elemMatch: { productId: product._id.toString() } }
}
},
{ $unwind: '$cart' },
{
$group: {
_id: '$cart.productId',
sumHeld: { $sum: '$cart.quantity' }
}
},
{
$project: {
sumHeld: 1
}
2019-10-26 11:08:53 +10:00
}
).toArray();
2019-10-26 11:08:53 +10:00
// If there is stock
if(stockHeld.length > 0){
const totalHeld = _.find(stockHeld, { _id: product._id.toString() }).sumHeld;
const netStock = product.productStock - totalHeld;
2019-10-26 11:08:53 +10:00
// Check there is sufficient stock
if(productQuantity > netStock){
return res.status(400).json({ message: 'There is insufficient stock of this product.' });
2019-02-09 14:07:02 +10:00
}
}
2019-10-26 11:08:53 +10:00
}
2019-02-09 14:07:02 +10:00
2019-10-26 11:08:53 +10:00
const productPrice = parseFloat(product.productPrice).toFixed(2);
2018-02-04 01:23:59 +10:00
2019-10-26 11:08:53 +10:00
let options = {};
if(req.body.productOptions){
try{
if(typeof req.body.productOptions === 'object'){
options = req.body.productOptions;
}else{
options = JSON.parse(req.body.productOptions);
}
}catch(ex){}
2019-10-26 11:08:53 +10:00
}
// Product with options hash
const productHash = hash({
productId: product._id.toString(),
options
});
2019-10-26 11:08:53 +10:00
// if exists we add to the existing value
let cartQuantity = 0;
if(req.session.cart[productHash]){
cartQuantity = parseInt(req.session.cart[productHash].quantity) + productQuantity;
req.session.cart[productHash].quantity = cartQuantity;
req.session.cart[productHash].totalItemPrice = productPrice * parseInt(req.session.cart[productHash].quantity);
2019-10-26 11:08:53 +10:00
}else{
// Set the card quantity
cartQuantity = productQuantity;
// new product deets
const productObj = {};
productObj.productId = product._id;
2019-10-26 11:08:53 +10:00
productObj.title = product.productTitle;
productObj.quantity = productQuantity;
productObj.totalItemPrice = productPrice * productQuantity;
productObj.options = options;
productObj.productImage = product.productImage;
productObj.productComment = productComment;
productObj.productSubscription = product.productSubscription;
2019-10-26 11:08:53 +10:00
if(product.productPermalink){
productObj.link = product.productPermalink;
2018-02-23 03:41:24 +10:00
}else{
2019-10-26 11:08:53 +10:00
productObj.link = product._id;
2018-01-07 04:55:48 +10:00
}
2018-02-23 03:41:24 +10:00
2019-10-26 11:08:53 +10:00
// merge into the current cart
req.session.cart[productHash] = productObj;
2019-10-26 11:08:53 +10:00
}
2019-10-26 11:08:53 +10:00
// Update cart to the DB
2019-10-29 18:26:30 +10:00
await db.cart.updateOne({ sessionId: req.session.id }, {
2019-10-26 11:08:53 +10:00
$set: { cart: req.session.cart }
}, { upsert: true });
2018-02-23 03:41:24 +10:00
2019-10-26 11:08:53 +10:00
// update total cart amount
await updateTotalCart(req, res);
2019-10-26 11:08:53 +10:00
// Update checking cart for subscription
updateSubscriptionCheck(req, res);
if(product.productSubscription){
req.session.cartSubscription = product.productSubscription;
}
return res.status(200).json({
message: 'Cart successfully updated',
cartId: productHash,
totalCartItems: req.session.totalCartItems
});
2018-01-07 04:55:48 +10:00
});
// search products
2018-01-07 05:35:49 +10:00
router.get('/search/:searchTerm/:pageNum?', (req, res) => {
2019-07-12 18:06:34 +10:00
const db = req.app.db;
const searchTerm = req.params.searchTerm;
const productsIndex = req.app.productsIndex;
const config = req.app.config;
const numberProducts = config.productsPerPage ? config.productsPerPage : 6;
2018-01-07 05:35:49 +10:00
2019-07-12 18:06:34 +10:00
const lunrIdArray = [];
2018-01-07 05:35:49 +10:00
productsIndex.search(searchTerm).forEach((id) => {
2019-06-15 15:52:32 +10:00
lunrIdArray.push(getId(id.ref));
2018-01-07 04:55:48 +10:00
});
2018-01-07 05:35:49 +10:00
let pageNum = 1;
2018-01-07 04:55:48 +10:00
if(req.params.pageNum){
pageNum = req.params.pageNum;
}
2018-01-15 07:11:22 +10:00
Promise.all([
2020-03-19 16:32:22 +10:00
paginateData(true, req, pageNum, 'products', { _id: { $in: lunrIdArray } }),
2019-06-15 15:52:32 +10:00
getMenu(db)
2018-01-15 07:11:22 +10:00
])
2020-03-19 16:32:22 +10:00
.then(([results, menu]) => {
// If JSON query param return json instead
if(req.query.json === 'true'){
res.status(200).json(results.data);
return;
}
2018-02-23 03:41:24 +10:00
2020-03-19 16:32:22 +10:00
res.render(`${config.themeViews}index`, {
title: 'Results',
results: results.data,
filtered: true,
session: req.session,
metaDescription: req.app.config.cartTitle + ' - Search term: ' + searchTerm,
searchTerm: searchTerm,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
productsPerPage: numberProducts,
totalProductCount: results.totalItems,
pageNum: pageNum,
paginateUrl: 'search',
config: config,
menu: sortMenu(menu),
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
2018-01-07 04:55:48 +10:00
});
2020-03-19 16:32:22 +10:00
})
.catch((err) => {
console.error(colors.red('Error searching for products', err));
});
2018-01-07 04:55:48 +10:00
});
// search products
2018-01-07 05:35:49 +10:00
router.get('/category/:cat/:pageNum?', (req, res) => {
2019-07-12 18:06:34 +10:00
const db = req.app.db;
const searchTerm = req.params.cat;
const productsIndex = req.app.productsIndex;
const config = req.app.config;
const numberProducts = config.productsPerPage ? config.productsPerPage : 6;
2018-01-07 05:35:49 +10:00
2019-07-12 18:06:34 +10:00
const lunrIdArray = [];
2018-01-07 05:35:49 +10:00
productsIndex.search(searchTerm).forEach((id) => {
2019-06-15 15:52:32 +10:00
lunrIdArray.push(getId(id.ref));
2018-01-07 04:55:48 +10:00
});
2018-01-07 05:35:49 +10:00
let pageNum = 1;
2018-01-07 04:55:48 +10:00
if(req.params.pageNum){
pageNum = req.params.pageNum;
}
2018-01-15 07:11:22 +10:00
Promise.all([
2020-03-19 16:32:22 +10:00
paginateData(true, req, pageNum, 'products', { _id: { $in: lunrIdArray } }),
2019-06-15 15:52:32 +10:00
getMenu(db)
2018-01-15 07:11:22 +10:00
])
.then(([results, menu]) => {
const sortedMenu = sortMenu(menu);
2018-01-07 04:55:48 +10:00
// If JSON query param return json instead
if(req.query.json === 'true'){
res.status(200).json(results.data);
return;
}
2018-02-23 03:41:24 +10:00
res.render(`${config.themeViews}index`, {
2019-12-18 19:18:31 +10:00
title: `Category: ${searchTerm}`,
results: results.data,
filtered: true,
session: req.session,
searchTerm: searchTerm,
2019-12-18 19:18:31 +10:00
metaDescription: `${req.app.config.cartTitle} - Category: ${searchTerm}`,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
productsPerPage: numberProducts,
2020-03-19 16:32:22 +10:00
totalProductCount: results.totalItems,
pageNum: pageNum,
menuLink: _.find(sortedMenu.items, (obj) => { return obj.link === searchTerm; }),
paginateUrl: 'category',
config: config,
menu: sortedMenu,
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
});
})
.catch((err) => {
console.error(colors.red('Error getting products for category', err));
2018-01-07 04:55:48 +10:00
});
});
// Language setup in cookie
router.get('/lang/:locale', (req, res) => {
res.cookie('locale', req.params.locale, { maxAge: 900000, httpOnly: true });
res.redirect('back');
2018-01-07 04:55:48 +10:00
});
// return sitemap
2018-01-07 05:35:49 +10:00
router.get('/sitemap.xml', (req, res, next) => {
2019-07-12 18:06:34 +10:00
const sm = require('sitemap');
const config = req.app.config;
2018-01-07 04:55:48 +10:00
2019-06-15 15:52:32 +10:00
addSitemapProducts(req, res, (err, products) => {
2018-01-07 04:55:48 +10:00
if(err){
console.error(colors.red('Error generating sitemap.xml', err));
}
2019-07-12 18:06:34 +10:00
const sitemap = sm.createSitemap(
2018-01-07 04:55:48 +10:00
{
hostname: config.baseUrl,
cacheTime: 600000,
urls: [
2019-06-15 14:46:08 +10:00
{ url: '/', changefreq: 'weekly', priority: 1.0 }
2018-01-07 04:55:48 +10:00
]
});
2019-07-12 18:06:34 +10:00
const currentUrls = sitemap.urls;
const mergedUrls = currentUrls.concat(products);
2018-01-07 04:55:48 +10:00
sitemap.urls = mergedUrls;
// render the sitemap
2018-01-07 05:35:49 +10:00
sitemap.toXML((err, xml) => {
2018-01-07 04:55:48 +10:00
if(err){
return res.status(500).end();
}
res.header('Content-Type', 'application/xml');
res.send(xml);
return true;
});
});
});
2018-01-07 05:35:49 +10:00
router.get('/page/:pageNum', (req, res, next) => {
2019-07-12 18:06:34 +10:00
const db = req.app.db;
const config = req.app.config;
const numberProducts = config.productsPerPage ? config.productsPerPage : 6;
2018-01-07 04:55:48 +10:00
2018-01-15 07:11:22 +10:00
Promise.all([
2020-03-19 16:32:22 +10:00
paginateData(true, req, req.params.pageNum, 'products'),
2019-06-15 15:52:32 +10:00
getMenu(db)
2018-01-15 07:11:22 +10:00
])
.then(([results, menu]) => {
2018-02-23 03:41:24 +10:00
// If JSON query param return json instead
if(req.query.json === 'true'){
res.status(200).json(results.data);
return;
}
2018-01-15 07:11:22 +10:00
res.render(`${config.themeViews}index`, {
title: 'Shop',
2018-01-07 04:55:48 +10:00
results: results.data,
session: req.session,
2019-06-15 15:52:32 +10:00
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
metaDescription: req.app.config.cartTitle + ' - Products page: ' + req.params.pageNum,
2018-02-23 03:41:24 +10:00
config: req.app.config,
2018-01-07 04:55:48 +10:00
productsPerPage: numberProducts,
2020-03-19 16:32:22 +10:00
totalProductCount: results.totalItems,
pageNum: req.params.pageNum,
2018-01-07 04:55:48 +10:00
paginateUrl: 'page',
helpers: req.handlebars.helpers,
showFooter: 'showFooter',
2019-06-15 15:52:32 +10:00
menu: sortMenu(menu)
2018-01-07 04:55:48 +10:00
});
2018-01-15 07:11:22 +10:00
})
.catch((err) => {
console.error(colors.red('Error getting products for page', err));
2018-01-07 04:55:48 +10:00
});
});
// The main entry point of the shop
router.get('/:page?', async (req, res, next) => {
const db = req.app.db;
const config = req.app.config;
const numberProducts = config.productsPerPage ? config.productsPerPage : 6;
// if no page is specified, just render page 1 of the cart
if(!req.params.page){
Promise.all([
2020-03-19 16:32:22 +10:00
paginateData(true, req, 1, 'products', {}),
getMenu(db)
])
.then(([results, menu]) => {
// If JSON query param return json instead
if(req.query.json === 'true'){
res.status(200).json(results.data);
return;
}
res.render(`${config.themeViews}index`, {
title: `${config.cartTitle} - Shop`,
theme: config.theme,
results: results.data,
session: req.session,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
2019-11-06 18:43:16 +10:00
config,
productsPerPage: numberProducts,
2020-03-19 16:32:22 +10:00
totalProductCount: results.totalItems,
pageNum: 1,
paginateUrl: 'page',
helpers: req.handlebars.helpers,
showFooter: 'showFooter',
menu: sortMenu(menu)
});
})
.catch((err) => {
console.error(colors.red('Error getting products for page', err));
});
2018-01-07 04:55:48 +10:00
}else{
if(req.params.page === 'admin'){
next();
return;
}
// lets look for a page
2020-03-07 19:18:06 +10:00
const page = await db.pages.findOne({ pageSlug: req.params.page, pageEnabled: 'true' });
2019-10-26 11:08:53 +10:00
// if we have a page lets render it, else throw 404
if(page){
res.render(`${config.themeViews}page`, {
title: page.pageName,
page: page,
searchTerm: req.params.page,
session: req.session,
message: clearSessionValue(req.session, 'message'),
messageType: clearSessionValue(req.session, 'messageType'),
config: req.app.config,
metaDescription: req.app.config.cartTitle + ' - ' + page,
helpers: req.handlebars.helpers,
showFooter: 'showFooter',
menu: sortMenu(await getMenu(db))
});
}else{
res.status(404).render('error', {
title: '404 Error - Page not found',
config: req.app.config,
message: '404 Error - Page not found',
helpers: req.handlebars.helpers,
showFooter: 'showFooter',
menu: sortMenu(await getMenu(db))
});
}
2018-01-07 04:55:48 +10:00
}
});
module.exports = router;