0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-04 10:22:38 +00:00

Merge branch 'master' into Update-core-and-reset

This commit is contained in:
Víctor Losada Hernández
2024-11-12 22:05:27 +01:00
committed by GitHub
7 changed files with 116 additions and 57 deletions

View File

@@ -1,3 +1,5 @@
require('./brewLookup.less');
const React = require('react'); const React = require('react');
const createClass = require('create-react-class'); const createClass = require('create-react-class');
const cx = require('classnames'); const cx = require('classnames');
@@ -12,22 +14,43 @@ const BrewLookup = createClass({
}, },
getInitialState() { getInitialState() {
return { return {
query : '', query : '',
foundBrew : null, foundBrew : null,
searching : false, searching : false,
error : null error : null,
scriptCount : 0
}; };
}, },
handleChange(e){ handleChange(e){
this.setState({ query: e.target.value }); this.setState({ query: e.target.value });
}, },
lookup(){ lookup(){
this.setState({ searching: true, error: null }); this.setState({ searching: true, error: null, scriptCount: 0 });
request.get(`/admin/lookup/${this.state.query}`) request.get(`/admin/lookup/${this.state.query}`)
.then((res)=>this.setState({ foundBrew: res.body })) .then((res)=>{
const foundBrew = res.body;
const scriptCheck = foundBrew?.text.match(/(<\/?s)cript/g);
this.setState({
foundBrew : foundBrew,
scriptCount : scriptCheck?.length || 0,
});
})
.catch((err)=>this.setState({ error: err })) .catch((err)=>this.setState({ error: err }))
.finally(()=>this.setState({ searching: false })); .finally(()=>{
this.setState({
searching : false
});
});
},
async cleanScript(){
if(!this.state.foundBrew?.shareId) return;
await request.put(`/admin/clean/script/${this.state.foundBrew.shareId}`)
.catch((err)=>{ this.setState({ error: err }); return; });
this.lookup();
}, },
renderFoundBrew(){ renderFoundBrew(){
@@ -46,12 +69,23 @@ const BrewLookup = createClass({
<dt>Share Link</dt> <dt>Share Link</dt>
<dd><a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>/share/{brew.shareId}</a></dd> <dd><a href={`/share/${brew.shareId}`} target='_blank' rel='noopener noreferrer'>/share/{brew.shareId}</a></dd>
<dt>Created Time</dt>
<dd>{brew.createdAt ? Moment(brew.createdAt).toLocaleString() : 'No creation date'}</dd>
<dt>Last Updated</dt> <dt>Last Updated</dt>
<dd>{Moment(brew.updatedAt).fromNow()}</dd> <dd>{Moment(brew.updatedAt).fromNow()}</dd>
<dt>Num of Views</dt> <dt>Num of Views</dt>
<dd>{brew.views}</dd> <dd>{brew.views}</dd>
<dt>SCRIPT tags detected</dt>
<dd>{this.state.scriptCount}</dd>
</dl> </dl>
{this.state.scriptCount > 0 &&
<div className='cleanButton'>
<button onClick={this.cleanScript}>CLEAN BREW</button>
</div>
}
</div>; </div>;
}, },

View File

@@ -0,0 +1,6 @@
.brewLookup {
.cleanButton {
display : inline-block;
width : 100%;
}
}

View File

@@ -161,7 +161,8 @@ const BrewRenderer = (props)=>{
renderedPages.length = 0; renderedPages.length = 0;
// Render currently-edited page first so cross-page effects (variables, links) can propagate out first // Render currently-edited page first so cross-page effects (variables, links) can propagate out first
renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1); if(rawPages.length > props.currentEditorCursorPageNum -1)
renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1);
_.forEach(rawPages, (page, index)=>{ _.forEach(rawPages, (page, index)=>{
if((isInView(index) || !renderedPages[index]) && typeof window !== 'undefined'){ if((isInView(index) || !renderedPages[index]) && typeof window !== 'undefined'){

49
package-lock.json generated
View File

@@ -21,11 +21,11 @@
"cookie-parser": "^1.4.7", "cookie-parser": "^1.4.7",
"create-react-class": "^15.7.0", "create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3", "dedent-tabs": "^0.10.3",
"dompurify": "^3.1.7", "dompurify": "^3.2.0",
"expr-eval": "^2.0.2", "expr-eval": "^2.0.2",
"express": "^4.21.1", "express": "^4.21.1",
"express-async-handler": "^1.2.0", "express-async-handler": "^1.2.0",
"express-static-gzip": "2.1.8", "express-static-gzip": "2.2.0",
"fs-extra": "11.2.0", "fs-extra": "11.2.0",
"idb-keyval": "^6.2.1", "idb-keyval": "^6.2.1",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
@@ -33,13 +33,13 @@
"less": "^3.13.1", "less": "^3.13.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"marked": "11.2.0", "marked": "11.2.0",
"marked-emoji": "^1.4.2", "marked-emoji": "^1.4.3",
"marked-extended-tables": "^1.0.10", "marked-extended-tables": "^1.0.10",
"marked-gfm-heading-id": "^3.2.0", "marked-gfm-heading-id": "^3.2.0",
"marked-smartypants-lite": "^1.0.2", "marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19", "markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1", "moment": "^2.30.1",
"mongoose": "^8.7.3", "mongoose": "^8.8.1",
"nanoid": "3.3.4", "nanoid": "3.3.4",
"nconf": "^0.12.1", "nconf": "^0.12.1",
"react": "^18.3.1", "react": "^18.3.1",
@@ -4327,9 +4327,9 @@
} }
}, },
"node_modules/bson": { "node_modules/bson": {
"version": "6.8.0", "version": "6.9.0",
"resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", "resolved": "https://registry.npmjs.org/bson/-/bson-6.9.0.tgz",
"integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", "integrity": "sha512-X9hJeyeM0//Fus+0pc5dSUMhhrrmWwQUtdavaQeF3Ta6m69matZkGWV/MrBcnwUeLC8W9kwwc2hfkZgUuCX3Ig==",
"engines": { "engines": {
"node": ">=16.20.1" "node": ">=16.20.1"
} }
@@ -5455,9 +5455,9 @@
} }
}, },
"node_modules/dompurify": { "node_modules/dompurify": {
"version": "3.1.7", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.0.tgz",
"integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==" "integrity": "sha512-AMdOzK44oFWqHEi0wpOqix/fUNY707OmoeFDnbi3Q5I8uOpy21ufUA5cDJPr0bosxrflOVD/H2DMSvuGKJGfmQ=="
}, },
"node_modules/duplexer2": { "node_modules/duplexer2": {
"version": "0.1.4", "version": "0.1.4",
@@ -6290,10 +6290,11 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/express-static-gzip": { "node_modules/express-static-gzip": {
"version": "2.1.8", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/express-static-gzip/-/express-static-gzip-2.1.8.tgz", "resolved": "https://registry.npmjs.org/express-static-gzip/-/express-static-gzip-2.2.0.tgz",
"integrity": "sha512-g8tiJuI9Y9Ffy59ehVXvqb0hhP83JwZiLxzanobPaMbkB5qBWA8nuVgd+rcd5qzH3GkgogTALlc0BaADYwnMbQ==", "integrity": "sha512-4ZQ0pHX0CAauxmzry2/8XFLM6aZA4NBvg9QezSlsEO1zLnl7vMFa48/WIcjzdfOiEUS4S1npPPKP2NHHYAp6qg==",
"dependencies": { "dependencies": {
"parseurl": "^1.3.3",
"serve-static": "^1.16.2" "serve-static": "^1.16.2"
} }
}, },
@@ -10487,11 +10488,11 @@
} }
}, },
"node_modules/marked-emoji": { "node_modules/marked-emoji": {
"version": "1.4.2", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-1.4.2.tgz", "resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-1.4.3.tgz",
"integrity": "sha512-2sP+bp2z76dwbILzQ7ijy2PyjjAJR3iAZCzaNGThD2UijFUBeidkn6MoCdX/j47tPIcWt9nwnjqRQPd01ZrfdA==", "integrity": "sha512-HDZx1VOmzu7XT2QNKWfrHGbNRMTWKj9XD78yrcH1madD30HpGLMODPOmKr/e7CA7NKKXkpXXNdndQn++ysXmHg==",
"peerDependencies": { "peerDependencies": {
"marked": ">=4 <15" "marked": ">=4 <16"
} }
}, },
"node_modules/marked-extended-tables": { "node_modules/marked-extended-tables": {
@@ -10865,13 +10866,13 @@
} }
}, },
"node_modules/mongoose": { "node_modules/mongoose": {
"version": "8.7.3", "version": "8.8.1",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.7.3.tgz", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.1.tgz",
"integrity": "sha512-Xl6+dzU5ZpEcDoJ8/AyrIdAwTY099QwpolvV73PIytpK13XqwllLq/9XeVzzLEQgmyvwBVGVgjmMrKbuezxrIA==", "integrity": "sha512-l7DgeY1szT98+EKU8GYnga5WnyatAu+kOQ2VlVX1Mxif6A0Umt0YkSiksCiyGxzx8SPhGe9a53ND1GD4yVDrPA==",
"dependencies": { "dependencies": {
"bson": "^6.7.0", "bson": "^6.7.0",
"kareem": "2.6.3", "kareem": "2.6.3",
"mongodb": "6.9.0", "mongodb": "~6.10.0",
"mpath": "0.9.0", "mpath": "0.9.0",
"mquery": "5.0.0", "mquery": "5.0.0",
"ms": "2.1.3", "ms": "2.1.3",
@@ -10943,9 +10944,9 @@
} }
}, },
"node_modules/mongoose/node_modules/mongodb": { "node_modules/mongoose/node_modules/mongodb": {
"version": "6.9.0", "version": "6.10.0",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.10.0.tgz",
"integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==", "integrity": "sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==",
"dependencies": { "dependencies": {
"@mongodb-js/saslprep": "^1.1.5", "@mongodb-js/saslprep": "^1.1.5",
"bson": "^6.7.0", "bson": "^6.7.0",

View File

@@ -98,11 +98,11 @@
"cookie-parser": "^1.4.7", "cookie-parser": "^1.4.7",
"create-react-class": "^15.7.0", "create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3", "dedent-tabs": "^0.10.3",
"dompurify": "^3.1.7", "dompurify": "^3.2.0",
"expr-eval": "^2.0.2", "expr-eval": "^2.0.2",
"express": "^4.21.1", "express": "^4.21.1",
"express-async-handler": "^1.2.0", "express-async-handler": "^1.2.0",
"express-static-gzip": "2.1.8", "express-static-gzip": "2.2.0",
"fs-extra": "11.2.0", "fs-extra": "11.2.0",
"idb-keyval": "^6.2.1", "idb-keyval": "^6.2.1",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
@@ -110,13 +110,13 @@
"less": "^3.13.1", "less": "^3.13.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"marked": "11.2.0", "marked": "11.2.0",
"marked-emoji": "^1.4.2", "marked-emoji": "^1.4.3",
"marked-extended-tables": "^1.0.10", "marked-extended-tables": "^1.0.10",
"marked-gfm-heading-id": "^3.2.0", "marked-gfm-heading-id": "^3.2.0",
"marked-smartypants-lite": "^1.0.2", "marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19", "markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1", "moment": "^2.30.1",
"mongoose": "^8.7.3", "mongoose": "^8.8.1",
"nanoid": "3.3.4", "nanoid": "3.3.4",
"nconf": "^0.12.1", "nconf": "^0.12.1",
"react": "^18.3.1", "react": "^18.3.1",

View File

@@ -5,6 +5,10 @@ const Moment = require('moment');
const templateFn = require('../client/template.js'); const templateFn = require('../client/template.js');
const zlib = require('zlib'); const zlib = require('zlib');
const HomebrewAPI = require('./homebrew.api.js');
const asyncHandler = require('express-async-handler');
const { splitTextStyleAndMetadata } = require('../shared/helpers.js');
process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin'; process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin';
process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3'; process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3';
@@ -66,23 +70,8 @@ router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{
}); });
/* Searches for matching edit or share id, also attempts to partial match */ /* Searches for matching edit or share id, also attempts to partial match */
router.get('/admin/lookup/:id', mw.adminOnly, async (req, res, next)=>{ router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res, next)=>{
HomebrewModel.findOne({ return res.json(req.brew);
$or : [
{ editId: { $regex: req.params.id, $options: 'i' } },
{ shareId: { $regex: req.params.id, $options: 'i' } },
]
}).exec()
.then((brew)=>{
if(!brew) // No document found
return res.status(404).json({ error: 'Document not found' });
else
return res.json(brew);
})
.catch((err)=>{
console.error(err);
return res.status(500).json({ error: 'Internal Server Error' });
});
}); });
/* Find 50 brews that aren't compressed yet */ /* Find 50 brews that aren't compressed yet */
@@ -100,6 +89,25 @@ router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{
}); });
}); });
/* Cleans `<script` and `</script>` from the "text" field of a brew */
router.put('/admin/clean/script/:id', asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res)=>{
console.log(`[ADMIN] Cleaning script tags from ShareID ${req.params.id}`);
function cleanText(text){return text.replaceAll(/(<\/?s)cript/gi, '');};
const brew = req.brew;
const properties = ['text', 'description', 'title'];
properties.forEach((property)=>{
brew[property] = cleanText(brew[property]);
});
splitTextStyleAndMetadata(brew);
req.body = brew;
return await HomebrewAPI.updateBrew(req, res);
});
/* Compresses the "text" field of a brew to binary */ /* Compresses the "text" field of a brew to binary */
router.put('/admin/compress/:id', (req, res)=>{ router.put('/admin/compress/:id', (req, res)=>{
@@ -144,7 +152,7 @@ router.get('/admin/notification/all', async (req, res, next)=>{
try { try {
const notifications = await NotificationModel.getAll(); const notifications = await NotificationModel.getAll();
return res.json(notifications); return res.json(notifications);
} catch (error) { } catch (error) {
console.log('Error getting all notifications: ', error.message); console.log('Error getting all notifications: ', error.message);
return res.status(500).json({ message: error.message }); return res.status(500).json({ message: error.message });

View File

@@ -87,8 +87,18 @@ const api = {
// Get relevant IDs for the brew // Get relevant IDs for the brew
const { id, googleId } = api.getId(req); const { id, googleId } = api.getId(req);
const accessMap = {
edit : { editId: id },
share : { shareId: id },
admin : {
$or : [
{ editId: id },
{ shareId: id },
] }
};
// Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine. // Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine.
let stub = await HomebrewModel.get(accessType === 'edit' ? { editId: id } : { shareId: id }) let stub = await HomebrewModel.get(accessMap[accessType])
.catch((err)=>{ .catch((err)=>{
if(googleId) { if(googleId) {
console.warn(`Unable to find document stub for ${accessType}Id ${id}`); console.warn(`Unable to find document stub for ${accessType}Id ${id}`);
@@ -295,9 +305,8 @@ const api = {
req.params.id = currentTheme.theme; req.params.id = currentTheme.theme;
req.params.renderer = currentTheme.renderer; req.params.renderer = currentTheme.renderer;
} } else {
//=== Static Themes ===// //=== Static Themes ===//
else {
const localSnippets = `${req.params.renderer}_${req.params.id}`; // Just log the name for loading on client const localSnippets = `${req.params.renderer}_${req.params.id}`; // Just log the name for loading on client
const localStyle = `@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");`; const localStyle = `@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");`;
completeSnippets.push(localSnippets); completeSnippets.push(localSnippets);