diff --git a/config/default.json b/config/default.json index daf77e82e..f74ce3b8e 100644 --- a/config/default.json +++ b/config/default.json @@ -2,5 +2,6 @@ "host" : "homebrewery.local.naturalcrit.com:8000", "naturalcrit_url" : "local.naturalcrit.com:8010", "secret" : "secret", - "web_port" : 8000 + "web_port" : 8000, + "enable_v3" : true } diff --git a/package-lock.json b/package-lock.json index 37a7b8347..f61895d44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "express-static-gzip": "2.1.1", "fs-extra": "10.0.0", "googleapis": "92.0.0", + "js-yaml": "^4.1.0", "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", @@ -2157,8 +2158,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/arr-diff": { "version": "4.0.0", @@ -5719,7 +5719,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -11070,8 +11069,7 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "arr-diff": { "version": "4.0.0", @@ -13879,7 +13877,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "requires": { "argparse": "^2.0.1" } diff --git a/package.json b/package.json index ac4494b8a..07af170ed 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "express-static-gzip": "2.1.1", "fs-extra": "10.0.0", "googleapis": "92.0.0", + "js-yaml": "^4.1.0", "jwt-simple": "^0.5.6", "less": "^3.13.1", "lodash": "^4.17.21", diff --git a/server.js b/server.js index a3a97cddf..4c4cb6f63 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,7 @@ const _ = require('lodash'); const jwt = require('jwt-simple'); const express = require('express'); +const yaml = require('js-yaml'); const app = express(); const homebrewApi = require('./server/homebrew.api.js'); @@ -32,7 +33,7 @@ const getBrewFromId = asyncHandler(async (id, accessType)=>{ if(accessType == 'raw') { return brew; } - splitTextAndStyle(brew); + splitTextStyleAndMetadata(brew); return brew; }); @@ -45,8 +46,15 @@ const sanitizeBrew = (brew, full=false)=>{ return brew; }; -const splitTextAndStyle = (brew)=>{ +const splitTextStyleAndMetadata = (brew)=>{ brew.text = brew.text.replaceAll('\r\n', '\n'); + if(brew.text.startsWith('```metadata')) { + const index = brew.text.indexOf('```\n\n'); + const metadataSection = brew.text.slice(12, index - 1); + const metadata = yaml.load(metadataSection); + Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer'])); + brew.text = brew.text.slice(index + 5); + } if(brew.text.startsWith('```css')) { const index = brew.text.indexOf('```\n\n'); brew.style = brew.text.slice(7, index - 1); @@ -128,7 +136,7 @@ app.get('/v3_preview', async (req, res, next)=>{ text : welcomeTextV3, renderer : 'V3' }; - splitTextAndStyle(brew); + splitTextStyleAndMetadata(brew); req.brew = brew; return next(); }); @@ -140,7 +148,7 @@ app.get('/changelog', async (req, res, next)=>{ text : changelogText, renderer : 'V3' }; - splitTextAndStyle(brew); + splitTextStyleAndMetadata(brew); req.brew = brew; return next(); }); @@ -152,7 +160,7 @@ app.get('/faq', async (req, res, next)=>{ text : faqText, renderer : 'V3' }; - splitTextAndStyle(brew); + splitTextStyleAndMetadata(brew); req.brew = brew; return next(); }); diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 59d4f6d68..f846c6d87 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -4,6 +4,7 @@ const router = require('express').Router(); const zlib = require('zlib'); const GoogleActions = require('./googleActions.js'); const Markdown = require('../shared/naturalcrit/markdown.js'); +const yaml = require('js-yaml'); // const getTopBrews = (cb) => { // HomebrewModel.find().sort({ views: -1 }).limit(5).exec(function(err, brews) { @@ -11,6 +12,22 @@ const Markdown = require('../shared/naturalcrit/markdown.js'); // }); // }; +const mergeBrewText = (brew)=>{ + let text = brew.text; + if(brew.style !== undefined) { + text = `\`\`\`css\n` + + `${brew.style || ''}\n` + + `\`\`\`\n\n` + + `${text}`; + } + const metadata = _.pick(brew, ['title', 'description', 'tags', 'systems', 'renderer']); + text = `\`\`\`metadata\n` + + `${yaml.dump(metadata)}\n` + + `\`\`\`\n\n` + + `${text}`; + return text; +}; + const MAX_TITLE_LENGTH = 100; const getGoodBrewTitle = (text)=>{ @@ -28,16 +45,6 @@ const excludePropsFromUpdate = (brew)=>{ return brew; }; -const mergeBrewText = (text, style)=>{ - if(typeof style !== 'undefined') { - text = `\`\`\`css\n` + - `${style}\n` + - `\`\`\`\n\n` + - `${text}`; - } - return text; -}; - const newBrew = (req, res)=>{ const brew = req.body; @@ -46,7 +53,7 @@ const newBrew = (req, res)=>{ } brew.authors = (req.account) ? [req.account.username] : []; - brew.text = mergeBrewText(brew.text, brew.style); + brew.text = mergeBrewText(brew); delete brew.editId; delete brew.shareId; @@ -75,7 +82,7 @@ const updateBrew = (req, res)=>{ .then((brew)=>{ const updateBrew = excludePropsFromUpdate(req.body); brew = _.merge(brew, updateBrew); - brew.text = mergeBrewText(brew.text, brew.style); + brew.text = mergeBrewText(brew); // Compress brew text to binary before saving brew.textBin = zlib.deflateRawSync(brew.text); @@ -143,7 +150,7 @@ const newGoogleBrew = async (req, res, next)=>{ } brew.authors = (req.account) ? [req.account.username] : []; - brew.text = mergeBrewText(brew.text, brew.style); + brew.text = mergeBrewText(brew); delete brew.editId; delete brew.shareId; @@ -165,7 +172,7 @@ const updateGoogleBrew = async (req, res, next)=>{ try { oAuth2Client = GoogleActions.authCheck(req.account, res); } catch (err) { return res.status(err.status).send(err.message); } const brew = excludePropsFromUpdate(req.body); - brew.text = mergeBrewText(brew.text, brew.style); + brew.text = mergeBrewText(brew); try { const updatedBrew = await GoogleActions.updateGoogleBrew(oAuth2Client, brew);