+ return (
+
Properties Editor
- this.handleFieldChange('title', e)} />
+ handleFieldChange('title', e)}
+ />
-
-
+
this.handleFieldChange('tags', e)}
+ placeholder='add tag'
+ unique={true}
+ values={metadata.tags}
+ onChange={(e)=>handleFieldChange('tags', e)}
tooltip='You may start tags with "type", "system", "group" or "meta" followed by a colon ":", these will be colored in your userpage.'
/>
-
- {this.renderLanguageDropdown()}
-
- {this.renderThemeDropdown()}
-
- {this.renderRenderOptions()}
+ {renderLanguageDropdown()}
+ {renderThemeDropdown()}
+ {renderRenderOptions()}
Authors
-
- {this.renderAuthors()}
-
+ {renderAuthors()}
@@ -419,30 +379,39 @@ const MetadataEditor = createReactClass({
id='combobox-invited-authors'
label='invited authors'
valuePatterns={/.+/}
- validators={[(v)=>!this.props.metadata.authors?.includes(v)]}
- placeholder='invite author' unique={true}
+ validators={[(v)=>!metadata.authors?.includes(v)]}
+ placeholder='invite author'
+ unique={true}
tooltip={`Invited author usernames are case sensitive.
After adding an invited author, send them the edit link. There, they can choose to accept or decline the invitation.`}
- values={this.props.metadata.invitedAuthors}
- onChange={(e)=>this.handleFieldChange('invitedAuthors', e)}
+ values={metadata.invitedAuthors}
+ onChange={(e)=>handleFieldChange('invitedAuthors', e)}
/>
Privacy
-
- {this.renderPublish()}
-
Published brews are searchable in the Vault and visible on your user page. Unpublished brews are not indexed in the Vault or visible on your user page, but can still be shared and indexed by search engines. You can unpublish a brew any time.
+ {renderPublish()}
+
+ Published brews are searchable in the Vault and visible on your user page. Unpublished brews are not
+ indexed in the Vault or visible on your user page, but can still be shared and indexed by search engines. You can unpublish a
+ brew any time.
+
-
- {this.renderDelete()}
-
-
;
- }
-});
+ {metadata.editId &&
+
+
+
+
+
}
+
+ );
+};
export default MetadataEditor;
diff --git a/package-lock.json b/package-lock.json
index fc60d253a..8374fb57a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "homebrewery",
- "version": "3.24.1",
+ "version": "3.24.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "homebrewery",
- "version": "3.24.1",
+ "version": "3.24.2",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -49,7 +49,7 @@
"jwt-simple": "^0.5.6",
"less": "^4.9.1",
"lodash": "^4.18.1",
- "marked-hbfm": "^1.0.1",
+ "marked-hbfm": "^1.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.31.0",
"mongoose": "^9.11.2",
@@ -11538,9 +11538,9 @@
}
},
"node_modules/marked-emoji": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-2.0.3.tgz",
- "integrity": "sha512-fChW/AfUqCHgoEC1nFDgiw3OR/qsi71/QXH/HTo05yd6B5+T+VHh1SqCpn/HpeGLDxkA+MK4+hr4eULB2/A8Jw==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-3.0.0.tgz",
+ "integrity": "sha512-4IODef6jiQfuRsWOXSH/q9YiXmpVemvm1raj4WmObkWeAPg5bMMPTvbDpxbn4BIvbM245a1Dhq6RAzCS0WFGOw==",
"license": "MIT",
"peerDependencies": {
"marked": ">=4 <19"
@@ -11568,25 +11568,25 @@
}
},
"node_modules/marked-hbfm": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/marked-hbfm/-/marked-hbfm-1.0.1.tgz",
- "integrity": "sha512-mqz1ALIk0POeRCGjAGDTRhyKrMe+i5ycsxLV/8MlG13xC/oTEXA66VHZvIMNLotdM8jNNnLC9TFLCWECN4QHug==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/marked-hbfm/-/marked-hbfm-1.0.3.tgz",
+ "integrity": "sha512-j+TLQqHv1PGb/ypxh8r+kGlgto1t3373GxxDn1gTBk473QC85uV4PteZfLLq8U5H2OLODbbyEGzxVvYdnOT0lQ==",
"license": "MIT",
"dependencies": {
"eslint-plugin-jest": "^29.16.2",
"eslint-plugin-react": "^7.37.5",
"lodash": "^4.18.1",
"marked": ">=3 <19",
- "marked-alignment-paragraphs": "^1.0.0",
- "marked-definition-lists": "^1.0.1",
- "marked-diagrams-markdeep": "^1.0.1",
- "marked-emoji": "^2.0.3",
- "marked-extended-tables": "^2.0.1",
- "marked-gfm-heading-id": "^4.1.4",
- "marked-nonbreaking-spaces": "^1.0.1",
- "marked-smartypants-lite": "^1.0.3",
- "marked-subsuper-text": "^1.0.4",
- "marked-variables": "^1.0.7"
+ "marked-alignment-paragraphs": "1.0.0",
+ "marked-definition-lists": "1.0.1",
+ "marked-diagrams-markdeep": "1.0.1",
+ "marked-emoji": "3.0.0",
+ "marked-extended-tables": "2.0.1",
+ "marked-gfm-heading-id": "4.1.4",
+ "marked-nonbreaking-spaces": "1.0.1",
+ "marked-smartypants-lite": "1.0.3",
+ "marked-subsuper-text": "1.0.4",
+ "marked-variables": "2.0.0"
}
},
"node_modules/marked-nonbreaking-spaces": {
@@ -11617,9 +11617,9 @@
}
},
"node_modules/marked-variables": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/marked-variables/-/marked-variables-1.0.7.tgz",
- "integrity": "sha512-b7ZxKQJ9TEF/xi7dpP//IyIvK10minaYqmQNX7K91K9189jSQ8grpxY9yOIAXpPmVfReY0aZbfxugolTBIpXAA==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/marked-variables/-/marked-variables-2.0.0.tgz",
+ "integrity": "sha512-U3LQ7mXfXpM0H2jExenENOvuFrP4JzSksRUr0yyENxZEkK3jmSlUEdT9LBuYxjOqWlMMhqiFVPOmtm1/QJnS+A==",
"license": "MIT",
"dependencies": {
"expr-eval": "^2.0.2",
diff --git a/package.json b/package.json
index 0a96093b6..7c73d7810 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "homebrewery",
"description": "Create authentic looking D&D homebrews using only markdown",
- "version": "3.24.1",
+ "version": "3.24.2",
"type": "module",
"engines": {
"npm": ">=10.8 <12",
@@ -128,7 +128,7 @@
"jwt-simple": "^0.5.6",
"less": "^4.9.1",
"lodash": "^4.18.1",
- "marked-hbfm": "^1.0.1",
+ "marked-hbfm": "^1.0.3",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.31.0",
"mongoose": "^9.11.2",
diff --git a/server/homebrew.api.js b/server/homebrew.api.js
index aa1f1f84a..c572b2cec 100644
--- a/server/homebrew.api.js
+++ b/server/homebrew.api.js
@@ -2,7 +2,6 @@
import _ from 'lodash';
import { model as HomebrewModel } from './homebrew.model.js';
import express from 'express';
-import zlib from 'zlib';
import GoogleActions from './googleActions.js';
import { hbfm } from 'marked-hbfm';
import * as yaml from 'js-yaml';
@@ -27,17 +26,8 @@ const isStaticTheme = (renderer, themeName)=>{
return Themes[renderer]?.[themeName] !== undefined;
};
-// const getTopBrews = (cb) => {
-// HomebrewModel.find().sort({ views: -1 }).limit(5).exec(function(err, brews) {
-// cb(brews);
-// });
-// };
-
-
const migrateSystemsToTags = (brew)=>{
- if(!('systems' in brew)) return brew;
-
- if(!Array.isArray(brew.systems) || brew.systems.length === 0) {
+ if(!('systems' in brew) || !Array.isArray(brew.systems) || brew.systems.length === 0) {
brew.systems = undefined;
return brew;
}
@@ -108,19 +98,17 @@ const api = {
const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] } });
- if(brews) {
- for (const brew of brews) {
- userThemes[brew.renderer] ??= {};
- userThemes[brew.renderer][brew.shareId] = {
- name : brew.title,
- renderer : brew.renderer,
- baseTheme : brew.theme,
- baseSnippets : false,
- author : brew.authors[0],
- path : brew.shareId,
- thumbnail : brew.thumbnail || '/assets/naturalCritLogoWhite.svg'
- };
- }
+ for (const brew of brews) {
+ userThemes[brew.renderer] ??= {};
+ userThemes[brew.renderer][brew.shareId] = {
+ name : brew.title,
+ renderer : brew.renderer,
+ baseTheme : brew.theme,
+ baseSnippets : false,
+ author : brew.authors[0],
+ path : brew.shareId,
+ thumbnail : brew.thumbnail || '/assets/naturalCritLogoWhite.svg'
+ };
}
return userThemes;
@@ -189,18 +177,14 @@ const api = {
stub.renderer = stub.renderer || undefined; // Clear empty strings
stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields
-
-
- const fixedStub = migrateSystemsToTags(stub);
- req.brew = fixedStub;
+ req.brew = migrateSystemsToTags(stub);
splitTextStyleAndMetadata(req.brew);
next();
};
},
getCSS : async (req, res)=>{
const { brew } = req;
- if(!brew) return res.status(404).send('');
- if(!brew.style) return res.status(404).send('');
+ if(!brew?.style) return res.status(404).send('');
res.set({
'Cache-Control' : 'no-cache',
@@ -216,19 +200,15 @@ const api = {
`\`\`\`\n\n` +
`${text}`;
}
- const metadata = _.pick(brew, ['title', 'description', 'tags', 'renderer', 'theme']);
+ const metadata = _.pick(brew, ['title', 'description', 'tags', 'renderer', 'theme', 'columns', 'columnGutter', 'license', 'legalAuthors']);
const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets;
metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined;
metadata.bleedSize = { top: brew?.bleedSize?.top, bottom: brew?.bleedSize?.bottom, inner: brew?.bleedSize?.inner, outer: brew?.bleedSize?.outer };
metadata.safetySpace = { top: brew?.safetySpace?.top, bottom: brew?.safetySpace?.bottom, outer: brew?.safetySpace?.outer, inner: brew?.safetySpace?.inner };
metadata.trimSize = { width: brew?.trimSize?.width, height: brew?.trimSize?.height };
- metadata.columns = brew?.columns;
- metadata.columnGutter = brew?.columnGutter;
- metadata.license = brew?.license;
- metadata.legalAuthors = brew?.legalAuthors;
text = `\`\`\`metadata\n` +
- `${yaml.dump(metadata)}\n` +
+ `${yaml.dump(metadata)}` +
`\`\`\`\n\n` +
`${text}`;
return text;
@@ -238,28 +218,14 @@ const api = {
return (tokens.find((token)=>token.type === 'heading' || token.type === 'paragraph')?.text || 'No Title')
.slice(0, MAX_TITLE_LENGTH);
},
- excludePropsFromUpdate : (brew)=>{
- // Remove undesired properties
- const modified = _.clone(brew);
- const propsToExclude = ['_id', 'views', 'lastViewed'];
- for (const prop of propsToExclude) {
- delete modified[prop];
- }
- return modified;
+ excludePropsFromUpdate : (brew)=>{ //Remove props that should not update/overwrite when editing
+ return _.omit(brew, ['_id', 'views', 'lastViewed']);
},
- excludeGoogleProps : (brew)=>{
- const modified = _.clone(brew);
- const propsToExclude = ['version', 'tags', 'systems', 'published', 'authors', 'owner', 'views', 'thumbnail'];
- for (const prop of propsToExclude) {
- delete modified[prop];
- }
- return modified;
+ excludeGoogleProps : (brew)=>{ //Remove props that should not be saved to Google (only stored to Homebrewery stub)
+ return _.omit(brew, ['version', 'tags', 'systems', 'published', 'authors', 'invitedAuthors', 'owner', 'views', 'thumbnail']);
},
- excludeStubProps : (brew)=>{
- const propsToExclude = ['text', 'textBin'];
- for (const prop of propsToExclude) {
- brew[prop] = undefined;
- }
+ excludeStubProps : (brew)=>{ //Remove props that should not be saved to stub-only brews
+ brew.text = brew.textBin = undefined; // Can't use _.omit because this brew is a Mongoose object
return brew;
},
beforeNewSave : (account, brew)=>{
@@ -278,9 +244,7 @@ const api = {
newGoogleBrew : async (account, brew, res)=>{
const oAuth2Client = GoogleActions.authCheck(account, res);
- const newBrew = api.excludeGoogleProps(brew);
-
- return await GoogleActions.newGoogleBrew(oAuth2Client, newBrew);
+ return await GoogleActions.newGoogleBrew(oAuth2Client, api.excludeGoogleProps(brew));
},
newBrew : async (req, res)=>{
const brew = req.body;
@@ -292,7 +256,7 @@ const api = {
api.beforeNewSave(req.account, brew);
- const newHomebrew = new HomebrewModel(brew);
+ let newHomebrew = new HomebrewModel(brew);
newHomebrew.editId = nanoid(12);
newHomebrew.shareId = nanoid(12);
@@ -301,15 +265,10 @@ const api = {
googleId = await api.newGoogleBrew(req.account, newHomebrew, res);
if(!googleId) return;
- api.excludeStubProps(newHomebrew);
+ newHomebrew = api.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;
}
-
+
saved = await newHomebrew.save()
.catch((err)=>{
console.error(err, err.toString(), err.stack);
@@ -380,7 +339,6 @@ const api = {
return res.status(200).send(returnObj);
},
updateBrew : async (req, res)=>{
- // Initialize brew from request and body, destructure query params, and set the initial value for the after-save method
const brewFromClient = api.excludePropsFromUpdate(req.body);
const brewFromServer = req.brew;
@@ -406,16 +364,17 @@ const api = {
const patches = parsePatch(brewFromClient.patches);
// Patch to a throwaway variable while parallelizing - we're more concerned with error/no error.
result = applyPatches(patches, encodeURI(brewFromServer.text));
- const failedPatches = patches.map((patch, index)=>{if(!result[1][index]){ return patch; }});
- if(failedPatches > 0){
- throw (`Patch failure: ${failedPatches}/${result[1].length} did not apply`);
+ const failedPatchCount = result[1].filter((patchApplied)=>!patchApplied).length; //Count how many patches failed to apply
+ if(failedPatchCount){
+ throw (`Patch failure: ${failedPatchCount}/${result[1].length} did not apply`);
}
- if(decodeURI(result[0]) != brewFromClient.text){
+ patchedText = decodeURI(result[0]);
+ if(patchedText != brewFromClient.text){
+ debugTextMismatch(brewFromClient.text, patchedText, `edit/${brewFromClient.editId}`);
throw ('Patches did not apply cleanly, text mismatch detected');
}
// brew.text = applyPatches(patches, brewFromServer.text)[0];
} catch (err) {
- debugTextMismatch(brewFromClient.text, brewFromServer.text, `edit/${brewFromClient.editId}`);
console.error('Failed to apply patches:', {
// patches : brewFromClient.patches,
// result : result,
@@ -426,77 +385,63 @@ const api = {
// throw err; // rethrow to preserve the 500 behavior
}
- let brew = _.assign(brewFromServer, brewFromClient);
-
- migrateSystemsToTags(brew);
+ let brew = _.assign(brewFromServer, brewFromClient);
+ brew = migrateSystemsToTags(brew);
brew.title = brew.title.trim();
brew.description = brew.description.trim() || '';
brew.text = api.mergeBrewText(brew);
-
- const googleId = brew.googleId;
- const { saveToGoogle, removeFromGoogle } = req.query;
- let afterSave = async ()=>true;
-
- if(brew.googleId && removeFromGoogle) {
- // If the google id exists and we're removing it from google, set afterSave to delete the google brew and mark the brew's google id as undefined
- afterSave = async ()=>{
- return await api.deleteGoogleBrew(req.account, googleId, brew.editId, res)
- .catch((err)=>{
- console.error(err);
- res.status(err?.status || err?.response?.status || 500).send(err.message || err);
- });
- };
-
- brew.googleId = undefined;
- } else if(!brew.googleId && saveToGoogle) {
- // If we don't have a google id and the user wants to save to google, create the google brew and set the google id on the brew
- brew.googleId = await api.newGoogleBrew(req.account, api.excludeGoogleProps(brew), res);
-
- if(!brew.googleId) return;
- } else if(brew.googleId) {
- // If the google id exists and no other actions are being performed, update the google brew
- const updated = await GoogleActions.updateGoogleBrew(api.excludeGoogleProps(brew), req.ip);
-
- if(!updated) return;
- }
-
- if(brew.googleId) {
- // If the google id exists after all those actions, exclude the props that are stored in google and aren't needed for rendering the brew items
- api.excludeStubProps(brew);
- } else {
- // Compress brew text to binary before saving
- brew.textBin = zlib.deflateRawSync(brew.text);
- // Delete the non-binary text field since it's not needed anymore
- brew.text = undefined;
- }
- brew.updatedAt = new Date();
- brew.version = (brew.version || 1) + 1;
-
+ brew.updatedAt = new Date();
+ brew.version = (brew.version || 1) + 1;
if(req.account) {
brew.authors = _.uniq(_.concat(brew.authors, req.account.username));
brew.invitedAuthors = _.uniq(_.filter(brew.invitedAuthors, (a)=>req.account.username !== a));
}
- // define a function to catch our save errors
- const saveError = (err)=>{
- console.error(err);
- res.status(err.status || 500).send(err.message || 'Unable to save brew to Homebrewery database');
- };
- let saved;
- if(!brew._id) {
- // if the brew does not have a stub id, create and save it, then write the new value back to the brew.
- saved = await new HomebrewModel(brew).save().catch(saveError);
- } else {
- // if the brew does have a stub id, update it using the stub id as the key.
- brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew);
- saved = await brew.save()
- .catch(saveError);
+ //=====----- Update to or remove from Google Drive -----=========//
+ const originalGoogleId = brew.googleId;
+ const { saveToGoogle, removeFromGoogle } = req.query;
+
+ if(brew.googleId && removeFromGoogle) { // If removing from google, remove the brew's googleId
+ brew.googleId = undefined;
}
+ else if(!brew.googleId && saveToGoogle) { // If adding to google, create new google document and record the googleId
+ brew.googleId = await api.newGoogleBrew(req.account, brew, res);
+ if(!brew.googleId) return;
+ }
+ else if(brew.googleId) { // If already on google, update the google brew
+ const updated = await GoogleActions.updateGoogleBrew(api.excludeGoogleProps(brew), req.ip);
+ if(!updated) return;
+ }
+
+ //=====----- Update to Mongo -----=====//
+ if(brew.googleId) {
+ // If google id exists after above actions, Mongo will store only a stub; exclude non-stub properties from update
+ brew = api.excludeStubProps(brew);
+ }
+
+ if(brew._id) // if the brew has a stub id, fetch and merge into Mongo stub document
+ brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew);
+ else // if not, create a new Mongo document
+ brew = new HomebrewModel(brew);
+
+ 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) return;
- // Call and wait for afterSave to complete
- const after = await afterSave();
- if(!after) return;
+
+ if(originalGoogleId && removeFromGoogle) {
+ const deleted = await api.deleteGoogleBrew(req.account, originalGoogleId, brew.editId, res)
+ .catch((err)=>{
+ console.error(err);
+ res.status(err?.status || err?.response?.status || 500).send(err.message || err);
+ });
+
+ if(!deleted) return;
+ }
saved.textBin = undefined; // Remove textBin from the saved object to save bandwidth
@@ -549,8 +494,6 @@ const api = {
if(shouldDeleteGoogleBrew) {
// When there are still authors remaining, we delete the google brew but store the full brew in the Homebrewery database
brew.googleId = undefined;
- brew.textBin = zlib.deflateRawSync(brew.text);
- brew.text = undefined;
}
brew.markModified('authors'); //Mongo will not properly update arrays without markModified()
await brew.save()
diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js
index 8bda5407b..ad6d3ac7e 100644
--- a/server/homebrew.api.spec.js
+++ b/server/homebrew.api.spec.js
@@ -1,6 +1,7 @@
/* eslint-disable max-lines */
import { splitTextStyleAndMetadata } from '../shared/helpers.js';
+import dedent from 'dedent';
describe('Tests for api', ()=>{
let api;
@@ -493,35 +494,35 @@ describe('Tests for api', ()=>{
},
});
- expect(result).toEqual(`\`\`\`metadata
-title: some title
-description: this is a description
-tags:
- - something
- - fun
-renderer: v3
-theme: phb
-bleedSize:
- top: .125in
- bottom: .125in
- inner: .125in
- outer: .125in
-safetySpace:
- top: .25in
- bottom: .25in
- outer: .25in
- inner: .5in
-trimSize:
- width: 8.5in
- height: 11in
-columns: '2'
-columnGutter: .125in
-license: None
-legalAuthors: ''
+ expect(result).toEqual(dedent`
+ \`\`\`metadata
+ title: some title
+ description: this is a description
+ tags:
+ - something
+ - fun
+ renderer: v3
+ theme: phb
+ columns: '2'
+ columnGutter: .125in
+ license: None
+ legalAuthors: ''
+ bleedSize:
+ top: .125in
+ bottom: .125in
+ inner: .125in
+ outer: .125in
+ safetySpace:
+ top: .25in
+ bottom: .25in
+ outer: .25in
+ inner: .5in
+ trimSize:
+ width: 8.5in
+ height: 11in
+ \`\`\`
-\`\`\`
-
-brew`);
+ brew`);
});
it('should set metadata and style', ()=>{
@@ -556,39 +557,39 @@ brew`);
},
});
- expect(result).toEqual(`\`\`\`metadata
-title: some title
-description: this is a description
-tags:
- - something
- - fun
-renderer: v3
-theme: phb
-bleedSize:
- top: .125in
- bottom: .125in
- inner: .125in
- outer: .125in
-safetySpace:
- top: .25in
- bottom: .25in
- outer: .25in
- inner: .5in
-trimSize:
- width: 8.5in
- height: 11in
-columns: '2'
-columnGutter: .125in
-license: None
-legalAuthors: ''
+ expect(result).toEqual(dedent`
+ \`\`\`metadata
+ title: some title
+ description: this is a description
+ tags:
+ - something
+ - fun
+ renderer: v3
+ theme: phb
+ columns: '2'
+ columnGutter: .125in
+ license: None
+ legalAuthors: ''
+ bleedSize:
+ top: .125in
+ bottom: .125in
+ inner: .125in
+ outer: .125in
+ safetySpace:
+ top: .25in
+ bottom: .25in
+ outer: .25in
+ inner: .5in
+ trimSize:
+ width: 8.5in
+ height: 11in
+ \`\`\`
-\`\`\`
+ \`\`\`css
+ hello yes i am css
+ \`\`\`
-\`\`\`css
-hello yes i am css
-\`\`\`
-
-brew`);
+ brew`);
});
});
describe('exclusion methods', ()=>{
@@ -700,8 +701,15 @@ brew`);
shareId : expect.any(String),
style : undefined,
tags : [],
- text : undefined,
- textBin : expect.objectContaining({}),
+ text : '```metadata\n' +
+ 'title: asdf\n' +
+ 'bleedSize: {}\n' +
+ 'safetySpace: {}\n' +
+ 'trimSize: {}' +
+ '\n' +
+ '```\n' +
+ '\n' +
+ 'asdf',
theme : '5ePHB',
thumbnail : '',
title : 'asdf',
@@ -1233,8 +1241,7 @@ brew`);
expect(saveFunc).toHaveBeenCalled();
expect(saved.authors).toEqual(['test2']);
expect(saved.googleId).toEqual(undefined);
- expect(saved.text).toEqual(undefined);
- expect(saved.textBin).not.toEqual(undefined);
+ expect(saved.text).not.toEqual(undefined);
});
it('should retain google brew and update stub when multiple authors and extra author requests deletion', async ()=>{
diff --git a/server/homebrew.model.js b/server/homebrew.model.js
index e923ac928..eceb08440 100644
--- a/server/homebrew.model.js
+++ b/server/homebrew.model.js
@@ -32,14 +32,21 @@ const HomebrewSchema = mongoose.Schema({
lock : { type: Object, index: true }
}, { versionKey: false });
+HomebrewSchema.pre('save', function() {
+ if(this.text !== undefined) {
+ this.textBin = zlib.deflateRawSync(this.text);
+ this.text = undefined;
+ }
+});
+
HomebrewSchema.statics.increaseView = async function(query) {
const brew = await Homebrew.findOne(query).exec();
brew.lastViewed = new Date();
brew.views = brew.views + 1;
await brew.save()
- .catch((err)=>{
- return err;
- });
+ .catch((err)=>{
+ return err;
+ });
return brew;
};
@@ -51,6 +58,7 @@ HomebrewSchema.statics.get = async function(query, fields=null){
if(!_.isNil(brew.textBin)) { // Uncompress zipped text field
const unzipped = zlib.inflateRawSync(brew.textBin);
brew.text = unzipped.toString();
+ brew.textBin = undefined;
}
return brew;
};