diff --git a/server/app.js b/server/app.js index eb264bcc9..a5244ca00 100644 --- a/server/app.js +++ b/server/app.js @@ -205,7 +205,6 @@ app.get('/user/:username', async (req, res, next)=>{ app.get('/edit/:id', asyncHandler(getBrew('edit')), (req, res, next)=>{ req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; sanitizeBrew(req.brew, 'edit'); - console.log('edit', req.brew); splitTextStyleAndMetadata(req.brew); res.header('Cache-Control', 'no-cache, no-store'); //reload the latest saved brew when pressing back button, not the cached version before save. return next(); @@ -261,7 +260,7 @@ if(isLocalEnvironment){ //Render the page const templateFn = require('./../client/template.js'); -app.use((req, res)=>{ +app.use(asyncHandler(async (req, res, next)=>{ // Create configuration object const configuration = { local : isLocalEnvironment, @@ -279,13 +278,14 @@ app.use((req, res)=>{ config : configuration }; const title = req.brew ? req.brew.title : ''; - templateFn('homebrew', title, props) - .then((page)=>{ res.send(page); }) - .catch((err)=>{ - console.log(err); - return res.sendStatus(500); - }); -}); + const page = await templateFn('homebrew', title, props) + .catch((err)=>{ + console.log(err); + return res.sendStatus(500); + }); + if(!page) return; + res.send(page); +})); //v=====----- Error-Handling Middleware -----=====v// //Format Errors so all fields will be sent @@ -309,6 +309,13 @@ app.use((err, req, res, next)=>{ console.error(err); res.status(status).send(getPureError(err)); }); + +app.use((req, res)=>{ + if(!res.headersSent) { + console.error('Headers have not been sent, responding with a server error.', req.url); + res.status(500).send('An error occurred and the server did not send a response. The error has been logged, please note the time this occurred and report this issue.'); + } +}); //^=====--------------------------------------=====^// module.exports = { diff --git a/server/homebrew.api.js b/server/homebrew.api.js index da8526fb9..0b4b59247 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -1,3 +1,4 @@ +/* eslint-disable max-lines */ const _ = require('lodash'); const HomebrewModel = require('./homebrew.model.js').model; const router = require('express').Router(); @@ -25,7 +26,7 @@ const getBrew = (accessType)=>{ googleId = id.slice(0, -12); id = id.slice(-12); } - let found = await HomebrewModel.get(accessType === 'edit' ? { editId: id } : { shareId: id }) + let stub = await HomebrewModel.get(accessType === 'edit' ? { editId: id } : { shareId: id }) .catch((err)=>{ if(googleId) { console.warn(`Unable to find document stub for ${accessType}Id ${id}`); @@ -33,19 +34,24 @@ const getBrew = (accessType)=>{ console.warn(err); } }); + stub = stub?.toObject(); - if(googleId || found?.googleId) { - const googleBrew = await GoogleActions.getGoogleBrew(googleId || found?.googleId, id, accessType) + if(googleId || stub?.googleId) { + let googleError; + const googleBrew = await GoogleActions.getGoogleBrew(googleId || stub?.googleId, id, accessType) .catch((err)=>{ console.warn(err); + googleError = err; }); - if(!found && !googleBrew) throw 'Brew not found in database or Google Drive'; - found = found ? Object.assign(excludeStubProps(found), excludeGoogleProps(googleBrew)) : googleBrew; - } else if(!found) { + if(!googleBrew) throw googleError; + stub = stub ? _.assign(excludeStubProps(stub), excludeGoogleProps(googleBrew)) : googleBrew; + } + + if(!stub) { throw 'Brew not found in database'; } - req.brew = accessType !== 'edit' && found.toObject ? found.toObject() : found; + req.brew = stub; } next(); @@ -78,11 +84,21 @@ const getGoodBrewTitle = (text)=>{ const excludePropsFromUpdate = (brew)=>{ // Remove undesired properties + const modified = _.clone(brew); const propsToExclude = ['_id', 'views', 'lastViewed', 'editId', 'shareId', 'googleId']; for (const prop of propsToExclude) { - delete brew[prop]; + delete modified[prop]; } - return brew; + return modified; +}; + +const excludeGoogleProps = (brew)=>{ + const modified = _.clone(brew); + const propsToExclude = ['tags', 'systems', 'published', 'authors', 'owner', 'views']; + for (const prop of propsToExclude) { + delete modified[prop]; + } + return modified; }; const excludeStubProps = (brew)=>{ @@ -93,15 +109,6 @@ const excludeStubProps = (brew)=>{ return brew; }; -const excludeGoogleProps = (brew)=>{ - const modified = brew.toObject ? brew.toObject() : brew; - const propsToExclude = ['tags', 'systems', 'published', 'authors', 'owner', 'views']; - for (const prop of propsToExclude) { - delete modified[prop]; - } - return modified; -}; - const beforeNewSave = (account, brew)=>{ if(!brew.title) { brew.title = getGoodBrewTitle(brew.text); @@ -114,7 +121,7 @@ const beforeNewSave = (account, brew)=>{ const newGoogleBrew = async (account, brew, res)=>{ const oAuth2Client = GoogleActions.authCheck(account, res); - const newBrew = excludeGoogleProps(_.clone(brew)); + const newBrew = excludeGoogleProps(brew); return await GoogleActions.newGoogleBrew(oAuth2Client, newBrew); }; @@ -137,23 +144,18 @@ const newBrew = async (req, res)=>{ if(transferToGoogle) { googleId = await newGoogleBrew(req.account, newHomebrew, res) .catch((err)=>{ + console.error(err); res.status(err?.status || err?.response?.status || 500).send(err?.message || err); }); + if(!googleId) return; excludeStubProps(newHomebrew); + newHomebrew.googleId = googleId; } else { // Compress brew text to binary before saving newHomebrew.textBin = zlib.deflateRawSync(newHomebrew.text); // Delete the non-binary text field since it's not needed anymore newHomebrew.text = undefined; } - if(transferToGoogle && !googleId) { - if(!res.headersSent) { - res.status(500).send('Unable to save document to Google Drive'); - } - return; - } else if(transferToGoogle) { - newHomebrew.googleId = googleId; - } saved = await newHomebrew.save() .catch((err)=>{ @@ -163,12 +165,11 @@ const newBrew = async (req, res)=>{ if(!saved) return; saved = saved.toObject(); - return res.status(200).send(saved); + res.status(200).send(saved); }; const updateBrew = async (req, res)=>{ - console.log(req.brew, req.body); - let brew = Object.assign(req.brew, excludePropsFromUpdate(req.body)); + let brew = _.assign(req.brew, excludePropsFromUpdate(req.body)); brew.text = mergeBrewText(brew); const { transferToGoogle, transferFromGoogle } = req.query; @@ -178,38 +179,23 @@ const updateBrew = async (req, res)=>{ console.error(err); res.status(err?.status || err?.response?.status || 500).send(err.message || err); }); - if(!deleted) { - if(res.headersSent) { - res.status(500).send('Unable to delete brew from Google'); - } - return; - } + if(!deleted) return; brew.googleId = undefined; } else if(!brew.googleId && transferToGoogle) { - brew.googleId = await newGoogleBrew(req.account, excludeGoogleProps(_.clone(brew)), res) + brew.googleId = await newGoogleBrew(req.account, excludeGoogleProps(brew), res) .catch((err)=>{ console.error(err); res.status(err.status || err.response.status).send(err.message || err); }); - if(!brew.googleId) { - if(res.headersSent) { - res.status(500).send('Unable to save brew to Google'); - } - return; - } + if(!brew.googleId) return; } else if(brew.googleId) { - const updated = await GoogleActions.updateGoogleBrew(excludeGoogleProps(_.clone(brew))) + const updated = await GoogleActions.updateGoogleBrew(excludeGoogleProps(brew)) .catch((err)=>{ console.error(err); res.status(err?.response?.status || 500).send(err); }); - if(!updated) { - if(res.headersSent) { - res.status(500).send('Unable to save brew to Google'); - } - return; - } + if(!updated) return; } if(brew.googleId) { @@ -226,6 +212,8 @@ const updateBrew = async (req, res)=>{ brew.authors = _.uniq(_.concat(brew.authors, req.account.username)); } + brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew); + if(!brew.markModified) { brew = new HomebrewModel(brew); } @@ -235,15 +223,12 @@ const updateBrew = async (req, res)=>{ const saved = await brew.save() .catch((err)=>{ + console.error(err); res.status(err.status || 500).send(err.message || 'Unable to save brew to Homebrewery database'); }); - if(!saved) { - if(!res.headersSent) { - res.status(500).send('Unable to save brew to Homebrewery database'); - } - } + if(!saved) return; - if(!res.headersSent) return res.status(200).send(saved); + res.status(200).send(saved); }; const deleteGoogleBrew = async (account, id, editId, res)=>{ @@ -257,14 +242,10 @@ const deleteBrew = async (req, res)=>{ if(brew.googleId) { const googleDeleted = await deleteGoogleBrew(account, brew.googleId, brew.editId, res) .catch((err)=>{ + console.error(err); res.status(500).send(err); }); - if(!googleDeleted) { - if(!res.headersSent) { - res.status(500).send('Unable to delete brew from Google'); - } - return; - } + if(!googleDeleted) return; } if(brew._id) { @@ -290,7 +271,7 @@ const deleteBrew = async (req, res)=>{ } } - return res.status(204).send(); + res.status(204).send(); }; router.post('/api', asyncHandler(newBrew));