/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/ const _ = require('lodash'); const jwt = require('jwt-simple'); const express = require('express'); const app = express(); const homebrewApi = require('./server/homebrew.api.js'); const GoogleActions = require('./server/googleActions.js'); const serveCompressedStaticAssets = require('./server/static-assets.mv.js'); const sanitizeFilename = require('sanitize-filename'); // //Custom Error // class ErrorHandler extends Error { // constructor(statusCode, message) { // super(); // this.statusCode = statusCode; // this.message = message; // } // } //Format brew source for viewing in the browser as plain text // const sanitizeSource = (text)=>{ // const replaceStrings = { '&' : '&', // '<' : '<', // '>' : '>' }; // for (const replaceStr in replaceStrings) { // text = text.replaceAll(replaceStr, replaceStrings[replaceStr]); // } // return `
${text}
`; // }; //Get the brew object from the HB database or Google Drive const getBrewFromId = async (id, accessType)=>{ if(accessType !== 'edit' && accessType !== 'share') throw ('Invalid Access Type when getting brew'); let brew; if(id.length > 12) { const googleId = id.slice(0, -12); id = id.slice(-12); brew = await GoogleActions.readFileMetadata(config.get('google_api_key'), googleId, id, accessType) .catch((err)=>{throw err;}); } else { brew = await HomebrewModel.get(accessType == 'edit' ? { editId: id } : { shareId: id }) .catch((err)=>{throw err;}); brew.sanatize(true); } return brew; }; app.use('/', serveCompressedStaticAssets(`${__dirname}/build`)); process.chdir(__dirname); //app.use(express.static(`${__dirname}/build`)); app.use(require('body-parser').json({ limit: '25mb' })); app.use(require('cookie-parser')()); app.use(require('./server/forcessl.mw.js')); const config = require('nconf') .argv() .env({ lowerCase: true }) .file('environment', { file: `config/${process.env.NODE_ENV}.json` }) .file('defaults', { file: 'config/default.json' }); //DB const mongoose = require('mongoose'); mongoose.connect(config.get('mongodb_uri') || config.get('mongolab_uri') || 'mongodb://localhost/naturalcrit', { retryWrites: false, useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true }); mongoose.connection.on('error', ()=>{ console.log('Error : Could not connect to a Mongo Database.'); console.log(' If you are running locally, make sure mongodb.exe is running.'); throw 'Can not connect to Mongo'; }); //Account Middleware app.use((req, res, next)=>{ if(req.cookies && req.cookies.nc_session){ try { req.account = jwt.decode(req.cookies.nc_session, config.get('secret')); //console.log("Just loaded up JWT from cookie:"); //console.log(req.account); } catch (e){} } req.config = { google_client_id : config.get('google_client_id'), google_client_secret : config.get('google_client_secret') }; return next(); }); app.use(homebrewApi); app.use(require('./server/admin.api.js')); const HomebrewModel = require('./server/homebrew.model.js').model; const welcomeText = require('fs').readFileSync('./client/homebrew/pages/homePage/welcome_msg.md', 'utf8'); const changelogText = require('fs').readFileSync('./changelog.md', 'utf8'); String.prototype.replaceAll = function(s, r){return this.split(s).join(r);}; //Robots.txt app.get('/robots.txt', (req, res)=>{ return res.sendFile(`${__dirname}/robots.txt`); }); // app.get('/error', (req, res)=>{ // throw new ErrorHandler(404, 'User with the specified email does not exist'); // }); //Source page app.get('/source/:id', (req, res)=>{ if(req.params.id.length > 12) { const googleId = req.params.id.slice(0, -12); const shareId = req.params.id.slice(-12); GoogleActions.readFileMetadata(config.get('google_api_key'), googleId, shareId, 'share') .then((brew)=>{ const replaceStrings = { '&': '&', '<': '<', '>': '>' }; let text = brew.text; for (const replaceStr in replaceStrings) { text = text.replaceAll(replaceStr, replaceStrings[replaceStr]); } text = `
${text}
`; res.status(200).send(text); }) .catch((err)=>{ console.log(err); return res.status(400).send('Can\'t get brew from Google'); }); } else { HomebrewModel.get({ shareId: req.params.id }) .then((brew)=>{ const replaceStrings = { '&': '&', '<': '<', '>': '>' }; let text = brew.text; for (const replaceStr in replaceStrings) { text = text.replaceAll(replaceStr, replaceStrings[replaceStr]); } text = `
${text}
`; res.status(200).send(text); }) .catch((err)=>{ console.log(err); return res.status(404).send('Could not find Homebrew with that id'); }); } }); //Download brew source page app.get('/download/:id', (req, res)=>{ const prefix = 'HB - '; if(req.params.id.length > 12) { const googleId = req.params.id.slice(0, -12); const shareId = req.params.id.slice(-12); GoogleActions.readFileMetadata(config.get('google_api_key'), googleId, shareId, 'share') .then((brew)=>{ let fileName = sanitizeFilename(`${prefix}${brew.title}`).replaceAll(' ', ''); if(!fileName || !fileName.length) { fileName = `${prefix}-Untitled-Brew`; }; res.set({ 'Cache-Control' : 'no-cache', 'Content-Type' : 'text/plain', 'Content-Disposition' : `attachment; filename="${fileName}.txt"` }); res.status(200).send(brew.text); }) .catch((err)=>{ console.log(err); return res.status(400).send('Can\'t get brew from Google'); }); } else { HomebrewModel.get({ shareId: req.params.id }) .then((brew)=>{ let fileName = sanitizeFilename(`${prefix}${brew.title}`).replaceAll(' ', ''); if(!fileName || !fileName.length) { fileName = `${prefix}-Untitled-Brew`; }; res.set({ 'Cache-Control' : 'no-cache', 'Content-Type' : 'text/plain', 'Content-Disposition' : `attachment; filename="${fileName}.txt"` }); res.status(200).send(brew.text); }) .catch((err)=>{ console.log(err); return res.status(404).send('Could not find Homebrew with that id'); }); } }); //User Page app.get('/user/:username', async (req, res, next)=>{ const fullAccess = req.account && (req.account.username == req.params.username); let googleBrews = []; if(req.account && req.account.googleId){ googleBrews = await GoogleActions.listGoogleBrews(req, res) .catch((err)=>{ console.error(err); }); } const brews = await HomebrewModel.getByUser(req.params.username, fullAccess) .catch((err)=>{ console.log(err); }); if(googleBrews) { req.brews = _.concat(brews, googleBrews); } else {req.brews = brews;} return next(); }); //Edit Page app.get('/edit/:id', async (req, res, next)=>{ res.header('Cache-Control', 'no-cache, no-store'); //reload the latest saved brew when pressing back button, not the cached version before save. const brew = await getBrewFromId(req.params.id, 'edit') .catch((err)=>{next(err);}); req.brew = brew; return next(); }); //New Page app.get('/new/:id', async (req, res, next)=>{ const brew = await getBrewFromId(req.params.id, 'share') .catch((err)=>{next(err);}); req.brew = brew; return next(); }); //Share Page app.get('/share/:id', async (req, res, next)=>{ const brew = await getBrewFromId(req.params.id, 'share') .catch((err)=>{next(err);}); if(req.params.id.length > 12) { const googleId = req.params.id.slice(0, -12); const shareId = req.params.id.slice(-12); await GoogleActions.increaseView(googleId, shareId, 'share', brew) .catch((err)=>{next(err);}); } else { await brew.increaseView(); } req.brew = brew; return next(); }); //Print Page app.get('/print/:id', async (req, res, next)=>{ const brew = await getBrewFromId(req.params.id, 'share'); req.brew = brew; return next(); }); //Render the page //const render = require('.build/render'); const templateFn = require('./client/template.js'); app.use((req, res)=>{ const props = { version : require('./package.json').version, url : req.originalUrl, welcomeText : welcomeText, changelog : changelogText, brew : req.brew, brews : req.brews, googleBrews : req.googleBrews, account : req.account, enable_v3 : config.get('enable_v3') }; templateFn('homebrew', title = req.brew ? req.brew.title : '', props) .then((page)=>{ res.send(page); }) .catch((err)=>{ console.log(err); return res.sendStatus(500); }); }); //Error Handling Middleware app.use((err, req, res, next)=>{ const { statusCode, message } = err; console.log('CUSTOM ERROR HANDLER'); console.error(err); res.status(statusCode).json({ status : 'error', statusCode, message }); }); const PORT = process.env.PORT || config.get('web_port') || 8000; app.listen(PORT); console.log(`server on port:${PORT}`);