From e8e16f4d66c1daab22d110cc264a2f99c55963ce Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Tue, 17 Sep 2024 14:46:56 -0500 Subject: [PATCH 01/75] Initial commit: Rename component, set basic structure No actual functionality implemented yet, just renames the component from "StringArrayEditor" to "TagInput", for brevity at the possible cost of clarity. For now, the original StringArrayEditor is kept and named "TagInput-class.jsx" so that I can reference it as I work on the functional component. --- .../editor/metadataEditor/metadataEditor.jsx | 6 +++--- .../tagInput-class.jsx} | 6 +++--- client/homebrew/editor/tagInput/tagInput.jsx | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) rename client/homebrew/editor/{stringArrayEditor/stringArrayEditor.jsx => tagInput/tagInput-class.jsx} (97%) create mode 100644 client/homebrew/editor/tagInput/tagInput.jsx diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 0f1f6ad54..6ee607eab 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -6,7 +6,7 @@ const _ = require('lodash'); const request = require('../../utils/request-middleware.js'); const Nav = require('naturalcrit/nav/nav.jsx'); const Combobox = require('client/components/combobox.jsx'); -const StringArrayEditor = require('../stringArrayEditor/stringArrayEditor.jsx'); +const TagInput = require('../tagInput/tagInput.jsx'); const Themes = require('themes/themes.json'); @@ -344,7 +344,7 @@ const MetadataEditor = createClass({ {this.renderThumbnail()} - this.handleFieldChange('tags', e)}/> @@ -368,7 +368,7 @@ const MetadataEditor = createClass({ {this.renderAuthors()} - !this.props.metadata.authors?.includes(v)]} placeholder='invite author' unique={true} values={this.props.metadata.invitedAuthors} diff --git a/client/homebrew/editor/stringArrayEditor/stringArrayEditor.jsx b/client/homebrew/editor/tagInput/tagInput-class.jsx similarity index 97% rename from client/homebrew/editor/stringArrayEditor/stringArrayEditor.jsx rename to client/homebrew/editor/tagInput/tagInput-class.jsx index 8f06ae561..b7acf31d0 100644 --- a/client/homebrew/editor/stringArrayEditor/stringArrayEditor.jsx +++ b/client/homebrew/editor/tagInput/tagInput-class.jsx @@ -2,8 +2,8 @@ const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); -const StringArrayEditor = createClass({ - displayName : 'StringArrayEditor', +const TagInput = createClass({ + displayName : 'TagInput', getDefaultProps : function() { return { label : '', @@ -146,4 +146,4 @@ const StringArrayEditor = createClass({ } }); -module.exports = StringArrayEditor; \ No newline at end of file +module.exports = TagInput; \ No newline at end of file diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx new file mode 100644 index 000000000..289432175 --- /dev/null +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -0,0 +1,21 @@ +const React = require('react'); +const { useState, useRef, useEffect } = React; +const _ = require('lodash'); + +const TagInput = ({unique, ...props})=>{ + + const [temporaryValue, setTemporaryValue] = useState(''); + + return ( +
+ +
+ ) +} + +module.exports = TagInput; \ No newline at end of file From d505e4e24c228d94467f5c99d1af90c973670343 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Tue, 17 Sep 2024 23:16:06 -0500 Subject: [PATCH 02/75] Render element for each value from props Take an array of values from props, load it into valueContext state with an "editing" boolean for each value. Then, when rendering the component, take each value in the valueContext array and create a div for each -- at this point, if the value is "being edited", it returns a div with text "editing". If not being edited, it returns a div with the value as text. Nothing is being edited at this point since that functionality doesn't exist yet. --- .../editor/metadataEditor/metadataEditor.jsx | 7 +++-- client/homebrew/editor/tagInput/tagInput.jsx | 28 +++++++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 6ee607eab..97b4df2ea 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -347,7 +347,8 @@ const MetadataEditor = createClass({ this.handleFieldChange('tags', e)}/> + // onChange={(e)=>this.handleFieldChange('tags', e)} + />
@@ -372,8 +373,10 @@ const MetadataEditor = createClass({ validators={[(v)=>!this.props.metadata.authors?.includes(v)]} placeholder='invite author' unique={true} values={this.props.metadata.invitedAuthors} + values={['cat', 'dog', 'fish']} notes={['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.']} - onChange={(e)=>this.handleFieldChange('invitedAuthors', e)}/> + // onChange={(e)=>this.handleFieldChange('invitedAuthors', e)} + />
diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 289432175..9391b9c16 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -1,19 +1,29 @@ const React = require('react'); -const { useState, useRef, useEffect } = React; +const { useState } = React; const _ = require('lodash'); -const TagInput = ({unique, ...props})=>{ +const TagInput = ({unique = true, values = [], ...props})=>{ const [temporaryValue, setTemporaryValue] = useState(''); + const [valueContext, setValueContext] = useState(values.map((value)=>({ value: value, editing : false }))); + + const tagElement = (value)=>{ + return ( +
{value}
+ ) + } return ( -
- +
+ + + {Object.values(valueContext).map((context, i)=>{ return context.editing ? tagElement('editing') : tagElement(context.value) })} + + setTemporaryValue(e.target.value)} />
) } From d5c5b4315beee23ba511a069d6d25779d64f3299 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Tue, 17 Sep 2024 23:28:56 -0500 Subject: [PATCH 03/75] Render tags as "write" or "read" Tags are now either "readTag" or "writeTag", with the former being a div with the tag value and the latter a text input with the value. Minor class name change in LESS. --- .../editor/metadataEditor/metadataEditor.less | 2 +- client/homebrew/editor/tagInput/tagInput.jsx | 25 +++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 27ebd88c2..914af9c4e 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -270,7 +270,7 @@ &:last-child { border-radius : 0 0.5em 0.5em 0; } } - .badge { + .tag { padding : 0.3em; margin : 2px; font-size : 0.9em; diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 9391b9c16..bd3f53db4 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -7,9 +7,15 @@ const TagInput = ({unique = true, values = [], ...props})=>{ const [temporaryValue, setTemporaryValue] = useState(''); const [valueContext, setValueContext] = useState(values.map((value)=>({ value: value, editing : false }))); - const tagElement = (value)=>{ + const readTag = (value)=>{ return ( -
{value}
+
{value}
+ ) + } + + const writeTag = (value)=>{ + return ( + ) } @@ -17,13 +23,16 @@ const TagInput = ({unique = true, values = [], ...props})=>{
- {Object.values(valueContext).map((context, i)=>{ return context.editing ? tagElement('editing') : tagElement(context.value) })} +
- setTemporaryValue(e.target.value)} /> + {Object.values(valueContext).map((context, i)=>{ return context.editing ? writeTag(context.value) : readTag(context.value) })} + + setTemporaryValue(e.target.value)} /> +
) } From 36aa4ea508e35a9220f747a2e52f2db56c045681 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Tue, 17 Sep 2024 23:50:59 -0500 Subject: [PATCH 04/75] Add click handler for readTags to open text input Clicking on a readTag now converts that tag to a text input, and maintains the tag value. It also closes any other open text inputs amongst the tags (but leaves the "new tag" input open). --- client/homebrew/editor/tagInput/tagInput.jsx | 21 ++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index bd3f53db4..8063b4ab2 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -7,13 +7,26 @@ const TagInput = ({unique = true, values = [], ...props})=>{ const [temporaryValue, setTemporaryValue] = useState(''); const [valueContext, setValueContext] = useState(values.map((value)=>({ value: value, editing : false }))); - const readTag = (value)=>{ + + const editTag = (evt)=>{ + setValueContext(valueContext.map((context)=>{ + context.editing = context.value === evt.target.dataset.value ? true : false; + return context; + })) + } + + const renderReadTag = (value)=>{ return ( -
{value}
+
editTag(evt)}> + {value} +
) } - const writeTag = (value)=>{ + const renderWriteTag = (value)=>{ return ( ) @@ -25,7 +38,7 @@ const TagInput = ({unique = true, values = [], ...props})=>{
- {Object.values(valueContext).map((context, i)=>{ return context.editing ? writeTag(context.value) : readTag(context.value) })} + {Object.values(valueContext).map((context, i)=>{ return context.editing ? renderWriteTag(context.value) : renderReadTag(context.value) })} Date: Wed, 18 Sep 2024 21:00:24 -0500 Subject: [PATCH 05/75] add editing of input functionality Currently uses uncontrolled inputs with a `defaultValue` attribute set to the values passed in via props. The input can then be edited, and when `Enter` is pressed, it updates the stored value state. Later, this can be updated to be trigger with `Tab` or clicking outside the active input element. --- client/homebrew/editor/tagInput/tagInput.jsx | 81 ++++++++++++-------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 8063b4ab2..cfcb2be42 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -1,53 +1,74 @@ const React = require('react'); const { useState } = React; -const _ = require('lodash'); - -const TagInput = ({unique = true, values = [], ...props})=>{ +const TagInput = ({ unique = true, values = [], ...props }) => { const [temporaryValue, setTemporaryValue] = useState(''); - const [valueContext, setValueContext] = useState(values.map((value)=>({ value: value, editing : false }))); + const [valueContext, setValueContext] = useState(values.map((value) => ({ value, editing: false }))); + const handleInputKeyDown = (evt, value) => { + if (evt.key === 'Enter') { + submitTag(evt.target.value, value); + } + }; - const editTag = (evt)=>{ - setValueContext(valueContext.map((context)=>{ - context.editing = context.value === evt.target.dataset.value ? true : false; - return context; - })) - } + const submitTag = (newValue, originalValue) => { + setValueContext((prevContext) => { + return prevContext.map((context) => { + if (context.value === originalValue) { + return { ...context, value: newValue, editing: false }; + } + return context; + }); + }); + }; - const renderReadTag = (value)=>{ + const editTag = (valueToEdit) => { + setValueContext((prevContext) => { + return prevContext.map((context) => { + if (context.value === valueToEdit) { + return { ...context, editing: true }; + } + return { ...context, editing: false }; + }); + }); + }; + + const renderReadTag = (context) => { return ( -
editTag(evt)}> - {value} +
editTag(context.value)}> + {context.value}
- ) - } + ); + }; - const renderWriteTag = (value)=>{ + const renderWriteTag = (context) => { return ( - - ) - } + handleInputKeyDown(evt, context.value)} + autoFocus + /> + ); + }; return (
-
- - {Object.values(valueContext).map((context, i)=>{ return context.editing ? renderWriteTag(context.value) : renderReadTag(context.value) })} + {valueContext.map((context) => { return context.editing ? renderWriteTag(context) : renderReadTag(context); })} setTemporaryValue(e.target.value)} /> + onChange={(e) => setTemporaryValue(e.target.value)} />
- ) -} + ); +}; -module.exports = TagInput; \ No newline at end of file +module.exports = TagInput; From d1686c4c8f7005786af1cc3c29333636405b5186 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Wed, 18 Sep 2024 21:50:04 -0500 Subject: [PATCH 06/75] Add in handlers for TagInput value changes Now brew metadata is actually updated and preserved across reloads to match updated tag values. useEffect calls the props.onChange event from the parent component on every change to the valueContext state of this component (right now, after hitting Enter in a tag input). --- .../editor/metadataEditor/metadataEditor.jsx | 5 ++--- client/homebrew/editor/tagInput/tagInput.jsx | 14 +++++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 97b4df2ea..7df2e44b6 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -347,7 +347,7 @@ const MetadataEditor = createClass({ this.handleFieldChange('tags', e)} + onChange={(e)=>this.handleFieldChange('tags', e)} />
@@ -373,9 +373,8 @@ const MetadataEditor = createClass({ validators={[(v)=>!this.props.metadata.authors?.includes(v)]} placeholder='invite author' unique={true} values={this.props.metadata.invitedAuthors} - values={['cat', 'dog', 'fish']} notes={['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.']} - // onChange={(e)=>this.handleFieldChange('invitedAuthors', e)} + onChange={(e)=>this.handleFieldChange('invitedAuthors', e)} />
diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index cfcb2be42..22760896a 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -1,16 +1,28 @@ const React = require('react'); -const { useState } = React; +const { useState, useEffect } = React; const TagInput = ({ unique = true, values = [], ...props }) => { const [temporaryValue, setTemporaryValue] = useState(''); const [valueContext, setValueContext] = useState(values.map((value) => ({ value, editing: false }))); + useEffect(()=>{ + handleChange(valueContext.map((context)=>context.value)) + }, [valueContext]) + + const handleChange = (value)=>{ + props.onChange({ + target : { value } + }) + }; + const handleInputKeyDown = (evt, value) => { if (evt.key === 'Enter') { submitTag(evt.target.value, value); } }; + + const submitTag = (newValue, originalValue) => { setValueContext((prevContext) => { return prevContext.map((context) => { From 70a3cb9ef9a1f1ae745107bb47cb259c245f74c0 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Wed, 18 Sep 2024 22:46:00 -0500 Subject: [PATCH 07/75] Add method for adding new tags Component now accepts new tags entered in the always-present input field. Entering a value and hitting Enter submits the tag, and it appears as a new tag. Updated the tag list keys to be unique (via `index`). To-Do: empty 'new tag' input after submitting. --- client/homebrew/editor/tagInput/tagInput.jsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 22760896a..f42e2f62f 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -1,5 +1,6 @@ const React = require('react'); const { useState, useEffect } = React; +const _ = require('lodash'); const TagInput = ({ unique = true, values = [], ...props }) => { const [temporaryValue, setTemporaryValue] = useState(''); @@ -25,6 +26,11 @@ const TagInput = ({ unique = true, values = [], ...props }) => { const submitTag = (newValue, originalValue) => { setValueContext((prevContext) => { + // add new tag + if(originalValue === null){ + return [...prevContext, { value: newValue, editing: false }] + } + // update existing tag return prevContext.map((context) => { if (context.value === originalValue) { return { ...context, value: newValue, editing: false }; @@ -45,9 +51,9 @@ const TagInput = ({ unique = true, values = [], ...props }) => { }); }; - const renderReadTag = (context) => { + const renderReadTag = (context, index) => { return ( -
editTag(context.value)}> @@ -56,10 +62,10 @@ const TagInput = ({ unique = true, values = [], ...props }) => { ); }; - const renderWriteTag = (context) => { + const renderWriteTag = (context, index) => { return ( handleInputKeyDown(evt, context.value)} autoFocus @@ -71,13 +77,14 @@ const TagInput = ({ unique = true, values = [], ...props }) => {
- {valueContext.map((context) => { return context.editing ? renderWriteTag(context) : renderReadTag(context); })} + {valueContext.map((context, index) => { return context.editing ? renderWriteTag(context, index) : renderReadTag(context, index); })} setTemporaryValue(e.target.value)} /> + onChange={(e) => setTemporaryValue(e.target.value)} + onKeyDown={(evt) => handleInputKeyDown(evt, null)} />
); From c65210b3ed6899e6ed131187a91b042d32fb2d35 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Wed, 18 Sep 2024 23:13:46 -0500 Subject: [PATCH 08/75] Add 'remove' button and method New button that triggers `submitTag()` method directly (rather than throw onKeyDown event) and passes `null` as the newValue. New `if` condition checks for null on newValue and if true, removes the tag that matches the originalValue. This *does* currently delete all duplicate tags if they match the one you are deleting. Not sure when you'd ever want duplicate tags, but regardless i'll likely switch this to work via Index, not value. --- client/homebrew/editor/tagInput/tagInput.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index f42e2f62f..03678961d 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -26,6 +26,11 @@ const TagInput = ({ unique = true, values = [], ...props }) => { const submitTag = (newValue, originalValue) => { setValueContext((prevContext) => { + // remove existing tag + if(newValue === null){ + console.log('remove'); + return [...prevContext].filter((context)=>context.value !== originalValue); + } // add new tag if(originalValue === null){ return [...prevContext, { value: newValue, editing: false }] @@ -58,6 +63,7 @@ const TagInput = ({ unique = true, values = [], ...props }) => { className='tag' onClick={() => editTag(context.value)}> {context.value} +
); }; From c1288ce4bb79ef7b45085113f7cc1f889cd97e6b Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Wed, 18 Sep 2024 23:24:10 -0500 Subject: [PATCH 09/75] Use index to find and remove tags Fixes issue in last commit, so removing a tag that has duplicate value of other tags only removes the correct one, not the others as well. --- client/homebrew/editor/tagInput/tagInput.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 03678961d..f72ec17cf 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -24,12 +24,12 @@ const TagInput = ({ unique = true, values = [], ...props }) => { - const submitTag = (newValue, originalValue) => { + const submitTag = (newValue, originalValue, index) => { setValueContext((prevContext) => { // remove existing tag if(newValue === null){ console.log('remove'); - return [...prevContext].filter((context)=>context.value !== originalValue); + return [...prevContext].filter((context, i)=>i !== index); } // add new tag if(originalValue === null){ @@ -63,7 +63,7 @@ const TagInput = ({ unique = true, values = [], ...props }) => { className='tag' onClick={() => editTag(context.value)}> {context.value} - +
); }; From a54adc1e4b9756dd9efc23b4c114516d5ebd697f Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Wed, 18 Sep 2024 23:39:26 -0500 Subject: [PATCH 10/75] Set new tag input to clear itself after submission Now whenever a new tag is submitted, the input element is cleared and ready for the next tag. Whitespace cleanup. --- client/homebrew/editor/tagInput/tagInput.jsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index f72ec17cf..625e89c36 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -16,19 +16,17 @@ const TagInput = ({ unique = true, values = [], ...props }) => { }) }; - const handleInputKeyDown = (evt, value) => { + const handleInputKeyDown = (evt, value, clear = false) => { if (evt.key === 'Enter') { submitTag(evt.target.value, value); - } + if(clear){ setTemporaryValue(''); } + }; }; - - const submitTag = (newValue, originalValue, index) => { setValueContext((prevContext) => { // remove existing tag if(newValue === null){ - console.log('remove'); return [...prevContext].filter((context, i)=>i !== index); } // add new tag @@ -90,7 +88,7 @@ const TagInput = ({ unique = true, values = [], ...props }) => { placeholder={props.placeholder} value={temporaryValue} onChange={(e) => setTemporaryValue(e.target.value)} - onKeyDown={(evt) => handleInputKeyDown(evt, null)} /> + onKeyDown={(evt) => handleInputKeyDown(evt, null, true)} />
); From 5b4a7c168fc3985d1f15103fd0dcc477d8e4d314 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Wed, 18 Sep 2024 23:54:12 -0500 Subject: [PATCH 11/75] Add comma to "submit" buttons Now comma (`,`) submits a tag, like `Enter` --- client/homebrew/editor/tagInput/tagInput.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 625e89c36..dee7baf94 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -17,7 +17,8 @@ const TagInput = ({ unique = true, values = [], ...props }) => { }; const handleInputKeyDown = (evt, value, clear = false) => { - if (evt.key === 'Enter') { + if (_.includes(['Enter', ','], evt.key)) { + evt.preventDefault(); submitTag(evt.target.value, value); if(clear){ setTemporaryValue(''); } }; @@ -88,7 +89,7 @@ const TagInput = ({ unique = true, values = [], ...props }) => { placeholder={props.placeholder} value={temporaryValue} onChange={(e) => setTemporaryValue(e.target.value)} - onKeyDown={(evt) => handleInputKeyDown(evt, null, true)} /> + onKeyDown={(evt) =>handleInputKeyDown(evt, null, true)} />
); From 7ea1696065e16a2e174a3edfafdcb2ea8f4cc62b Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Thu, 19 Sep 2024 10:40:09 -0500 Subject: [PATCH 12/75] Adjust html structure to handle tags as list Begin work on setting a better html structure for the component. Create a .less file for the component, which I may not actually use. --- client/homebrew/editor/tagInput/tagInput.jsx | 11 +++++++---- client/homebrew/editor/tagInput/tagInput.less | 0 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 client/homebrew/editor/tagInput/tagInput.less diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 625e89c36..8619df6cf 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -1,3 +1,4 @@ +require('./tagInput.less'); const React = require('react'); const { useState, useEffect } = React; const _ = require('lodash'); @@ -56,13 +57,13 @@ const TagInput = ({ unique = true, values = [], ...props }) => { const renderReadTag = (context, index) => { return ( -
editTag(context.value)}> {context.value} -
+ ); }; @@ -80,8 +81,10 @@ const TagInput = ({ unique = true, values = [], ...props }) => { return (
-
- {valueContext.map((context, index) => { return context.editing ? renderWriteTag(context, index) : renderReadTag(context, index); })} +
+
    + {valueContext.map((context, index) => { return context.editing ? renderWriteTag(context, index) : renderReadTag(context, index); })} +
Date: Thu, 19 Sep 2024 15:48:47 -0500 Subject: [PATCH 13/75] Fix multiple duplicate tags updating at once Fixes an issue where tags with duplicate values would all update to the same value after editing just one. Also an adjustment to the parameters that are passed to handleInputKeyDown-- they are now one object. This helps handle an "options" object where more optional features can be turned on and off. --- client/homebrew/editor/tagInput/tagInput.jsx | 30 +++++++++++--------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 387e09b81..2c636b0c8 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -17,12 +17,14 @@ const TagInput = ({ unique = true, values = [], ...props }) => { }) }; - const handleInputKeyDown = (evt, value, clear = false) => { + const handleInputKeyDown = ({ evt, value, index, options = {} }) => { if (_.includes(['Enter', ','], evt.key)) { evt.preventDefault(); - submitTag(evt.target.value, value); - if(clear){ setTemporaryValue(''); } - }; + submitTag(evt.target.value, value, index); + if (options.clear) { + setTemporaryValue(''); + } + } }; const submitTag = (newValue, originalValue, index) => { @@ -36,8 +38,8 @@ const TagInput = ({ unique = true, values = [], ...props }) => { return [...prevContext, { value: newValue, editing: false }] } // update existing tag - return prevContext.map((context) => { - if (context.value === originalValue) { + return prevContext.map((context, i) => { + if (i === index) { return { ...context, value: newValue, editing: false }; } return context; @@ -45,10 +47,10 @@ const TagInput = ({ unique = true, values = [], ...props }) => { }); }; - const editTag = (valueToEdit) => { + const editTag = (index) => { setValueContext((prevContext) => { - return prevContext.map((context) => { - if (context.value === valueToEdit) { + return prevContext.map((context, i) => { + if (i === index) { return { ...context, editing: true }; } return { ...context, editing: false }; @@ -61,7 +63,7 @@ const TagInput = ({ unique = true, values = [], ...props }) => {
  • editTag(context.value)}> + onClick={() => editTag(index)}> {context.value}
  • @@ -73,7 +75,7 @@ const TagInput = ({ unique = true, values = [], ...props }) => { handleInputKeyDown(evt, context.value)} + onKeyDown={(evt) => handleInputKeyDown({evt, value: context.value, index: index})} autoFocus /> ); @@ -87,12 +89,14 @@ const TagInput = ({ unique = true, values = [], ...props }) => { {valueContext.map((context, index) => { return context.editing ? renderWriteTag(context, index) : renderReadTag(context, index); })} - setTemporaryValue(e.target.value)} - onKeyDown={(evt) =>handleInputKeyDown(evt, null, true)} /> + onKeyDown={(evt) => handleInputKeyDown({ evt, value: null, options: { clear: true } })} + />
    ); From 433f016c25a6c69dfd3ef30d5e58263a2a6348c7 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Thu, 19 Sep 2024 15:57:40 -0500 Subject: [PATCH 14/75] rename tag container class to unify with fields --- client/homebrew/editor/tagInput/tagInput.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 2c636b0c8..8161ffe51 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -84,7 +84,7 @@ const TagInput = ({ unique = true, values = [], ...props }) => { return (
    -
    +
      {valueContext.map((context, index) => { return context.editing ? renderWriteTag(context, index) : renderReadTag(context, index); })}
    From 5af45f16b0c5a08cb481151b643504a5806ad449 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Mon, 23 Sep 2024 14:54:24 -0500 Subject: [PATCH 15/75] remove tagInput-class This file was just the old StringArrayEditor that I kept around for easy reference. Can be deleted now. --- .../editor/tagInput/tagInput-class.jsx | 149 ------------------ 1 file changed, 149 deletions(-) delete mode 100644 client/homebrew/editor/tagInput/tagInput-class.jsx diff --git a/client/homebrew/editor/tagInput/tagInput-class.jsx b/client/homebrew/editor/tagInput/tagInput-class.jsx deleted file mode 100644 index 85b8c6a3f..000000000 --- a/client/homebrew/editor/tagInput/tagInput-class.jsx +++ /dev/null @@ -1,149 +0,0 @@ -const React = require('react'); -const createClass = require('create-react-class'); -const _ = require('lodash'); - -const TagInput = createClass({ - displayName : 'TagInput', - getDefaultProps : function() { - return { - label : '', - values : [], - valuePatterns : null, - validators : [], - placeholder : '', - notes : [], - unique : false, - cannotEdit : [], - onChange : ()=>{} - }; - }, - - getInitialState : function() { - return { - valueContext : !!this.props.values ? this.props.values.map((value)=>({ - value, - editing : false - })) : [], - temporaryValue : '', - updateValue : '' - }; - }, - - componentDidUpdate : function(prevProps) { - if(!_.eq(this.props.values, prevProps.values)) { - this.setState({ - valueContext : this.props.values ? this.props.values.map((newValue)=>({ - value : newValue, - editing : this.state.valueContext.find(({ value })=>value === newValue)?.editing || false - })) : [] - }); - } - }, - - handleChange : function(value) { - this.props.onChange({ - target : { - value - } - }); - }, - - addValue : function(value){ - this.handleChange(_.uniq([...this.props.values, value])); - this.setState({ - temporaryValue : '' - }); - }, - - removeValue : function(index){ - this.handleChange(this.props.values.filter((_, i)=>i !== index)); - }, - - updateValue : function(value, index){ - const valueContext = this.state.valueContext; - valueContext[index].value = value; - valueContext[index].editing = false; - this.handleChange(valueContext.map((context)=>context.value)); - this.setState({ valueContext, updateValue: '' }); - }, - - editValue : function(index){ - if(!!this.props.cannotEdit && this.props.cannotEdit.includes(this.props.values[index])) { - return; - } - const valueContext = this.state.valueContext.map((context, i)=>{ - context.editing = index === i; - return context; - }); - this.setState({ valueContext, updateValue: this.props.values[index] }); - }, - - valueIsValid : function(value, index) { - const values = _.clone(this.props.values); - if(index !== undefined) { - values.splice(index, 1); - } - const matchesPatterns = !this.props.valuePatterns || this.props.valuePatterns.some((pattern)=>!!(value || '').match(pattern)); - const uniqueIfSet = !this.props.unique || !values.includes(value); - const passesValidators = !this.props.validators || this.props.validators.every((validator)=>validator(value)); - return matchesPatterns && uniqueIfSet && passesValidators; - }, - - handleValueInputKeyDown : function(event, index) { - if(event.key === 'Enter') { - if(this.valueIsValid(event.target.value, index)) { - if(index !== undefined) { - this.updateValue(event.target.value, index); - } else { - this.addValue(event.target.value); - } - } - } else if(event.key === 'Escape') { - this.closeEditInput(index); - } - }, - - closeEditInput : function(index) { - const valueContext = this.state.valueContext; - valueContext[index].editing = false; - this.setState({ valueContext, updateValue: '' }); - }, - - render : function() { - const valueElements = Object.values(this.state.valueContext).map((context, i)=>context.editing - ? -
    - this.handleValueInputKeyDown(e, i)} - onChange={(e)=>this.setState({ updateValue: e.target.value })}/> - {
    { e.stopPropagation(); this.closeEditInput(i); }}>
    } - {this.valueIsValid(this.state.updateValue, i) ?
    { e.stopPropagation(); this.updateValue(this.state.updateValue, i); }}>
    : null} -
    -
    - :
    this.editValue(i)}>{context.value} - {!!this.props.cannotEdit && this.props.cannotEdit.includes(context.value) ? null :
    { e.stopPropagation(); this.removeValue(i); }}>
    } -
    - ); - - return
    - -
    -
    - {valueElements} -
    - this.handleValueInputKeyDown(e)} - onChange={(e)=>this.setState({ temporaryValue: e.target.value })}/> - {this.valueIsValid(this.state.temporaryValue) ?
    { e.stopPropagation(); this.addValue(this.state.temporaryValue); }}>
    : null} -
    -
    - - {this.props.notes ? this.props.notes.map((n, index)=>

    {n}

    ) : null} -
    -
    ; - } -}); - -module.exports = TagInput; \ No newline at end of file From a96ff6ecb3a6c40fd223091ee4d99dc477b1dc05 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Mon, 23 Sep 2024 21:05:37 -0500 Subject: [PATCH 16/75] Variable name changes for clarity Followed suggestions on the PR. --- client/homebrew/editor/tagInput/tagInput.jsx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/client/homebrew/editor/tagInput/tagInput.jsx b/client/homebrew/editor/tagInput/tagInput.jsx index 8161ffe51..816541167 100644 --- a/client/homebrew/editor/tagInput/tagInput.jsx +++ b/client/homebrew/editor/tagInput/tagInput.jsx @@ -4,12 +4,12 @@ const { useState, useEffect } = React; const _ = require('lodash'); const TagInput = ({ unique = true, values = [], ...props }) => { - const [temporaryValue, setTemporaryValue] = useState(''); - const [valueContext, setValueContext] = useState(values.map((value) => ({ value, editing: false }))); + const [tempInputText, setTempInputText] = useState(''); + const [tagList, setTagList] = useState(values.map((value) => ({ value, editing: false }))); useEffect(()=>{ - handleChange(valueContext.map((context)=>context.value)) - }, [valueContext]) + handleChange(tagList.map((context)=>context.value)) + }, [tagList]) const handleChange = (value)=>{ props.onChange({ @@ -22,13 +22,13 @@ const TagInput = ({ unique = true, values = [], ...props }) => { evt.preventDefault(); submitTag(evt.target.value, value, index); if (options.clear) { - setTemporaryValue(''); + setTempInputText(''); } } }; const submitTag = (newValue, originalValue, index) => { - setValueContext((prevContext) => { + setTagList((prevContext) => { // remove existing tag if(newValue === null){ return [...prevContext].filter((context, i)=>i !== index); @@ -48,7 +48,7 @@ const TagInput = ({ unique = true, values = [], ...props }) => { }; const editTag = (index) => { - setValueContext((prevContext) => { + setTagList((prevContext) => { return prevContext.map((context, i) => { if (i === index) { return { ...context, editing: true }; @@ -86,15 +86,15 @@ const TagInput = ({ unique = true, values = [], ...props }) => {
      - {valueContext.map((context, index) => { return context.editing ? renderWriteTag(context, index) : renderReadTag(context, index); })} + {tagList.map((context, index) => { return context.editing ? renderWriteTag(context, index) : renderReadTag(context, index); })}
    setTemporaryValue(e.target.value)} + value={tempInputText} + onChange={(e) => setTempInputText(e.target.value)} onKeyDown={(evt) => handleInputKeyDown({ evt, value: null, options: { clear: true } })} />
    From ccafee7a217467181e8c6d61b8e62fc6c9a11696 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 13 Oct 2024 13:44:33 +1300 Subject: [PATCH 17/75] Get text from textBin in brew object --- server/admin.api.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index 0ec6a9c88..37aef9f16 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -76,8 +76,12 @@ router.get('/admin/lookup/:id', mw.adminOnly, async (req, res, next)=>{ .then((brew)=>{ if(!brew) // No document found return res.status(404).json({ error: 'Document not found' }); - else + else { + if(!brew.text && brew.textBin){ + brew.text = zlib.inflateRawSync(brew.textBin); + } return res.json(brew); + } }) .catch((err)=>{ console.error(err); From 6bc865144a1f89d96081613b12e1015d90e5df22 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 13 Oct 2024 13:45:11 +1300 Subject: [PATCH 18/75] Add cleaning function to API --- server/admin.api.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/server/admin.api.js b/server/admin.api.js index 37aef9f16..534646efc 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -104,6 +104,37 @@ router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{ }); }); +/* Cleans `` from the "text" field of a brew */ +router.put('/admin/clean/script/:id', (req, res)=>{ + console.log(`[ADMIN] Cleaning script tags from ShareID ${req.params.id}`); + + function cleanText(text){return text.replaceAll(/(<\/?s)cript/gi, '');}; + + HomebrewModel.findOne({ shareId: req.params.id }) + .then((brew)=>{ + if(!brew) + return res.status(404).send('Brew not found'); + + if(!brew.text && brew.textBin) { + brew.text = zlib.inflateRawSync(brew.textBin); + } + + const properties = ['text', 'description', 'title']; + properties.forEach((property)=>{ + brew[property] = cleanText(brew[property]); + }); + + brew.textBin = zlib.deflateRawSync(brew.text); + brew.text = undefined; + + return brew.save(); + }) + .then((obj)=>res.status(200).send(obj)) + .catch((err)=>{ + console.error(err); + res.status(500).send('Error while saving'); + }); +}); /* Compresses the "text" field of a brew to binary */ router.put('/admin/compress/:id', (req, res)=>{ From 63f4104f816be59e0335b84d002086b7897c2eda Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 13 Oct 2024 13:45:24 +1300 Subject: [PATCH 19/75] Add UI to Admin page --- .../admin/brewUtils/brewLookup/brewLookup.jsx | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index 50a2f2015..180e46b72 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -12,17 +12,18 @@ const BrewLookup = createClass({ }, getInitialState() { return { - query : '', - foundBrew : null, - searching : false, - error : null + query : '', + foundBrew : null, + searching : false, + error : null, + checkForScript : false }; }, handleChange(e){ this.setState({ query: e.target.value }); }, lookup(){ - this.setState({ searching: true, error: null }); + this.setState({ searching: true, error: null, checkForScript: false }); request.get(`/admin/lookup/${this.state.query}`) .then((res)=>this.setState({ foundBrew: res.body })) @@ -30,6 +31,23 @@ const BrewLookup = createClass({ .finally(()=>this.setState({ searching: false })); }, + checkForScript(){ + const brew = this.state.foundBrew; + const scriptCheck = brew.text.match(/(<\/?s)cript/); + this.setState({ + checkForScript : !!scriptCheck + }); + }, + + cleanScript(){ + if(!this.state.foundBrew?.shareId) return; + + request.put(`/admin/clean/script/${this.state.foundBrew.shareId}`) + .then((res)=>this.setState({ foundBrew: res.body })) + .catch((err)=>this.setState({ error: err })) + .finally(()=>this.setState({ checkForScript: false })); + }, + renderFoundBrew(){ const brew = this.state.foundBrew; return
    @@ -52,6 +70,8 @@ const BrewLookup = createClass({
    Num of Views
    {brew.views}
    + + {this.state.checkForScript && }
    ; }, From d3cc5c890ba95a050d7b51cf9c6cf3eb69bb179a Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 24 Oct 2024 17:20:55 +1300 Subject: [PATCH 20/75] Display number of SCRIPT tags detected in brew --- client/admin/brewUtils/brewLookup/brewLookup.jsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index 180e46b72..fa5784501 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -16,14 +16,15 @@ const BrewLookup = createClass({ foundBrew : null, searching : false, error : null, - checkForScript : false + checkForScript : false, + scriptCount : undefined }; }, handleChange(e){ this.setState({ query: e.target.value }); }, lookup(){ - this.setState({ searching: true, error: null, checkForScript: false }); + this.setState({ searching: true, error: null, checkForScript: false, scriptCount: undefined }); request.get(`/admin/lookup/${this.state.query}`) .then((res)=>this.setState({ foundBrew: res.body })) @@ -35,7 +36,8 @@ const BrewLookup = createClass({ const brew = this.state.foundBrew; const scriptCheck = brew.text.match(/(<\/?s)cript/); this.setState({ - checkForScript : !!scriptCheck + checkForScript : !!scriptCheck, + scriptCount : scriptCheck?.length || 0 }); }, @@ -45,7 +47,7 @@ const BrewLookup = createClass({ request.put(`/admin/clean/script/${this.state.foundBrew.shareId}`) .then((res)=>this.setState({ foundBrew: res.body })) .catch((err)=>this.setState({ error: err })) - .finally(()=>this.setState({ checkForScript: false })); + .finally(()=>this.setState({ checkForScript: false, scriptCount: 0 })); }, renderFoundBrew(){ @@ -71,6 +73,7 @@ const BrewLookup = createClass({
    {brew.views}
    + {(typeof this.state.scriptCount == 'number') &&

    Number of SCRIPT tags found: {this.state.scriptCount}

    } {this.state.checkForScript && }
    ; }, From db1fdca3ab57e30d244277cf8fea74b5487f10b7 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 24 Oct 2024 20:45:12 +1300 Subject: [PATCH 21/75] Automatically check for SCRIPT tags --- .../admin/brewUtils/brewLookup/brewLookup.jsx | 38 ++++++++++++------- .../brewUtils/brewLookup/brewLookup.less | 6 +++ 2 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 client/admin/brewUtils/brewLookup/brewLookup.less diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index fa5784501..922613559 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -1,3 +1,5 @@ +require('./brewLookup.less'); + const React = require('react'); const createClass = require('create-react-class'); const cx = require('classnames'); @@ -27,18 +29,21 @@ const BrewLookup = createClass({ this.setState({ searching: true, error: null, checkForScript: false, scriptCount: undefined }); 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/); + this.setState({ + foundBrew : foundBrew, + scriptCount : scriptCheck?.length || 0, + checkForScript : scriptCheck?.length > 0 + }); + }) .catch((err)=>this.setState({ error: err })) - .finally(()=>this.setState({ searching: false })); - }, - - checkForScript(){ - const brew = this.state.foundBrew; - const scriptCheck = brew.text.match(/(<\/?s)cript/); - this.setState({ - checkForScript : !!scriptCheck, - scriptCount : scriptCheck?.length || 0 - }); + .finally(()=>{ + this.setState({ + searching : false + }); + }); }, cleanScript(){ @@ -71,10 +76,15 @@ const BrewLookup = createClass({
    Num of Views
    {brew.views}
    + +
    Number of SCRIPT tags detected
    +
    {this.state.scriptCount}
    - - {(typeof this.state.scriptCount == 'number') &&

    Number of SCRIPT tags found: {this.state.scriptCount}

    } - {this.state.checkForScript && } + {this.state.checkForScript && +
    + +
    + }
    ; }, diff --git a/client/admin/brewUtils/brewLookup/brewLookup.less b/client/admin/brewUtils/brewLookup/brewLookup.less new file mode 100644 index 000000000..da15e3a64 --- /dev/null +++ b/client/admin/brewUtils/brewLookup/brewLookup.less @@ -0,0 +1,6 @@ +.brewLookup { + .cleanButton { + display : inline-block; + width : 100%; + } +} \ No newline at end of file From e3619bb1fc29d261753f6e01f87df0538703a0eb Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Fri, 25 Oct 2024 00:11:02 +1300 Subject: [PATCH 22/75] Add global flag to regex --- client/admin/brewUtils/brewLookup/brewLookup.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index 922613559..8814e465a 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -31,7 +31,7 @@ const BrewLookup = createClass({ request.get(`/admin/lookup/${this.state.query}`) .then((res)=>{ const foundBrew = res.body; - const scriptCheck = foundBrew.text.match(/(<\/?s)cript/); + const scriptCheck = foundBrew.text.match(/(<\/?s)cript/g); this.setState({ foundBrew : foundBrew, scriptCount : scriptCheck?.length || 0, From 28894adeabc3187fa4791091b28bb0c30f422f90 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Fri, 25 Oct 2024 11:17:44 +1300 Subject: [PATCH 23/75] Add error check for no brew found --- client/admin/brewUtils/brewLookup/brewLookup.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index 8814e465a..ab938854e 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -31,7 +31,7 @@ const BrewLookup = createClass({ request.get(`/admin/lookup/${this.state.query}`) .then((res)=>{ const foundBrew = res.body; - const scriptCheck = foundBrew.text.match(/(<\/?s)cript/g); + const scriptCheck = foundBrew?.text.match(/(<\/?s)cript/g); this.setState({ foundBrew : foundBrew, scriptCount : scriptCheck?.length || 0, From 948f03b5b86bc9c8cc3fbdf1b2fc07726dbfb394 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Fri, 25 Oct 2024 11:18:36 +1300 Subject: [PATCH 24/75] Add admin access type to getBrew --- server/homebrew.api.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 213b341ca..c6c9ab0f8 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -87,8 +87,18 @@ const api = { // Get relevant IDs for the brew const { id, googleId } = api.getId(req); + const accessMap = { + edit : { editId: id }, + share : { shareId: id }, + admin : { + $or : [ + { editId: { $regex: req.params.id, $options: 'i' } }, + { shareId: { $regex: req.params.id, $options: 'i' } }, + ] } + }; + // 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)=>{ if(googleId) { console.warn(`Unable to find document stub for ${accessType}Id ${id}`); From ac2de613c5d0e23947b2f4266868428ae517f848 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Fri, 25 Oct 2024 11:19:55 +1300 Subject: [PATCH 25/75] Change Admin lookup to use Homebrew.API getBrew instead --- server/admin.api.js | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 11e336c22..3d1688129 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -5,6 +5,9 @@ const Moment = require('moment'); const templateFn = require('../client/template.js'); const zlib = require('zlib'); +const HomebrewAPI = require('./homebrew.api.js'); +const asyncHandler = require('express-async-handler'); + process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin'; process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3'; @@ -66,27 +69,19 @@ router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{ }); /* Searches for matching edit or share id, also attempts to partial match */ -router.get('/admin/lookup/:id', mw.adminOnly, async (req, res, next)=>{ - HomebrewModel.findOne({ - $or : [ - { editId: { $regex: req.params.id, $options: 'i' } }, - { shareId: { $regex: req.params.id, $options: 'i' } }, - ] - }).exec() - .then((brew)=>{ - if(!brew) // No document found +router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', true)), async (req, res, next)=>{ + const brew = req?.brew ?? undefined; + + try { + if(!brew){ + // No document found return res.status(404).json({ error: 'Document not found' }); - else { - if(!brew.text && brew.textBin){ - brew.text = zlib.inflateRawSync(brew.textBin); - } - return res.json(brew); } - }) - .catch((err)=>{ + 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 */ @@ -179,7 +174,7 @@ router.get('/admin/notification/all', async (req, res, next)=>{ try { const notifications = await NotificationModel.getAll(); return res.json(notifications); - + } catch (error) { console.log('Error getting all notifications: ', error.message); return res.status(500).json({ message: error.message }); From 63f6f6d3c6e733317e03530692309e9009f033c5 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Fri, 25 Oct 2024 11:27:28 +1300 Subject: [PATCH 26/75] Fix new getBrew access type --- server/homebrew.api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index c6c9ab0f8..cd44c0e13 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -92,8 +92,8 @@ const api = { share : { shareId: id }, admin : { $or : [ - { editId: { $regex: req.params.id, $options: 'i' } }, - { shareId: { $regex: req.params.id, $options: 'i' } }, + { editId: { $regex: id, $options: 'i' } }, + { shareId: { $regex: id, $options: 'i' } }, ] } }; From 898be28af3c6753dd4234653d85eedfbad1eebe4 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Fri, 25 Oct 2024 11:40:17 +1300 Subject: [PATCH 27/75] Fix Homebrew API parameter --- server/admin.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/admin.api.js b/server/admin.api.js index 3d1688129..4a1569950 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -69,7 +69,7 @@ router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{ }); /* Searches for matching edit or share id, also attempts to partial match */ -router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', true)), async (req, res, next)=>{ +router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res, next)=>{ const brew = req?.brew ?? undefined; try { From fea8f157a7d41b88447a574da1aa404e01883e83 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Fri, 25 Oct 2024 17:45:12 +1300 Subject: [PATCH 28/75] Change script clean to use Homebrew API update --- server/admin.api.js | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 4a1569950..e0ff2131c 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -7,6 +7,7 @@ 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_PASS = process.env.ADMIN_PASS || 'password3'; @@ -100,35 +101,25 @@ router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{ }); /* Cleans `` from the "text" field of a brew */ -router.put('/admin/clean/script/:id', (req, res)=>{ +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, '');}; - HomebrewModel.findOne({ shareId: req.params.id }) - .then((brew)=>{ - if(!brew) - return res.status(404).send('Brew not found'); + const brew = req.brew; - if(!brew.text && brew.textBin) { - brew.text = zlib.inflateRawSync(brew.textBin); - } + const properties = ['text', 'description', 'title']; + properties.forEach((property)=>{ + brew[property] = cleanText(brew[property]); + }); + // Tag cleaning is commented out as it is impossible to enter a script tag in tags + // brew.tags = cleanText(brew.tags.join('\n')).split('\n'); - const properties = ['text', 'description', 'title']; - properties.forEach((property)=>{ - brew[property] = cleanText(brew[property]); - }); + splitTextStyleAndMetadata(brew); - brew.textBin = zlib.deflateRawSync(brew.text); - brew.text = undefined; + req.body = brew; - return brew.save(); - }) - .then((obj)=>res.status(200).send(obj)) - .catch((err)=>{ - console.error(err); - res.status(500).send('Error while saving'); - }); + return await HomebrewAPI.updateBrew(req, res); }); /* Compresses the "text" field of a brew to binary */ From db75e0dd6678df5b71b435fc7b0f0d6e72e04466 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 03:25:59 +0000 Subject: [PATCH 29/75] Bump elliptic from 6.5.7 to 6.6.0 Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.7 to 6.6.0. - [Commits](https://github.com/indutny/elliptic/compare/v6.5.7...v6.6.0) --- updated-dependencies: - dependency-name: elliptic dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e07efc07..7602cee69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5400,9 +5400,9 @@ "integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==" }, "node_modules/elliptic": { - "version": "6.5.7", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", - "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz", + "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", From a29aca32e7eab4eb80aea9605ad2e2d8220754df Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Tue, 29 Oct 2024 20:42:53 +1300 Subject: [PATCH 30/75] Display createdAt time --- client/admin/brewUtils/brewLookup/brewLookup.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index ab938854e..234aaf78e 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -71,6 +71,9 @@ const BrewLookup = createClass({
    Share Link
    /share/{brew.shareId}
    +
    Created Time
    +
    {brew.createdAt ? Moment(brew.createdAt).toLocaleString() : 'No creation date'}
    +
    Last Updated
    {Moment(brew.updatedAt).fromNow()}
    From bd26f02ddb33fd55f634723136dba7ace3ca15e7 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 10 Nov 2024 19:23:42 +1300 Subject: [PATCH 31/75] Remove getBrew admin regex search --- server/homebrew.api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index cd44c0e13..65d4c8051 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -92,8 +92,8 @@ const api = { share : { shareId: id }, admin : { $or : [ - { editId: { $regex: id, $options: 'i' } }, - { shareId: { $regex: id, $options: 'i' } }, + { editId: id }, + { shareId: id }, ] } }; From 27f14b042b8b65b86dcccfb0ef091dcab859af5a Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 10 Nov 2024 19:24:54 +1300 Subject: [PATCH 32/75] Remove comment about irrelevant tag cleaning --- server/admin.api.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index e0ff2131c..9fa2f0a69 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -112,8 +112,6 @@ router.put('/admin/clean/script/:id', asyncHandler(HomebrewAPI.getBrew('admin', properties.forEach((property)=>{ brew[property] = cleanText(brew[property]); }); - // Tag cleaning is commented out as it is impossible to enter a script tag in tags - // brew.tags = cleanText(brew.tags.join('\n')).split('\n'); splitTextStyleAndMetadata(brew); From 952b67aed3be3aaf1b31f47563fc19f3f5dc57f5 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 10 Nov 2024 19:29:28 +1300 Subject: [PATCH 33/75] Remove checkForScript state --- .../admin/brewUtils/brewLookup/brewLookup.jsx | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index 234aaf78e..7b7fd1b2e 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -14,28 +14,26 @@ const BrewLookup = createClass({ }, getInitialState() { return { - query : '', - foundBrew : null, - searching : false, - error : null, - checkForScript : false, - scriptCount : undefined + query : '', + foundBrew : null, + searching : false, + error : null, + scriptCount : 0 }; }, handleChange(e){ this.setState({ query: e.target.value }); }, lookup(){ - this.setState({ searching: true, error: null, checkForScript: false, scriptCount: undefined }); + this.setState({ searching: true, error: null, scriptCount: 0 }); request.get(`/admin/lookup/${this.state.query}`) .then((res)=>{ const foundBrew = res.body; const scriptCheck = foundBrew?.text.match(/(<\/?s)cript/g); this.setState({ - foundBrew : foundBrew, - scriptCount : scriptCheck?.length || 0, - checkForScript : scriptCheck?.length > 0 + foundBrew : foundBrew, + scriptCount : scriptCheck?.length || 0, }); }) .catch((err)=>this.setState({ error: err })) @@ -52,7 +50,7 @@ const BrewLookup = createClass({ request.put(`/admin/clean/script/${this.state.foundBrew.shareId}`) .then((res)=>this.setState({ foundBrew: res.body })) .catch((err)=>this.setState({ error: err })) - .finally(()=>this.setState({ checkForScript: false, scriptCount: 0 })); + .finally(()=>this.setState({ scriptCount: 0 })); }, renderFoundBrew(){ @@ -83,7 +81,7 @@ const BrewLookup = createClass({
    Number of SCRIPT tags detected
    {this.state.scriptCount}
    - {this.state.checkForScript && + {this.state.scriptCount > 0 &&
    From b3793a33307b9738f2a714860bf2efff928b6b95 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 10 Nov 2024 19:30:57 +1300 Subject: [PATCH 34/75] Simplify scriptCount logic --- client/admin/brewUtils/brewLookup/brewLookup.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index 7b7fd1b2e..a4f462a0e 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -81,7 +81,7 @@ const BrewLookup = createClass({
    Number of SCRIPT tags detected
    {this.state.scriptCount}
    - {this.state.scriptCount > 0 && + {this.state.scriptCount &&
    From ee811e94e19404981735d13b32adb14607c9456a Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 10 Nov 2024 19:34:19 +1300 Subject: [PATCH 35/75] Remove error handling that can never trigger --- server/admin.api.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 9fa2f0a69..29e32d6dc 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -72,17 +72,7 @@ router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{ /* Searches for matching edit or share id, also attempts to partial match */ router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res, next)=>{ const brew = req?.brew ?? undefined; - - try { - if(!brew){ - // No document found - return res.status(404).json({ error: 'Document not found' }); - } - return res.json(brew); - } catch (err) { - console.error(err); - return res.status(500).json({ error: 'Internal Server Error' }); - } + return res.json(brew); }); /* Find 50 brews that aren't compressed yet */ From 033b7fa44ff14a84f7ab15b18acac3c4f37f4040 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 10 Nov 2024 19:35:57 +1300 Subject: [PATCH 36/75] Lint fix --- server/homebrew.api.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 65d4c8051..e156f3c85 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -305,9 +305,8 @@ const api = { req.params.id = currentTheme.theme; req.params.renderer = currentTheme.renderer; - } + } else { //=== Static Themes ===// - else { 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\");`; completeSnippets.push(localSnippets); From 2dafbf20802bc42a7b6abd5df2d835784f5df578 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 10 Nov 2024 20:19:30 +1300 Subject: [PATCH 37/75] Simplify Admin brew lookup function --- server/admin.api.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/admin.api.js b/server/admin.api.js index 29e32d6dc..bc179ff7b 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -71,8 +71,7 @@ router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{ /* Searches for matching edit or share id, also attempts to partial match */ router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res, next)=>{ - const brew = req?.brew ?? undefined; - return res.json(brew); + return res.json(req.brew); }); /* Find 50 brews that aren't compressed yet */ From dc1d40512b9c1aed90ee4b69dd464f214d5bc62f Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 10 Nov 2024 21:45:17 +1300 Subject: [PATCH 38/75] Reinstate length check --- client/admin/brewUtils/brewLookup/brewLookup.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index a4f462a0e..7b7fd1b2e 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -81,7 +81,7 @@ const BrewLookup = createClass({
    Number of SCRIPT tags detected
    {this.state.scriptCount}
    - {this.state.scriptCount && + {this.state.scriptCount > 0 &&
    From 9bc4b1fb5689abd4ca052f4501095f3f64abbd35 Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Thu, 31 Oct 2024 22:04:11 -0500 Subject: [PATCH 39/75] Changes to core.less, reset.less, and toolbar Making some changes to the reset.less so that some default UA button styling is removed. Then, changing core.less so that the classic "HB" button styling is scoped to a certain class `.colorButton`. This will make it easier to use the button element in other places. --- client/homebrew/brewRenderer/toolBar/toolBar.less | 8 +------- client/homebrew/editor/metadataEditor/metadataEditor.less | 7 ++++--- shared/naturalcrit/styles/core.less | 5 +---- shared/naturalcrit/styles/reset.less | 8 +++++++- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.less b/client/homebrew/brewRenderer/toolBar/toolBar.less index 381e5eeed..c2f4ff148 100644 --- a/client/homebrew/brewRenderer/toolBar/toolBar.less +++ b/client/homebrew/brewRenderer/toolBar/toolBar.less @@ -13,6 +13,7 @@ height : auto; padding : 2px 0; font-family : 'Open Sans', sans-serif; + font-size : 13px; color : #CCCCCC; background-color : #555555; & > *:not(.toggleButton) { @@ -154,13 +155,6 @@ width : auto; min-width : 46px; height : 100%; - padding : 0 0px; - font-weight : unset; - color : inherit; - background-color : unset; - - &:not(button:has(i, svg)) { padding : 0 8px; } - &:hover { background-color : #444444; } &:focus { border : 1px solid #D3D3D3;outline : none;} &:disabled { diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 62ec6b37b..d29916a50 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -79,6 +79,7 @@ text-overflow : ellipsis; } button { + .colorButton(); padding : 0px 5px; color : white; background-color : black; @@ -138,16 +139,16 @@ margin-bottom : 15px; button { width : 100%; } button.publish { - .button(@blueLight); + .colorButton(@blueLight); } button.unpublish { - .button(@silver); + .colorButton(@silver); } } .delete.field .value { button { - .button(@red); + .colorButton(@red); } } .authors.field .value { diff --git a/shared/naturalcrit/styles/core.less b/shared/naturalcrit/styles/core.less index c742ad7b1..21a2687bc 100644 --- a/shared/naturalcrit/styles/core.less +++ b/shared/naturalcrit/styles/core.less @@ -21,10 +21,7 @@ html,body, #reactRoot{ *{ box-sizing : border-box; } -button{ - .button(); -} -.button(@backgroundColor : @green){ +.colorButton(@backgroundColor : @green){ .animate(background-color); display : inline-block; padding : 0.6em 1.2em; diff --git a/shared/naturalcrit/styles/reset.less b/shared/naturalcrit/styles/reset.less index be5bffc7e..df5564a21 100644 --- a/shared/naturalcrit/styles/reset.less +++ b/shared/naturalcrit/styles/reset.less @@ -1,4 +1,4 @@ -:where(html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video){ +:where(html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,button,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video){ border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0 } @@ -25,3 +25,9 @@ :where(table){ border-collapse:collapse;border-spacing:0 } + +:where(button) { + background-color: unset; + text-transform: unset; + color: unset; +} From 4e4463fe4dc863fb54d55368acf296f618e45431 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 11 Nov 2024 11:17:00 -0600 Subject: [PATCH 40/75] Fix Issue 3718 by bounds checking prerender. --- client/homebrew/brewRenderer/brewRenderer.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 1c45269cf..4685775b9 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -161,7 +161,8 @@ const BrewRenderer = (props)=>{ renderedPages.length = 0; // 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)=>{ if((isInView(index) || !renderedPages[index]) && typeof window !== 'undefined'){ From 107aa34ee40fdbdad23970d17b500c5e1f9de4ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 03:12:02 +0000 Subject: [PATCH 41/75] Bump dompurify from 3.1.7 to 3.2.0 Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.1.7 to 3.2.0. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.1.7...3.2.0) --- updated-dependencies: - dependency-name: dompurify dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index ae99df672..bc3530f17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "cookie-parser": "^1.4.7", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", - "dompurify": "^3.1.7", + "dompurify": "^3.2.0", "expr-eval": "^2.0.2", "express": "^4.21.1", "express-async-handler": "^1.2.0", @@ -5455,9 +5455,9 @@ } }, "node_modules/dompurify": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz", - "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.0.tgz", + "integrity": "sha512-AMdOzK44oFWqHEi0wpOqix/fUNY707OmoeFDnbi3Q5I8uOpy21ufUA5cDJPr0bosxrflOVD/H2DMSvuGKJGfmQ==" }, "node_modules/duplexer2": { "version": "0.1.4", diff --git a/package.json b/package.json index a48423f50..f31fed0f5 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "cookie-parser": "^1.4.7", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", - "dompurify": "^3.1.7", + "dompurify": "^3.2.0", "expr-eval": "^2.0.2", "express": "^4.21.1", "express-async-handler": "^1.2.0", From 8c6c8f861d31f3fe910f7f82a01be9538b6cc935 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 12 Nov 2024 00:08:56 -0500 Subject: [PATCH 42/75] Automatically re-check for scripts Adding a separate `keepText` field for the `updateBrew()` API might be a bandaid for something that should be looked at more deeply as a separate refactor, considering `updateBrew()` is configured to just return the stub and not the whole document. For now, re-scanning for script tags after updating can be as simple as just re-looking up the brew. --- client/admin/brewUtils/brewLookup/brewLookup.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index 7b7fd1b2e..80f08fcf8 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -44,13 +44,13 @@ const BrewLookup = createClass({ }); }, - cleanScript(){ + async cleanScript(){ if(!this.state.foundBrew?.shareId) return; - request.put(`/admin/clean/script/${this.state.foundBrew.shareId}`) - .then((res)=>this.setState({ foundBrew: res.body })) - .catch((err)=>this.setState({ error: err })) - .finally(()=>this.setState({ scriptCount: 0 })); + await request.put(`/admin/clean/script/${this.state.foundBrew.shareId}`) + .catch((err)=>{ this.setState({ error: err }); return; }); + + this.lookup(); }, renderFoundBrew(){ From 2e9c7b1d9b7a212337330f66e9fada792d4c1f86 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 12 Nov 2024 00:20:37 -0500 Subject: [PATCH 43/75] Shorten label --- client/admin/brewUtils/brewLookup/brewLookup.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx index 80f08fcf8..e5b585ced 100644 --- a/client/admin/brewUtils/brewLookup/brewLookup.jsx +++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx @@ -78,7 +78,7 @@ const BrewLookup = createClass({
    Num of Views
    {brew.views}
    -
    Number of SCRIPT tags detected
    +
    SCRIPT tags detected
    {this.state.scriptCount}
    {this.state.scriptCount > 0 && From 0d2dfe66bcc85e9b1a9ad3e9e0537248da49fef3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 05:36:16 +0000 Subject: [PATCH 44/75] Bump mongoose from 8.7.3 to 8.8.1 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.7.3 to 8.8.1. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.7.3...8.8.1) --- updated-dependencies: - dependency-name: mongoose dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 22 +++++++++++----------- package.json | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc3530f17..1d1d86534 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.7.3", + "mongoose": "^8.8.1", "nanoid": "3.3.4", "nconf": "^0.12.1", "react": "^18.3.1", @@ -4327,9 +4327,9 @@ } }, "node_modules/bson": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", - "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.9.0.tgz", + "integrity": "sha512-X9hJeyeM0//Fus+0pc5dSUMhhrrmWwQUtdavaQeF3Ta6m69matZkGWV/MrBcnwUeLC8W9kwwc2hfkZgUuCX3Ig==", "engines": { "node": ">=16.20.1" } @@ -10865,13 +10865,13 @@ } }, "node_modules/mongoose": { - "version": "8.7.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.7.3.tgz", - "integrity": "sha512-Xl6+dzU5ZpEcDoJ8/AyrIdAwTY099QwpolvV73PIytpK13XqwllLq/9XeVzzLEQgmyvwBVGVgjmMrKbuezxrIA==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.1.tgz", + "integrity": "sha512-l7DgeY1szT98+EKU8GYnga5WnyatAu+kOQ2VlVX1Mxif6A0Umt0YkSiksCiyGxzx8SPhGe9a53ND1GD4yVDrPA==", "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", - "mongodb": "6.9.0", + "mongodb": "~6.10.0", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", @@ -10943,9 +10943,9 @@ } }, "node_modules/mongoose/node_modules/mongodb": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz", - "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.10.0.tgz", + "integrity": "sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==", "dependencies": { "@mongodb-js/saslprep": "^1.1.5", "bson": "^6.7.0", diff --git a/package.json b/package.json index f31fed0f5..529745eef 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.7.3", + "mongoose": "^8.8.1", "nanoid": "3.3.4", "nconf": "^0.12.1", "react": "^18.3.1", From b22f3d041c403e13823f6dc2111619ecd00a93f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:15:31 +0000 Subject: [PATCH 45/75] Bump express-static-gzip from 2.1.8 to 2.2.0 Bumps [express-static-gzip](https://github.com/tkoenig89/express-static-gzip) from 2.1.8 to 2.2.0. - [Release notes](https://github.com/tkoenig89/express-static-gzip/releases) - [Commits](https://github.com/tkoenig89/express-static-gzip/compare/v2.1.8...v2.2.0) --- updated-dependencies: - dependency-name: express-static-gzip dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1d1d86534..897967a5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "expr-eval": "^2.0.2", "express": "^4.21.1", "express-async-handler": "^1.2.0", - "express-static-gzip": "2.1.8", + "express-static-gzip": "2.2.0", "fs-extra": "11.2.0", "idb-keyval": "^6.2.1", "js-yaml": "^4.1.0", @@ -6290,10 +6290,11 @@ "license": "MIT" }, "node_modules/express-static-gzip": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/express-static-gzip/-/express-static-gzip-2.1.8.tgz", - "integrity": "sha512-g8tiJuI9Y9Ffy59ehVXvqb0hhP83JwZiLxzanobPaMbkB5qBWA8nuVgd+rcd5qzH3GkgogTALlc0BaADYwnMbQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/express-static-gzip/-/express-static-gzip-2.2.0.tgz", + "integrity": "sha512-4ZQ0pHX0CAauxmzry2/8XFLM6aZA4NBvg9QezSlsEO1zLnl7vMFa48/WIcjzdfOiEUS4S1npPPKP2NHHYAp6qg==", "dependencies": { + "parseurl": "^1.3.3", "serve-static": "^1.16.2" } }, diff --git a/package.json b/package.json index 529745eef..ab4ceffba 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "expr-eval": "^2.0.2", "express": "^4.21.1", "express-async-handler": "^1.2.0", - "express-static-gzip": "2.1.8", + "express-static-gzip": "2.2.0", "fs-extra": "11.2.0", "idb-keyval": "^6.2.1", "js-yaml": "^4.1.0", From f749706cb3661021cacb3bbc471ae1c878cb5171 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:15:37 +0000 Subject: [PATCH 46/75] Bump marked-emoji from 1.4.2 to 1.4.3 Bumps [marked-emoji](https://github.com/UziTech/marked-emoji) from 1.4.2 to 1.4.3. - [Release notes](https://github.com/UziTech/marked-emoji/releases) - [Changelog](https://github.com/UziTech/marked-emoji/blob/main/release.config.cjs) - [Commits](https://github.com/UziTech/marked-emoji/compare/v1.4.2...v1.4.3) --- updated-dependencies: - dependency-name: marked-emoji dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1d1d86534..8b94d5cbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "less": "^3.13.1", "lodash": "^4.17.21", "marked": "11.2.0", - "marked-emoji": "^1.4.2", + "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.0.10", "marked-gfm-heading-id": "^3.2.0", "marked-smartypants-lite": "^1.0.2", @@ -10487,11 +10487,11 @@ } }, "node_modules/marked-emoji": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-1.4.2.tgz", - "integrity": "sha512-2sP+bp2z76dwbILzQ7ijy2PyjjAJR3iAZCzaNGThD2UijFUBeidkn6MoCdX/j47tPIcWt9nwnjqRQPd01ZrfdA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-1.4.3.tgz", + "integrity": "sha512-HDZx1VOmzu7XT2QNKWfrHGbNRMTWKj9XD78yrcH1madD30HpGLMODPOmKr/e7CA7NKKXkpXXNdndQn++ysXmHg==", "peerDependencies": { - "marked": ">=4 <15" + "marked": ">=4 <16" } }, "node_modules/marked-extended-tables": { diff --git a/package.json b/package.json index 529745eef..473d1398d 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "less": "^3.13.1", "lodash": "^4.17.21", "marked": "11.2.0", - "marked-emoji": "^1.4.2", + "marked-emoji": "^1.4.3", "marked-extended-tables": "^1.0.10", "marked-gfm-heading-id": "^3.2.0", "marked-smartypants-lite": "^1.0.2", From b857a91ab8009430386ead3afff41a537a1e37d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 03:21:50 +0000 Subject: [PATCH 47/75] Bump mongoose from 8.8.1 to 8.8.2 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.1 to 8.8.2. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.8.1...8.8.2) --- updated-dependencies: - dependency-name: mongoose dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a9b64c1d7..e5a0557a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.8.1", + "mongoose": "^8.8.2", "nanoid": "3.3.4", "nconf": "^0.12.1", "react": "^18.3.1", @@ -10866,9 +10866,9 @@ } }, "node_modules/mongoose": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.1.tgz", - "integrity": "sha512-l7DgeY1szT98+EKU8GYnga5WnyatAu+kOQ2VlVX1Mxif6A0Umt0YkSiksCiyGxzx8SPhGe9a53ND1GD4yVDrPA==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.2.tgz", + "integrity": "sha512-jCTSqDANfRzk909v4YoZQi7jlGRB2MTvgG+spVBc/BA4tOs1oWJr//V6yYujqNq9UybpOtsSfBqxI0dSOEFJHQ==", "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", diff --git a/package.json b/package.json index 08473ca05..5e65641a2 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.8.1", + "mongoose": "^8.8.2", "nanoid": "3.3.4", "nconf": "^0.12.1", "react": "^18.3.1", From fb9148ada5077028a4766ec6b986c23903a8ae10 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 20 Nov 2024 16:21:35 -0500 Subject: [PATCH 48/75] Site runs and all tests pass --- client/homebrew/brewRenderer/brewRenderer.jsx | 2 +- .../notificationPopup/notificationPopup.jsx | 2 +- client/homebrew/editor/editor.jsx | 2 +- .../editor/metadataEditor/metadataEditor.jsx | 2 +- .../basePages/listPage/brewItem/brewItem.jsx | 2 +- client/homebrew/pages/editPage/editPage.jsx | 4 +- client/homebrew/pages/errorPage/errorPage.jsx | 2 +- client/homebrew/pages/homePage/homePage.jsx | 2 +- client/homebrew/pages/newPage/newPage.jsx | 4 +- client/homebrew/pages/vaultPage/vaultPage.jsx | 2 +- client/homebrew/utils/request-middleware.js | 4 +- client/template.js | 6 +- package-lock.json | 24 ++++++ package.json | 6 +- scripts/buildHomebrew.js | 29 ++++---- server.js | 8 +- server/admin.api.js | 22 +++--- server/admin.api.spec.js | 9 ++- server/app.js | 73 +++++++++++-------- server/brewDefaults.js | 4 +- server/config.js | 12 +-- server/db.js | 8 +- server/forcessl.mw.js | 2 +- server/googleActions.js | 13 ++-- server/homebrew.api.js | 30 ++++---- server/homebrew.api.spec.js | 7 +- server/homebrew.model.js | 17 +++-- server/middleware/check-client-version.js | 6 +- server/middleware/content-negotiation.js | 4 +- server/middleware/content-negotiation.spec.js | 41 ----------- server/notifications.model.js | 10 +-- server/static-assets.mv.js | 4 +- server/token.js | 10 +-- server/vault.api.js | 8 +- shared/helpers.js | 8 +- shared/naturalcrit/markdown.js | 30 ++++---- tests/markdown/basic.test.js | 2 +- tests/markdown/definition-lists.test.js | 2 +- tests/markdown/emojis.test.js | 2 +- tests/markdown/hard-breaks.test.js | 2 +- tests/markdown/mustache-syntax.test.js | 2 +- tests/markdown/variables.test.js | 2 +- tests/routes/static-pages.test.js | 6 +- themes/V3/Blank/snippets/footer.gen.js | 2 +- themes/fonts/iconFonts/diceFont.js | 2 +- themes/fonts/iconFonts/elderberryInn.js | 2 +- themes/fonts/iconFonts/fontAwesome.js | 2 +- themes/fonts/iconFonts/gameIcons.js | 2 +- 48 files changed, 230 insertions(+), 217 deletions(-) delete mode 100644 server/middleware/content-negotiation.spec.js diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 4685775b9..36d263040 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -5,7 +5,7 @@ const { useState, useRef, useCallback, useMemo } = React; const _ = require('lodash'); const MarkdownLegacy = require('naturalcrit/markdownLegacy.js'); -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; const ErrorBar = require('./errorBar/errorBar.jsx'); const ToolBar = require('./toolBar/toolBar.jsx'); diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx index 3ea165d62..0c8fc4b8c 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.jsx @@ -1,6 +1,6 @@ require('./notificationPopup.less'); import React, { useEffect, useState } from 'react'; -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; import Dialog from '../../../components/dialog.jsx'; diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 9fef72cbb..bba5f3ad9 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -4,7 +4,7 @@ const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); const dedent = require('dedent-tabs').default; -const Markdown = require('../../../shared/naturalcrit/markdown.js'); +import Markdown from '../../../shared/naturalcrit/markdown.js'; const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx'); const SnippetBar = require('./snippetbar/snippetbar.jsx'); diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 0e06b2c72..bfc3b8b61 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -3,7 +3,7 @@ require('./metadataEditor.less'); const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; const Nav = require('naturalcrit/nav/nav.jsx'); const Combobox = require('client/components/combobox.jsx'); const TagInput = require('../tagInput/tagInput.jsx'); diff --git a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx index 039bc98f5..9011564a3 100644 --- a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx +++ b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.jsx @@ -2,7 +2,7 @@ require('./brewItem.less'); const React = require('react'); const createClass = require('create-react-class'); const moment = require('moment'); -const request = require('../../../../utils/request-middleware.js'); +import request from '../../../../utils/request-middleware.js'; const googleDriveIcon = require('../../../../googleDrive.svg'); const homebreweryIcon = require('../../../../thumbnail.png'); diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 7ddf0bb06..889fd58c5 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -4,7 +4,7 @@ const React = require('react'); const _ = require('lodash'); const createClass = require('create-react-class'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; const { Meta } = require('vitreum/headtags'); const Nav = require('naturalcrit/nav/nav.jsx'); @@ -23,7 +23,7 @@ const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); const LockNotification = require('./lockNotification/lockNotification.jsx'); -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js'); const { printCurrentBrew, fetchThemeBundle } = require('../../../../shared/helpers.js'); diff --git a/client/homebrew/pages/errorPage/errorPage.jsx b/client/homebrew/pages/errorPage/errorPage.jsx index 387a99b02..4ac73da8c 100644 --- a/client/homebrew/pages/errorPage/errorPage.jsx +++ b/client/homebrew/pages/errorPage/errorPage.jsx @@ -1,7 +1,7 @@ require('./errorPage.less'); const React = require('react'); const UIPage = require('../basePages/uiPage/uiPage.jsx'); -const Markdown = require('../../../../shared/naturalcrit/markdown.js'); +import Markdown from '../../../../shared/naturalcrit/markdown.js'; const ErrorIndex = require('./errors/errorIndex.js'); const ErrorPage = ({ brew })=>{ diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index f737506f1..00d0c801d 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -2,7 +2,7 @@ require('./homePage.less'); const React = require('react'); const createClass = require('create-react-class'); const cx = require('classnames'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; const { Meta } = require('vitreum/headtags'); const Nav = require('naturalcrit/nav/nav.jsx'); diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 8216b347c..ee2c67d5f 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -2,9 +2,9 @@ require('./newPage.less'); const React = require('react'); const createClass = require('create-react-class'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; const Nav = require('naturalcrit/nav/nav.jsx'); const PrintNavItem = require('../../navbar/print.navitem.jsx'); diff --git a/client/homebrew/pages/vaultPage/vaultPage.jsx b/client/homebrew/pages/vaultPage/vaultPage.jsx index fbf15f814..21a8e8363 100644 --- a/client/homebrew/pages/vaultPage/vaultPage.jsx +++ b/client/homebrew/pages/vaultPage/vaultPage.jsx @@ -15,7 +15,7 @@ const BrewItem = require('../basePages/listPage/brewItem/brewItem.jsx'); const SplitPane = require('../../../../shared/naturalcrit/splitPane/splitPane.jsx'); const ErrorIndex = require('../errorPage/errors/errorIndex.js'); -const request = require('../../utils/request-middleware.js'); +import request from '../../utils/request-middleware.js'; const VaultPage = (props)=>{ const [pageState, setPageState] = useState(parseInt(props.query.page) || 1); diff --git a/client/homebrew/utils/request-middleware.js b/client/homebrew/utils/request-middleware.js index f6bc2571b..01a9d2571 100644 --- a/client/homebrew/utils/request-middleware.js +++ b/client/homebrew/utils/request-middleware.js @@ -1,4 +1,4 @@ -const request = require('superagent'); +import request from 'superagent'; const addHeader = (request)=>request.set('Homebrewery-Version', global.version); @@ -9,4 +9,4 @@ const requestMiddleware = { delete : (path)=>addHeader(request.delete(path)), }; -module.exports = requestMiddleware; \ No newline at end of file +export default requestMiddleware; \ No newline at end of file diff --git a/client/template.js b/client/template.js index c77f953ff..990df785c 100644 --- a/client/template.js +++ b/client/template.js @@ -8,6 +8,8 @@ const template = async function(name, title='', props = {}){ }); const ogMetaTags = ogTags.join('\n'); + const ssrModule = await import(`../build/${name}/ssr.cjs`); + return ` @@ -21,7 +23,7 @@ const template = async function(name, title='', props = {}){ ${title.length ? `${title} - The Homebrewery`: 'The Homebrewery - NaturalCrit'} -
    ${require(`../build/${name}/ssr.js`)(props)}
    +
    ${ssrModule.default(props)}
    @@ -29,4 +31,4 @@ const template = async function(name, title='', props = {}){ `; }; -module.exports = template; \ No newline at end of file +export default template; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a9b64c1d7..03f892206 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "license": "MIT", "dependencies": { "@babel/core": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.25.9", @@ -52,6 +53,7 @@ }, "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", + "babel-plugin-transform-import-meta": "^2.2.1", "eslint": "^9.14.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", @@ -559,6 +561,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, @@ -3881,6 +3884,27 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/babel-plugin-transform-import-meta": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-import-meta/-/babel-plugin-transform-import-meta-2.2.1.tgz", + "integrity": "sha512-AxNh27Pcg8Kt112RGa3Vod2QS2YXKKJ6+nSvRtv7qQTJAdx0MZa4UHZ4lnxHUWA2MNbLuZQv5FVab4P1CoLOWw==", + "dev": true, + "license": "BSD", + "dependencies": { + "@babel/template": "^7.4.4", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.10.0" + } + }, + "node_modules/babel-plugin-transform-import-meta/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", diff --git a/package.json b/package.json index 08473ca05..f5c595a35 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "homebrewery", "description": "Create authentic looking D&D homebrews using only markdown", "version": "3.16.0", + "type": "module", "engines": { "npm": "^10.2.x", "node": "^20.18.x" @@ -83,11 +84,13 @@ "@babel/preset-react" ], "plugins": [ - "@babel/plugin-transform-runtime" + "@babel/plugin-transform-runtime", + "babel-plugin-transform-import-meta" ] }, "dependencies": { "@babel/core": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.25.9", @@ -129,6 +132,7 @@ }, "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", + "babel-plugin-transform-import-meta": "^2.2.1", "eslint": "^9.14.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", diff --git a/scripts/buildHomebrew.js b/scripts/buildHomebrew.js index f072b0359..313c92db7 100644 --- a/scripts/buildHomebrew.js +++ b/scripts/buildHomebrew.js @@ -1,14 +1,15 @@ -const fs = require('fs-extra'); -const zlib = require('zlib'); -const Proj = require('./project.json'); +import fs from 'fs-extra'; +import zlib from 'zlib'; +import Proj from './project.json' with { type: 'json' }; +import vitreum from 'vitreum'; +const { pack, watchFile, livereload } = vitreum; -const { pack, watchFile, livereload } = require('vitreum'); -const isDev = !!process.argv.find((arg)=>arg=='--dev'); +import lessTransform from 'vitreum/transforms/less.js'; +import assetTransform from 'vitreum/transforms/asset.js'; +import babel from '@babel/core'; +import less from 'less'; -const lessTransform = require('vitreum/transforms/less.js'); -const assetTransform = require('vitreum/transforms/asset.js'); -const babel = require('@babel/core'); -const less = require('less'); +const isDev = !!process.argv.find((arg) => arg === '--dev'); const babelify = async (code)=>(await babel.transformAsync(code, { presets: [['@babel/preset-env', { 'exclude': ['proposal-dynamic-import'] }], '@babel/preset-react'], plugins: ['@babel/plugin-transform-runtime'] })).code; @@ -24,7 +25,7 @@ const build = async ({ bundle, render, ssr })=>{ //css = `@layer bundle {\n${css}\n}`; await fs.outputFile('./build/homebrew/bundle.css', css); await fs.outputFile('./build/homebrew/bundle.js', bundle); - await fs.outputFile('./build/homebrew/ssr.js', ssr); + await fs.outputFile('./build/homebrew/ssr.cjs', ssr); await fs.copy('./client/homebrew/favicon.ico', './build/assets/favicon.ico'); @@ -51,7 +52,7 @@ fs.emptyDirSync('./build'); const themes = { Legacy: {}, V3: {} }; let themeFiles = fs.readdirSync('./themes/Legacy'); - for (dir of themeFiles) { + for (let dir of themeFiles) { const themeData = JSON.parse(fs.readFileSync(`./themes/Legacy/${dir}/settings.json`).toString()); themeData.path = dir; themes.Legacy[dir] = (themeData); @@ -68,7 +69,7 @@ fs.emptyDirSync('./build'); } themeFiles = fs.readdirSync('./themes/V3'); - for (dir of themeFiles) { + for (let dir of themeFiles) { const themeData = JSON.parse(fs.readFileSync(`./themes/V3/${dir}/settings.json`).toString()); themeData.path = dir; themes.V3[dir] = (themeData); @@ -104,14 +105,14 @@ fs.emptyDirSync('./build'); const editorThemesBuildDir = './build/homebrew/cm-themes'; await fs.copy('./node_modules/codemirror/theme', editorThemesBuildDir); await fs.copy('./themes/codeMirror/customThemes', editorThemesBuildDir); - editorThemeFiles = fs.readdirSync(editorThemesBuildDir); + const editorThemeFiles = fs.readdirSync(editorThemesBuildDir); const editorThemeFile = './themes/codeMirror/editorThemes.json'; if(fs.existsSync(editorThemeFile)) fs.rmSync(editorThemeFile); const stream = fs.createWriteStream(editorThemeFile, { flags: 'a' }); stream.write('[\n"default"'); - for (themeFile of editorThemeFiles) { + for (let themeFile of editorThemeFiles) { stream.write(`,\n"${themeFile.slice(0, -4)}"`); } stream.write('\n]\n'); diff --git a/server.js b/server.js index 6cbe07c4f..fe5a9a363 100644 --- a/server.js +++ b/server.js @@ -1,12 +1,12 @@ -const DB = require('./server/db.js'); -const server = require('./server/app.js'); -const config = require('./server/config.js'); +import DB from './server/db.js'; +import server from './server/app.js'; +import config from './server/config.js'; DB.connect(config).then(()=>{ // Ensure that we have successfully connected to the database // before launching server const PORT = process.env.PORT || config.get('web_port') || 8000; - server.app.listen(PORT, ()=>{ + server.listen(PORT, ()=>{ const reset = '\x1b[0m'; // Reset to default style const bright = '\x1b[1m'; // Bright (bold) style const cyan = '\x1b[36m'; // Cyan color diff --git a/server/admin.api.js b/server/admin.api.js index bc179ff7b..02cdcb2f7 100644 --- a/server/admin.api.js +++ b/server/admin.api.js @@ -1,13 +1,15 @@ -const HomebrewModel = require('./homebrew.model.js').model; -const NotificationModel = require('./notifications.model.js').model; -const router = require('express').Router(); -const Moment = require('moment'); -const templateFn = require('../client/template.js'); -const zlib = require('zlib'); +import {model as HomebrewModel } from './homebrew.model.js'; +import {model as NotificationModel } from './notifications.model.js'; +import express from 'express'; +import Moment from 'moment'; +import zlib from 'zlib'; +import templateFn from '../client/template.js'; -const HomebrewAPI = require('./homebrew.api.js'); -const asyncHandler = require('express-async-handler'); -const { splitTextStyleAndMetadata } = require('../shared/helpers.js'); +import HomebrewAPI from './homebrew.api.js'; +import asyncHandler from 'express-async-handler'; +import { splitTextStyleAndMetadata } from '../shared/helpers.js'; + +const router = express.Router(); process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin'; process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3'; @@ -190,4 +192,4 @@ router.get('/admin', mw.adminOnly, (req, res)=>{ }); }); -module.exports = router; +export default router; diff --git a/server/admin.api.spec.js b/server/admin.api.spec.js index b0dbd5d84..6a23393b1 100644 --- a/server/admin.api.spec.js +++ b/server/admin.api.spec.js @@ -1,9 +1,10 @@ -const supertest = require('supertest'); +import supertest from 'supertest'; +import HBApp from './app.js'; +import {model as NotificationModel } from './notifications.model.js'; -const app = supertest.agent(require('app.js').app) - .set('X-Forwarded-Proto', 'https'); -const NotificationModel = require('./notifications.model.js').model; +// Mimic https responses to avoid being redirected all the time +const app = supertest.agent(HBApp).set('X-Forwarded-Proto', 'https'); describe('Tests for admin api', ()=>{ afterEach(()=>{ diff --git a/server/app.js b/server/app.js index 5f3a35150..8a2e17bbd 100644 --- a/server/app.js +++ b/server/app.js @@ -1,25 +1,41 @@ /*eslint max-lines: ["warn", {"max": 500, "skipBlankLines": true, "skipComments": true}]*/ // Set working directory to project root +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; +import packageJSON from './../package.json' with { type: "json" }; + +const __dirname = dirname(fileURLToPath(import.meta.url)); process.chdir(`${__dirname}/..`); +const version = packageJSON.version; + +import _ from 'lodash'; +import jwt from 'jwt-simple'; +import express from 'express'; +import yaml from 'js-yaml'; +import config from './config.js'; +import fs from 'fs-extra'; -const _ = require('lodash'); -const jwt = require('jwt-simple'); -const express = require('express'); -const yaml = require('js-yaml'); const app = express(); -const config = require('./config.js'); -const fs = require('fs-extra'); -const { homebrewApi, getBrew, getUsersBrewThemes, getCSS } = require('./homebrew.api.js'); -const GoogleActions = require('./googleActions.js'); -const serveCompressedStaticAssets = require('./static-assets.mv.js'); -const sanitizeFilename = require('sanitize-filename'); -const asyncHandler = require('express-async-handler'); -const templateFn = require('./../client/template.js'); +import api from './homebrew.api.js'; +const { homebrewApi, getBrew, getUsersBrewThemes, getCSS } = api; +import adminApi from './admin.api.js'; +import vaultApi from './vault.api.js'; +import GoogleActions from './googleActions.js'; +import serveCompressedStaticAssets from './static-assets.mv.js'; +import sanitizeFilename from 'sanitize-filename'; +import asyncHandler from 'express-async-handler'; +import templateFn from '../client/template.js'; +import {model as HomebrewModel } from './homebrew.model.js'; -const { DEFAULT_BREW } = require('./brewDefaults.js'); +import { DEFAULT_BREW } from './brewDefaults.js'; +import { splitTextStyleAndMetadata } from '../shared/helpers.js'; -const { splitTextStyleAndMetadata } = require('../shared/helpers.js'); +//==== Middleware Imports ====// +import contentNegotiation from './middleware/content-negotiation.js'; +import bodyParser from 'body-parser'; +import cookieParser from 'cookie-parser'; +import forceSSL from './forcessl.mw.js'; const sanitizeBrew = (brew, accessType)=>{ @@ -34,10 +50,10 @@ const sanitizeBrew = (brew, accessType)=>{ app.set('trust proxy', 1 /* number of proxies between user and server */) app.use('/', serveCompressedStaticAssets(`build`)); -app.use(require('./middleware/content-negotiation.js')); -app.use(require('body-parser').json({ limit: '25mb' })); -app.use(require('cookie-parser')()); -app.use(require('./forcessl.mw.js')); +app.use(contentNegotiation); +app.use(bodyParser.json({ limit: '25mb' })); +app.use(cookieParser()); +app.use(forceSSL); //Account Middleware app.use((req, res, next)=>{ @@ -57,15 +73,14 @@ app.use((req, res, next)=>{ }); app.use(homebrewApi); -app.use(require('./admin.api.js')); -app.use(require('./vault.api.js')); +app.use(adminApi); +app.use(vaultApi); -const HomebrewModel = require('./homebrew.model.js').model; -const welcomeText = require('fs').readFileSync('client/homebrew/pages/homePage/welcome_msg.md', 'utf8'); -const welcomeTextLegacy = require('fs').readFileSync('client/homebrew/pages/homePage/welcome_msg_legacy.md', 'utf8'); -const migrateText = require('fs').readFileSync('client/homebrew/pages/homePage/migrate.md', 'utf8'); -const changelogText = require('fs').readFileSync('changelog.md', 'utf8'); -const faqText = require('fs').readFileSync('faq.md', 'utf8'); +const welcomeText = fs.readFileSync('client/homebrew/pages/homePage/welcome_msg.md', 'utf8'); +const welcomeTextLegacy = fs.readFileSync('client/homebrew/pages/homePage/welcome_msg_legacy.md', 'utf8'); +const migrateText = fs.readFileSync('client/homebrew/pages/homePage/migrate.md', 'utf8'); +const changelogText = fs.readFileSync('changelog.md', 'utf8'); +const faqText = fs.readFileSync('faq.md', 'utf8'); String.prototype.replaceAll = function(s, r){return this.split(s).join(r);}; @@ -479,7 +494,7 @@ const renderPage = async (req, res)=>{ deployment : config.get('heroku_app_name') ?? '' }; const props = { - version : require('./../package.json').version, + version : version, url : req.customUrl || req.originalUrl, brew : req.brew, brews : req.brews, @@ -556,6 +571,4 @@ app.use((req, res)=>{ }); //^=====--------------------------------------=====^// -module.exports = { - app : app -}; +export default app; diff --git a/server/brewDefaults.js b/server/brewDefaults.js index 62fc6e671..11a84b9e9 100644 --- a/server/brewDefaults.js +++ b/server/brewDefaults.js @@ -1,4 +1,4 @@ -const _ = require('lodash'); +import _ from 'lodash'; // Default properties for newly-created brews const DEFAULT_BREW = { @@ -32,7 +32,7 @@ const DEFAULT_BREW_LOAD = _.defaults( }, DEFAULT_BREW); -module.exports = { +export { DEFAULT_BREW, DEFAULT_BREW_LOAD }; diff --git a/server/config.js b/server/config.js index fc50e68ba..69674595b 100644 --- a/server/config.js +++ b/server/config.js @@ -1,5 +1,7 @@ -module.exports = require('nconf') - .argv() - .env({ lowerCase: true }) - .file('environment', { file: `config/${process.env.NODE_ENV}.json` }) - .file('defaults', { file: 'config/default.json' }); +import nconf from 'nconf'; + +export default nconf + .argv() + .env({ lowerCase: true }) + .file('environment', { file: `config/${process.env.NODE_ENV}.json` }) + .file('defaults', { file: 'config/default.json' }); \ No newline at end of file diff --git a/server/db.js b/server/db.js index 7690927e9..97da56a08 100644 --- a/server/db.js +++ b/server/db.js @@ -5,7 +5,7 @@ // reused by both the main application and all tests which require database // connection. -const Mongoose = require('mongoose'); +import Mongoose from 'mongoose'; const getMongoDBURL = (config)=>{ return config.get('mongodb_uri') || @@ -31,7 +31,7 @@ const connect = async (config)=>{ .catch((error)=>handleConnectionError(error)); }; -module.exports = { - connect : connect, - disconnect : disconnect +export default { + connect, + disconnect }; diff --git a/server/forcessl.mw.js b/server/forcessl.mw.js index 4f03d9c32..bf9ab65d3 100644 --- a/server/forcessl.mw.js +++ b/server/forcessl.mw.js @@ -1,4 +1,4 @@ -module.exports = (req, res, next)=>{ +export default (req, res, next)=>{ if(process.env.NODE_ENV === 'local' || process.env.NODE_ENV === 'docker') return next(); if(req.header('x-forwarded-proto') !== 'https') { return res.redirect(302, `https://${req.get('Host')}${req.url}`); diff --git a/server/googleActions.js b/server/googleActions.js index bc97551ee..758cb7e3d 100644 --- a/server/googleActions.js +++ b/server/googleActions.js @@ -1,8 +1,9 @@ /* eslint-disable max-lines */ -const googleDrive = require('@googleapis/drive'); -const { nanoid } = require('nanoid'); -const token = require('./token.js'); -const config = require('./config.js'); +import googleDrive from '@googleapis/drive'; +import { nanoid } from 'nanoid'; +import token from './token.js'; +import config from './config.js'; + let serviceAuth; if(!config.get('service_account')){ @@ -72,7 +73,7 @@ const GoogleActions = { getGoogleFolder : async (auth)=>{ const drive = googleDrive.drive({ version: 'v3', auth }); - fileMetadata = { + const fileMetadata = { 'name' : 'Homebrewery', 'mimeType' : 'application/vnd.google-apps.folder' }; @@ -344,4 +345,4 @@ const GoogleActions = { } }; -module.exports = GoogleActions; +export default GoogleActions; diff --git a/server/homebrew.api.js b/server/homebrew.api.js index e156f3c85..b8d4024ad 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -1,18 +1,20 @@ /* eslint-disable max-lines */ -const _ = require('lodash'); -const HomebrewModel = require('./homebrew.model.js').model; -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 asyncHandler = require('express-async-handler'); -const { nanoid } = require('nanoid'); -const { splitTextStyleAndMetadata } = require('../shared/helpers.js'); +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 Markdown from '../shared/naturalcrit/markdown.js'; +import yaml from 'js-yaml'; +import asyncHandler from 'express-async-handler'; +import { nanoid } from 'nanoid'; +import { splitTextStyleAndMetadata } from '../shared/helpers.js'; +import checkClientVersion from './middleware/check-client-version.js'; -const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); +const router = express.Router(); -const Themes = require('../themes/themes.json'); +import { DEFAULT_BREW, DEFAULT_BREW_LOAD } from './brewDefaults.js'; +import Themes from '../themes/themes.json' with { type: 'json' }; const isStaticTheme = (renderer, themeName)=>{ return Themes[renderer]?.[themeName] !== undefined; @@ -473,7 +475,7 @@ const api = { } }; -router.use('/api', require('./middleware/check-client-version.js')); +router.use('/api', checkClientVersion); router.post('/api', asyncHandler(api.newBrew)); router.put('/api/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); router.put('/api/update/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); @@ -481,4 +483,4 @@ router.delete('/api/:id', asyncHandler(api.deleteBrew)); router.get('/api/remove/:id', asyncHandler(api.deleteBrew)); router.get('/api/theme/:renderer/:id', asyncHandler(api.getThemeBundle)); -module.exports = api; +export default api; \ No newline at end of file diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index a1222cb57..84ffc3052 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -36,8 +36,9 @@ describe('Tests for api', ()=>{ } }); - google = require('./googleActions.js'); - model = require('./homebrew.model.js').model; + google = require('./googleActions.js').default; + model = require('./homebrew.model.js').model; + api = require('./homebrew.api').default; jest.mock('./googleActions.js'); google.authCheck = jest.fn(()=>'client'); @@ -54,8 +55,6 @@ describe('Tests for api', ()=>{ setHeader : jest.fn(()=>{}) }; - api = require('./homebrew.api'); - hbBrew = { text : `brew text`, style : 'hello yes i am css', diff --git a/server/homebrew.model.js b/server/homebrew.model.js index c8db8fdcc..adeac0d5d 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -1,7 +1,8 @@ -const mongoose = require('mongoose'); -const { nanoid } = require('nanoid'); -const _ = require('lodash'); -const zlib = require('zlib'); +import mongoose from 'mongoose'; +import { nanoid } from 'nanoid'; +import _ from 'lodash'; +import zlib from 'zlib'; + const HomebrewSchema = mongoose.Schema({ shareId : { type: String, default: ()=>{return nanoid(12);}, index: { unique: true } }, @@ -44,7 +45,7 @@ HomebrewSchema.statics.get = async function(query, fields=null){ const brew = await Homebrew.findOne(query, fields).orFail() .catch((error)=>{throw 'Can not find brew';}); if(!_.isNil(brew.textBin)) { // Uncompress zipped text field - unzipped = zlib.inflateRawSync(brew.textBin); + const unzipped = zlib.inflateRawSync(brew.textBin); brew.text = unzipped.toString(); } return brew; @@ -62,7 +63,7 @@ HomebrewSchema.statics.getByUser = async function(username, allowAccess=false, f const Homebrew = mongoose.model('Homebrew', HomebrewSchema); -module.exports = { - schema : HomebrewSchema, - model : Homebrew, +export { + HomebrewSchema as schema, + Homebrew as model }; diff --git a/server/middleware/check-client-version.js b/server/middleware/check-client-version.js index e9caf6eff..001995f4e 100644 --- a/server/middleware/check-client-version.js +++ b/server/middleware/check-client-version.js @@ -1,6 +1,8 @@ -module.exports = (req, res, next)=>{ +import packageJSON from '../../package.json' with { type: "json" }; +const version = packageJSON.version; + +export default (req, res, next)=>{ const userVersion = req.get('Homebrewery-Version'); - const version = require('../../package.json').version; if(userVersion != version) { return res.status(412).send({ diff --git a/server/middleware/content-negotiation.js b/server/middleware/content-negotiation.js index a5bc7dc83..ece60e064 100644 --- a/server/middleware/content-negotiation.js +++ b/server/middleware/content-negotiation.js @@ -1,8 +1,8 @@ -const config = require('../config.js'); +import config from '../config.js'; const nodeEnv = config.get('node_env'); const isLocalEnvironment = config.get('local_environments').includes(nodeEnv); -module.exports = (req, res, next)=>{ +export default (req, res, next)=>{ const isImageRequest = req.get('Accept')?.split(',') ?.filter((h)=>!h.includes('q=')) ?.every((h)=>/image\/.*/.test(h)); diff --git a/server/middleware/content-negotiation.spec.js b/server/middleware/content-negotiation.spec.js deleted file mode 100644 index 68f22eb1c..000000000 --- a/server/middleware/content-negotiation.spec.js +++ /dev/null @@ -1,41 +0,0 @@ -const contentNegotiationMiddleware = require('./content-negotiation.js'); - -describe('content-negotiation-middleware', ()=>{ - let request; - let response; - let next; - - beforeEach(()=>{ - request = { - get : function(key) { - return this[key]; - } - }; - response = { - status : jest.fn(()=>response), - send : jest.fn(()=>{}) - }; - next = jest.fn(); - }); - - it('should return 406 on image request', ()=>{ - contentNegotiationMiddleware({ - Accept : 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8', - ...request - }, response); - - expect(response.status).toHaveBeenLastCalledWith(406); - expect(response.send).toHaveBeenCalledWith({ - message : 'Request for image at this URL is not supported' - }); - }); - - it('should call next on non-image request', ()=>{ - contentNegotiationMiddleware({ - Accept : 'text,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8', - ...request - }, response, next); - - expect(next).toHaveBeenCalled(); - }); -}); \ No newline at end of file diff --git a/server/notifications.model.js b/server/notifications.model.js index 0a32bde8a..723609bb5 100644 --- a/server/notifications.model.js +++ b/server/notifications.model.js @@ -1,5 +1,5 @@ -const mongoose = require('mongoose'); -const _ = require('lodash'); +import mongoose from 'mongoose'; +import _ from 'lodash'; const NotificationSchema = new mongoose.Schema({ dismissKey : { type: String, unique: true, required: true }, @@ -56,7 +56,7 @@ NotificationSchema.statics.getAll = async function() { const Notification = mongoose.model('Notification', NotificationSchema); -module.exports = { - schema : NotificationSchema, - model : Notification, +export { + NotificationSchema as schema, + Notification as model }; diff --git a/server/static-assets.mv.js b/server/static-assets.mv.js index 732420d46..adf606689 100644 --- a/server/static-assets.mv.js +++ b/server/static-assets.mv.js @@ -1,4 +1,4 @@ -const expressStaticGzip = require('express-static-gzip'); +import expressStaticGzip from 'express-static-gzip'; // Serve brotli-compressed static files if available const customCacheControlHandler=(response, path)=>{ @@ -28,4 +28,4 @@ const init=(pathToAssets)=>{ } }); }; -module.exports = init; +export default init; diff --git a/server/token.js b/server/token.js index 70d6e01c5..7a23dff4b 100644 --- a/server/token.js +++ b/server/token.js @@ -1,7 +1,5 @@ -const jwt = require('jwt-simple'); - -// Load configuration values -const config = require('./config.js'); +import jwt from 'jwt-simple'; +import config from './config.js'; // Generate an Access Token for the given User ID const generateAccessToken = (account)=>{ @@ -24,6 +22,4 @@ const generateAccessToken = (account)=>{ return token; }; -module.exports = { - generateAccessToken : generateAccessToken -}; +export default generateAccessToken; \ No newline at end of file diff --git a/server/vault.api.js b/server/vault.api.js index 8aa382f26..6a7b9fb91 100644 --- a/server/vault.api.js +++ b/server/vault.api.js @@ -1,6 +1,6 @@ -const express = require('express'); -const asyncHandler = require('express-async-handler'); -const HomebrewModel = require('./homebrew.model.js').model; +import express from 'express'; +import asyncHandler from 'express-async-handler'; +import {model as HomebrewModel } from './homebrew.model.js'; const router = express.Router(); @@ -106,4 +106,4 @@ const findTotal = async (req, res)=>{ router.get('/api/vault/total', asyncHandler(findTotal)); router.get('/api/vault', asyncHandler(findBrews)); -module.exports = router; +export default router; diff --git a/shared/helpers.js b/shared/helpers.js index ac684b06f..d60da885d 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -1,6 +1,6 @@ -const _ = require('lodash'); -const yaml = require('js-yaml'); -const request = require('../client/homebrew/utils/request-middleware.js'); +import _ from 'lodash'; +import yaml from 'js-yaml'; +import request from '../client/homebrew/utils/request-middleware.js'; const splitTextStyleAndMetadata = (brew)=>{ brew.text = brew.text.replaceAll('\r\n', '\n'); @@ -51,7 +51,7 @@ const fetchThemeBundle = async (obj, renderer, theme)=>{ })); }; -module.exports = { +export { splitTextStyleAndMetadata, printCurrentBrew, fetchThemeBundle, diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index ef789bdd6..4c1a2f92a 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -1,19 +1,19 @@ /* eslint-disable max-lines */ -const _ = require('lodash'); -const Marked = require('marked'); -const MarkedExtendedTables = require('marked-extended-tables'); -const { markedSmartypantsLite: MarkedSmartypantsLite } = require('marked-smartypants-lite'); -const { gfmHeadingId: MarkedGFMHeadingId, resetHeadings: MarkedGFMResetHeadingIDs } = require('marked-gfm-heading-id'); -const { markedEmoji: MarkedEmojis } = require('marked-emoji'); +import _ from 'lodash'; +import { Parser as MathParser } from 'expr-eval'; +import { marked as Marked } from 'marked'; +import MarkedExtendedTables from 'marked-extended-tables'; +import { markedSmartypantsLite as MarkedSmartypantsLite } from 'marked-smartypants-lite'; +import { gfmHeadingId as MarkedGFMHeadingId, resetHeadings as MarkedGFMResetHeadingIDs } from 'marked-gfm-heading-id'; +import { markedEmoji as MarkedEmojis } from 'marked-emoji'; //Icon fonts included so they can appear in emoji autosuggest dropdown -const diceFont = require('../../themes/fonts/iconFonts/diceFont.js'); -const elderberryInn = require('../../themes/fonts/iconFonts/elderberryInn.js'); -const fontAwesome = require('../../themes/fonts/iconFonts/fontAwesome.js'); -const gameIcons = require('../../themes/fonts/iconFonts/gameIcons.js'); +import diceFont from '../../themes/fonts/iconFonts/diceFont.js'; +import elderberryInn from '../../themes/fonts/iconFonts/elderberryInn.js'; +import gameIcons from '../../themes/fonts/iconFonts/gameIcons.js'; +import fontAwesome from '../../themes/fonts/iconFonts/fontAwesome.js'; -const MathParser = require('expr-eval').Parser; -const renderer = new Marked.Renderer(); +const renderer = new Marked.Renderer(); const tokenizer = new Marked.Tokenizer(); //Limit math features to simple items @@ -854,7 +854,7 @@ const globalVarsList = {}; let varsQueue = []; let globalPageNumber = 0; -module.exports = { +const Markdown = { marked : Marked, render : (rawBrewText, pageNumber=0)=>{ globalVarsList[pageNumber] = {}; //Reset global links for current page, to ensure values are parsed in order @@ -865,6 +865,7 @@ module.exports = { } rawBrewText = rawBrewText.replace(/^\\column$/gm, `\n
    \n`); + const opts = Marked.defaults; rawBrewText = opts.hooks.preprocess(rawBrewText); @@ -935,3 +936,6 @@ module.exports = { return errors; }, }; + +export default Markdown; + diff --git a/tests/markdown/basic.test.js b/tests/markdown/basic.test.js index 80f5520e7..e5feec0b3 100644 --- a/tests/markdown/basic.test.js +++ b/tests/markdown/basic.test.js @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; test('Processes the markdown within an HTML block if its just a class wrapper', function() { const source = '
    *Bold text*
    '; diff --git a/tests/markdown/definition-lists.test.js b/tests/markdown/definition-lists.test.js index 9c0bdf6b0..039754ca1 100644 --- a/tests/markdown/definition-lists.test.js +++ b/tests/markdown/definition-lists.test.js @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; describe('Inline Definition Lists', ()=>{ test('No Term 1 Definition', function() { diff --git a/tests/markdown/emojis.test.js b/tests/markdown/emojis.test.js index a4abbc6a4..e70ebb673 100644 --- a/tests/markdown/emojis.test.js +++ b/tests/markdown/emojis.test.js @@ -1,4 +1,4 @@ -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; const dedent = require('dedent-tabs').default; // Marked.js adds line returns after closing tags on some default tokens. diff --git a/tests/markdown/hard-breaks.test.js b/tests/markdown/hard-breaks.test.js index 3d0f59a41..8af102716 100644 --- a/tests/markdown/hard-breaks.test.js +++ b/tests/markdown/hard-breaks.test.js @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; describe('Hard Breaks', ()=>{ test('Single Break', function() { diff --git a/tests/markdown/mustache-syntax.test.js b/tests/markdown/mustache-syntax.test.js index 51284ef2b..261a5fd32 100644 --- a/tests/markdown/mustache-syntax.test.js +++ b/tests/markdown/mustache-syntax.test.js @@ -1,7 +1,7 @@ /* eslint-disable max-lines */ const dedent = require('dedent-tabs').default; -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; // Marked.js adds line returns after closing tags on some default tokens. // This removes those line returns for comparison sake. diff --git a/tests/markdown/variables.test.js b/tests/markdown/variables.test.js index bf778b14d..be16e8a22 100644 --- a/tests/markdown/variables.test.js +++ b/tests/markdown/variables.test.js @@ -1,7 +1,7 @@ /* eslint-disable max-lines */ const dedent = require('dedent-tabs').default; -const Markdown = require('naturalcrit/markdown.js'); +import Markdown from 'naturalcrit/markdown.js'; // Marked.js adds line returns after closing tags on some default tokens. // This removes those line returns for comparison sake. diff --git a/tests/routes/static-pages.test.js b/tests/routes/static-pages.test.js index c5578dec9..ebfa48dd4 100644 --- a/tests/routes/static-pages.test.js +++ b/tests/routes/static-pages.test.js @@ -1,8 +1,8 @@ -const supertest = require('supertest'); +import supertest from 'supertest'; +import HBApp from 'app.js'; // Mimic https responses to avoid being redirected all the time -const app = supertest.agent(require('app.js').app) - .set('X-Forwarded-Proto', 'https'); +const app = supertest.agent(HBApp).set('X-Forwarded-Proto', 'https'); describe('Tests for static pages', ()=>{ it('Home page works', ()=>{ diff --git a/themes/V3/Blank/snippets/footer.gen.js b/themes/V3/Blank/snippets/footer.gen.js index 6583cd06e..9384baed7 100644 --- a/themes/V3/Blank/snippets/footer.gen.js +++ b/themes/V3/Blank/snippets/footer.gen.js @@ -1,4 +1,4 @@ -const Markdown = require('../../../../shared/naturalcrit/markdown.js'); +import Markdown from '../../../../shared/naturalcrit/markdown.js'; module.exports = { createFooterFunc : function(headerSize=1){ diff --git a/themes/fonts/iconFonts/diceFont.js b/themes/fonts/iconFonts/diceFont.js index 6ac75ad26..a349d7b0a 100644 --- a/themes/fonts/iconFonts/diceFont.js +++ b/themes/fonts/iconFonts/diceFont.js @@ -93,4 +93,4 @@ const diceFont = { 'df_solid_small_dot_d6_6' : 'df solid-small-dot-d6-6' }; -module.exports = diceFont; \ No newline at end of file +export default diceFont; \ No newline at end of file diff --git a/themes/fonts/iconFonts/elderberryInn.js b/themes/fonts/iconFonts/elderberryInn.js index 042648e4d..6fd933f78 100644 --- a/themes/fonts/iconFonts/elderberryInn.js +++ b/themes/fonts/iconFonts/elderberryInn.js @@ -206,4 +206,4 @@ const elderberryInn = { 'ei_wish' : 'ei wish' }; -module.exports = elderberryInn; \ No newline at end of file +export default elderberryInn; \ No newline at end of file diff --git a/themes/fonts/iconFonts/fontAwesome.js b/themes/fonts/iconFonts/fontAwesome.js index 764bd5bc5..f5f89e3aa 100644 --- a/themes/fonts/iconFonts/fontAwesome.js +++ b/themes/fonts/iconFonts/fontAwesome.js @@ -2051,4 +2051,4 @@ const fontAwesome = { 'fab_zhihu' : 'fab fa-zhihu' }; -module.exports = fontAwesome; \ No newline at end of file +export default fontAwesome; \ No newline at end of file diff --git a/themes/fonts/iconFonts/gameIcons.js b/themes/fonts/iconFonts/gameIcons.js index d92591cef..346e83027 100644 --- a/themes/fonts/iconFonts/gameIcons.js +++ b/themes/fonts/iconFonts/gameIcons.js @@ -506,4 +506,4 @@ const gameIcons = { 'gi_acid' : 'gi acid' }; -module.exports = gameIcons; \ No newline at end of file +export default gameIcons; \ No newline at end of file From 1850173f87b4ed4934c1dd8eb8bfab9e911bc73e Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 20 Nov 2024 16:22:48 -0500 Subject: [PATCH 49/75] Remove unused dependency --- package-lock.json | 1 - package.json | 1 - 2 files changed, 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 03f892206..be7d7adb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "license": "MIT", "dependencies": { "@babel/core": "^7.26.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.25.9", diff --git a/package.json b/package.json index f5c595a35..36115255f 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,6 @@ }, "dependencies": { "@babel/core": "^7.26.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", "@babel/preset-react": "^7.25.9", From e5624434d697117cfacfb200024a963c2a94ef6a Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 20 Nov 2024 17:04:23 -0500 Subject: [PATCH 50/75] Update buildAdmin.js --- scripts/buildAdmin.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/buildAdmin.js b/scripts/buildAdmin.js index 1157a063b..9c77315ef 100644 --- a/scripts/buildAdmin.js +++ b/scripts/buildAdmin.js @@ -1,13 +1,14 @@ -const fs = require('fs-extra'); -const Proj = require('./project.json'); -const { pack } = require('vitreum'); +import fs from 'fs-extra'; +import Proj from './project.json' with { type: 'json' }; +import vitreum from 'vitreum'; +const { pack } = vitreum; + +import lessTransform from 'vitreum/transforms/less.js'; +import assetTransform from 'vitreum/transforms/asset.js'; + const isDev = !!process.argv.find((arg)=>arg=='--dev'); -const lessTransform = require('vitreum/transforms/less.js'); -const assetTransform = require('vitreum/transforms/asset.js'); -//const Meta = require('vitreum/headtags'); - const transforms = { '.less' : lessTransform, '*' : assetTransform('./build') @@ -17,7 +18,7 @@ const build = async ({ bundle, render, ssr })=>{ const css = await lessTransform.generate({ paths: './shared' }); await fs.outputFile('./build/admin/bundle.css', css); await fs.outputFile('./build/admin/bundle.js', bundle); - await fs.outputFile('./build/admin/ssr.js', ssr); + await fs.outputFile('./build/admin/ssr.cjs', ssr); }; fs.emptyDirSync('./build/admin'); From 6f016bf5b676a3da6874d6fc4704ae11f2487394 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:25:09 +0000 Subject: [PATCH 51/75] Bump dompurify from 3.2.0 to 3.2.1 Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.2.0 to 3.2.1. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.2.0...3.2.1) --- updated-dependencies: - dependency-name: dompurify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 17 +++++++++++++---- package.json | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 69ae504de..a7cddf6e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "cookie-parser": "^1.4.7", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", - "dompurify": "^3.2.0", + "dompurify": "^3.2.1", "expr-eval": "^2.0.2", "express": "^4.21.1", "express-async-handler": "^1.2.0", @@ -3084,6 +3084,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "optional": true + }, "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", @@ -5478,9 +5484,12 @@ } }, "node_modules/dompurify": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.0.tgz", - "integrity": "sha512-AMdOzK44oFWqHEi0wpOqix/fUNY707OmoeFDnbi3Q5I8uOpy21ufUA5cDJPr0bosxrflOVD/H2DMSvuGKJGfmQ==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.1.tgz", + "integrity": "sha512-NBHEsc0/kzRYQd+AY6HR6B/IgsqzBABrqJbpCDQII/OK6h7B7LXzweZTDsqSW2LkTRpoxf18YUP+YjGySk6B3w==", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } }, "node_modules/duplexer2": { "version": "0.1.4", diff --git a/package.json b/package.json index 5b095c7a4..5c3b989d1 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "cookie-parser": "^1.4.7", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", - "dompurify": "^3.2.0", + "dompurify": "^3.2.1", "expr-eval": "^2.0.2", "express": "^4.21.1", "express-async-handler": "^1.2.0", From 7c3f3b87af5c2bbf8c4e3c69965289a4c689baf9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:32:02 +0000 Subject: [PATCH 52/75] Bump eslint from 9.14.0 to 9.15.0 Bumps [eslint](https://github.com/eslint/eslint) from 9.14.0 to 9.15.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v9.14.0...v9.15.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 77 +++++++++++++++++++---------------------------- package.json | 2 +- 2 files changed, 32 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index b60594977..544cba788 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.2.1", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", "globals": "^15.12.0", @@ -1871,9 +1871,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", "dev": true, "dependencies": { "@eslint/object-schema": "^2.1.4", @@ -1885,20 +1885,19 @@ } }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1922,7 +1921,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -1931,9 +1929,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", + "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1949,9 +1947,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", "dev": true, "dependencies": { "levn": "^0.4.1" @@ -3291,7 +3289,6 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -3345,7 +3342,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -5006,11 +5002,10 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -5793,26 +5788,26 @@ "license": "MIT" }, "node_modules/eslint": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", + "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.14.0", - "@eslint/plugin-kit": "^0.2.0", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.15.0", + "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.0", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.5", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", @@ -5831,8 +5826,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -10096,8 +10090,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-stable-stringify": { "version": "0.0.1", @@ -14093,13 +14086,6 @@ "node": ">=8" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -14711,7 +14697,6 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } diff --git a/package.json b/package.json index 5c3b989d1..a18302f09 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.2.1", - "eslint": "^9.14.0", + "eslint": "^9.15.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", "globals": "^15.12.0", From 9807cf762ba51ead10768bffc392dc13dcc0e0df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:51:39 +0000 Subject: [PATCH 53/75] Bump nanoid from 3.3.4 to 5.0.8 Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.4 to 5.0.8. - [Release notes](https://github.com/ai/nanoid/releases) - [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md) - [Commits](https://github.com/ai/nanoid/compare/3.3.4...5.0.8) --- updated-dependencies: - dependency-name: nanoid dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 19 ++++++++++++------- package.json | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 544cba788..6b30e4a73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.8.2", - "nanoid": "3.3.4", + "nanoid": "5.0.8", "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -11047,15 +11047,20 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "license": "MIT", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.8.tgz", + "integrity": "sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { - "nanoid": "bin/nanoid.cjs" + "nanoid": "bin/nanoid.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^18 || >=20" } }, "node_modules/nanomatch": { diff --git a/package.json b/package.json index a18302f09..7e6a4ab98 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.8.2", - "nanoid": "3.3.4", + "nanoid": "5.0.8", "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", From ebe8e1067c96de0512e936aad0350ca902253f56 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 21 Nov 2024 13:33:32 -0500 Subject: [PATCH 54/75] Move babel config to separate file Jest struggles to read all babel configurations if directly inside package.json. This now allows us to install nanoid 5 and pass all tests with it. --- babel.config.json | 10 ++++++++++ package.json | 13 +++---------- server/googleActions.js | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 babel.config.json diff --git a/babel.config.json b/babel.config.json new file mode 100644 index 000000000..5e768ec31 --- /dev/null +++ b/babel.config.json @@ -0,0 +1,10 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-react" + ], + "plugins": [ + "@babel/plugin-transform-runtime", + "babel-plugin-transform-import-meta" + ] +} diff --git a/package.json b/package.json index 7e6a4ab98..0050b8e26 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,9 @@ "shared", "server" ], + "transformIgnorePatterns": [ + "node_modules/(?!nanoid/).*" + ], "coveragePathIgnorePatterns": [ "build/*" ], @@ -78,16 +81,6 @@ "jest-expect-message" ] }, - "babel": { - "presets": [ - "@babel/preset-env", - "@babel/preset-react" - ], - "plugins": [ - "@babel/plugin-transform-runtime", - "babel-plugin-transform-import-meta" - ] - }, "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-runtime": "^7.25.9", diff --git a/server/googleActions.js b/server/googleActions.js index 758cb7e3d..ec541e5f5 100644 --- a/server/googleActions.js +++ b/server/googleActions.js @@ -60,7 +60,7 @@ const GoogleActions = { account.googleRefreshToken = tokens.refresh_token; } account.googleAccessToken = tokens.access_token; - const JWTToken = token.generateAccessToken(account); + const JWTToken = token(account); //Save updated token to cookie //res.cookie('nc_session', JWTToken, { maxAge: 1000*60*60*24*365, path: '/', sameSite: 'lax' }); From decb334808b914edf0274507375db029a32ce688 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 25 Nov 2024 10:41:11 -0600 Subject: [PATCH 55/75] Fix regression in emoji auto-complete due to ESM update --- shared/naturalcrit/codeEditor/autocompleteEmoji.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/naturalcrit/codeEditor/autocompleteEmoji.js b/shared/naturalcrit/codeEditor/autocompleteEmoji.js index fae373115..c7efa172b 100644 --- a/shared/naturalcrit/codeEditor/autocompleteEmoji.js +++ b/shared/naturalcrit/codeEditor/autocompleteEmoji.js @@ -1,7 +1,7 @@ -const diceFont = require('../../../themes/fonts/iconFonts/diceFont.js'); -const elderberryInn = require('../../../themes/fonts/iconFonts/elderberryInn.js'); -const fontAwesome = require('../../../themes/fonts/iconFonts/fontAwesome.js'); -const gameIcons = require('../../../themes/fonts/iconFonts/gameIcons.js'); +import diceFont from '../../../themes/fonts/iconFonts/diceFont.js'; +import elderberryInn from '../../../themes/fonts/iconFonts/elderberryInn.js'; +import fontAwesome from '../../../themes/fonts/iconFonts/fontAwesome.js'; +import gameIcons from '../../../themes/fonts/iconFonts/gameIcons.js'; const emojis = { ...diceFont, From add088c2a92d49482facfdb6dd1958d676fb9b9c Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 27 Nov 2024 16:26:26 -0500 Subject: [PATCH 56/75] Up version to 3.16.1 --- changelog.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 1f7815d8d..3736ba9b0 100644 --- a/changelog.md +++ b/changelog.md @@ -85,6 +85,52 @@ pre { ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). +### Wednesday 11/27/2024 - v3.16.1 + +{{taskList +##### 5e-Cleric + +* [x] Allow linking to specific HTML IDs via `#ID` at the end of the URL, e.g.: `homebrewery.naturalcrit.com/share/share/a6RCXwaDS58i#p4` to link to Page 4 directly + +Fixes issues [#2820](https://github.com/naturalcrit/homebrewery/issues/2820), [#3505](https://github.com/naturalcrit/homebrewery/issues/3505) + +* [x] Fix generation of link to certain Google Drive brews + +Fixes issue [#3776](https://github.com/naturalcrit/homebrewery/issues/3776) + +##### abquintic + +* [x] Fix blank pages appearing when pasting text + +Fixes issue [#3718](https://github.com/naturalcrit/homebrewery/issues/3718) + +##### Gazook89 + +* [x] Add new brew viewing options to the view toolbar +- {{fac,single-spread}} {{openSans **SINGLE PAGE**}} +- {{fac,facing-spread}} {{openSans **TWO PAGE**}} +- {{fac,flow-spread}} {{openSans **GRID**}} + +Fixes issue [#1379](https://github.com/naturalcrit/homebrewery/issues/1379) + +* [x] Updates to tag input boxes + +##### G-Ambatte + +* [x] Admin tools to fix certain corrupted documents + +Fixes issue [#3801](https://github.com/naturalcrit/homebrewery/issues/3801) + +* [x] Fix print window being affected by document zoom + +Fixes issue [#3744](https://github.com/naturalcrit/homebrewery/issues/3744) + + +##### calculuschild, 5e-Cleric, G-Ambatte, Gazook89, abquintic + +* [x] Multiple code refactors, cleanups, and security fixes +}} + ### Saturday 10/12/2024 - v3.16.0 {{taskList diff --git a/package-lock.json b/package-lock.json index 6b30e4a73..54df6a48e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebrewery", - "version": "3.16.0", + "version": "3.16.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebrewery", - "version": "3.16.0", + "version": "3.16.1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 0050b8e26..d87e75887 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.16.0", + "version": "3.16.1", "type": "module", "engines": { "npm": "^10.2.x", From 6f4cc0d91bc61e3f76ca727820c9ecc833cc717a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 21:29:38 +0000 Subject: [PATCH 57/75] Bump mongoose from 8.8.2 to 8.8.3 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.2 to 8.8.3. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.8.2...8.8.3) --- updated-dependencies: - dependency-name: mongoose dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 54df6a48e..8d3b75ef9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.8.2", + "mongoose": "^8.8.3", "nanoid": "5.0.8", "nconf": "^0.12.1", "react": "^18.3.1", @@ -10891,9 +10891,10 @@ } }, "node_modules/mongoose": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.2.tgz", - "integrity": "sha512-jCTSqDANfRzk909v4YoZQi7jlGRB2MTvgG+spVBc/BA4tOs1oWJr//V6yYujqNq9UybpOtsSfBqxI0dSOEFJHQ==", + "version": "8.8.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.3.tgz", + "integrity": "sha512-/I4n/DcXqXyIiLRfAmUIiTjj3vXfeISke8dt4U4Y8Wfm074Wa6sXnQrXN49NFOFf2mM1kUdOXryoBvkuCnr+Qw==", + "license": "MIT", "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", diff --git a/package.json b/package.json index d87e75887..ba7322cbf 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.8.2", + "mongoose": "^8.8.3", "nanoid": "5.0.8", "nconf": "^0.12.1", "react": "^18.3.1", From 3f0a6a577fecee1cfcbc69a5c16f8a941d7bd41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Wed, 27 Nov 2024 23:28:08 +0100 Subject: [PATCH 58/75] faq new version --- faq.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/faq.md b/faq.md index c7254952b..d3b6d24f6 100644 --- a/faq.md +++ b/faq.md @@ -69,7 +69,6 @@ pre { You can check the site status here: [Everyone or Just Me](https://downforeveryoneorjustme.com/homebrewery.naturalcrit.com) - ### Why am I getting an error when trying to save, and my account is linked to Google? A sign-in with Google only lasts a year until the authentication expires. You must go [here](https://www.naturalcrit.com/login), click the *Log-out* button, and then sign back in using your Google account. @@ -82,12 +81,17 @@ If you have linked your account with a Google account, you would change your pas ### Is there a way to restore a previous version of my brew? -Currently, there is no way to do this through the site yourself. This would take too much of a toll on the amount of storage the homebrewery requires. However, we do have daily backups of our database that we keep for 8 days, and you can contact the moderators on [the subreddit](https://www.reddit.com/r/homebrewery) with your Homebrewery username, the name of the lost brew, and the last known time it was working properly. We can manually look through our backups and restore it if it exists. +In your brew, there is an icon, :fas_clock_rotate_left:, that button opens up a menu with versions of your brew, stored in order from newer to older, up to a week old. Because of the amount of duplicates this function creates, this information is stored in **your browser**, so if you were to uninstall it or clear your cookies and site data, or change computers, the info will not be there. + +Also, we do have daily backups of our database that we keep for 8 days, and you can contact the moderators on [the subreddit](https://www.reddit.com/r/homebrewery) with your Homebrewery username, the name of the lost brew, and the last known time it was working properly. We can manually look through our backups and restore it if it exists. + ### I worked on a brew for X hours, and suddenly all the text disappeared! This usually happens if you accidentally drag-select all of your text and then start typing which overwrites the selection. Do not panic, and do not refresh the page or reload your brew quite yet as it is probably auto-saved in this state already. Simply press CTRL+Z as many times as needed to undo your last few changes and you will be back to where you were, then make sure to save your brew in the "good" state. +You can also load a history version old enough to have all the text, using the :fas_clock_rotate_left: history versions button. + \column ### Why is only Chrome supported? @@ -112,10 +116,7 @@ Once you have an image you would like to use, it is recommended to host it somew \page ### A particular font does not work for my language, what do I do? -The fonts used were originally created for use with the English language, though revisions since then have added more support for other languages. They are still not complete sets and may be missing a glyph/character you need. Unfortunately, the volunteer group as it stands at the time of this writing does not have a font guru, so it would be difficult to add more glyphs (especially complicated glyphs). Let us know which glyph is missing on the subreddit, but you may need to search [Google Fonts](https://fonts.google.com) for an alternative font if you need something fast. - -### Whenever I click on the "Get PDF" button, instead of getting a download, it opens Print Preview in another tab. -Yes, this is by design. In the print preview, select "Save as PDF" as the Destination, and then click "Save". There will be a normal download dialog where you can save your brew as a PDF. +The fonts used were originally created for use with the English language, though revisions since then have added more support for other languages. They are still not complete sets and may be missing a glyph/character you need. Unfortunately, the volunteer group as it stands at the time of this writing does not have a font guru, so it would be difficult to add more glyphs (especially complicated glyphs). Let us know which glyph is missing on the subreddit, but you may need to search [Google Fonts](https://fonts.google.com) for an alternative font if you need something fast. ### I have white borders on the bottom/sides of the print preview. @@ -126,4 +127,8 @@ The Homebrewery defaults to creating US Letter page sizes. If you are printing ### Typing `#### Adhesion` in the text editor doesn't show the header at all in the completed page? -Your ad-blocking software is mistakenly assuming your text to be an ad. Whitelist homebrewery.naturalcrit.com in your ad-blocking software. +Your ad-blocking software is mistakenly assuming your text to be an ad. We recommend whitelisting homebrewery.naturalcrit.com in your ad-blocking software, as we have no ads. + +### My username appears as _hidden_ when checking my brews in the Vault, why is that? + +Your username is most likely your e-mail adress, and our code is picking that up and protecting your identity. This will remain as is, but you can ask for a name change by contacting the moderators on [the subreddit](https://www.reddit.com/r/homebrewery) with your Homebrewery username, and your desired new name. You will also be asked to provide details about some of your unpublished brews, to verify your identity. No information will be leaked or shared. From 7c096809395eeeadf31ebefe78c4d1baa9490778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Wed, 27 Nov 2024 23:45:25 +0100 Subject: [PATCH 59/75] add vault navitem to share and edit pages --- client/homebrew/pages/editPage/editPage.jsx | 2 ++ client/homebrew/pages/sharePage/sharePage.jsx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 889fd58c5..46502af23 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -16,6 +16,7 @@ const PrintNavItem = require('../../navbar/print.navitem.jsx'); const ErrorNavItem = require('../../navbar/error-navitem.jsx'); const Account = require('../../navbar/account.navitem.jsx'); const RecentNavItem = require('../../navbar/recent.navitem.jsx').both; +const VaultNavItem = require('../../navbar/vault.navitem.jsx'); const SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); const Editor = require('../../editor/editor.jsx'); @@ -417,6 +418,7 @@ const EditPage = createClass({ + diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 2d96e1ce6..04f0e3a6b 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -8,6 +8,7 @@ const Navbar = require('../../navbar/navbar.jsx'); const MetadataNav = require('../../navbar/metadata.navitem.jsx'); const PrintNavItem = require('../../navbar/print.navitem.jsx'); const RecentNavItem = require('../../navbar/recent.navitem.jsx').both; +const VaultNavItem = require('../../navbar/vault.navitem.jsx'); const Account = require('../../navbar/account.navitem.jsx'); const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); @@ -110,6 +111,7 @@ const SharePage = createClass({ } + From 7ef259ddbecf7cf3bc400f892580a6c7eb94a579 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 30 Nov 2024 17:40:38 +0000 Subject: [PATCH 60/75] Bump stylelint from 16.10.0 to 16.11.0 Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.10.0 to 16.11.0. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/16.10.0...16.11.0) --- updated-dependencies: - dependency-name: stylelint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 166 +++++++++++++++++++++++++++++----------------- package.json | 2 +- 2 files changed, 107 insertions(+), 61 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8d3b75ef9..762c8be12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,7 +61,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.10.0", + "stylelint": "^16.11.0", "stylelint-config-recess-order": "^5.1.1", "stylelint-config-recommended": "^14.0.1", "supertest": "^7.0.0" @@ -1749,9 +1749,9 @@ "license": "MIT" }, "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.1.tgz", - "integrity": "sha512-lSquqZCHxDfuTg/Sk2hiS0mcSFCEBuj49JfzPHJogDBT0mGCyY5A1AQzBWngitrp7i1/HAZpIgzF/VjhOEIJIg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", "dev": true, "funding": [ { @@ -1763,17 +1763,18 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { "node": ">=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.1" + "@csstools/css-tokenizer": "^3.0.3" } }, "node_modules/@csstools/css-tokenizer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.1.tgz", - "integrity": "sha512-UBqaiu7kU0lfvaP982/o3khfXccVlHPWp0/vwwiIgDF0GmqqqxoiXC/6FCjlS9u92f7CoEz6nXKQnrn1kIAkOw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", "dev": true, "funding": [ { @@ -1785,6 +1786,7 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { "node": ">=18" } @@ -1812,28 +1814,6 @@ "@csstools/css-tokenizer": "^3.0.1" } }, - "node_modules/@csstools/selector-specificity": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz", - "integrity": "sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss-selector-parser": "^6.1.0" - } - }, "node_modules/@dual-bundle/import-meta-resolve": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", @@ -5047,12 +5027,13 @@ } }, "node_modules/css-tree": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.0.0.tgz", - "integrity": "sha512-o88DVQ6GzsABn1+6+zo2ct801dBO5OASVyxbbvA2W20ue2puSh/VOuqUj90eUeMSX/xqGqBmOKiRQN7tJOuBXw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.0.1.tgz", + "integrity": "sha512-8Fxxv+tGhORlshCdCwnNJytvlvq46sOLSYEx2ZIGurahWvMucSRnyjPA3AmrMq4VPRYbHVpWj5VkiVasrM2H4Q==", "dev": true, + "license": "MIT", "dependencies": { - "mdn-data": "2.10.0", + "mdn-data": "2.12.1", "source-map-js": "^1.0.1" }, "engines": { @@ -10251,9 +10232,9 @@ } }, "node_modules/known-css-properties": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.34.0.tgz", - "integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==", + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", + "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", "dev": true, "license": "MIT" }, @@ -10585,10 +10566,11 @@ } }, "node_modules/mdn-data": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.10.0.tgz", - "integrity": "sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw==", - "dev": true + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.1.tgz", + "integrity": "sha512-rsfnCbOHjqrhWxwt5/wtSLzpoKTzW7OXdT5lLOIH1OTYhWu9rRJveGq0sKvDZODABH7RX+uoR+DYcpFnq4Tf6Q==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/media-typer": { "version": "0.3.0", @@ -11786,9 +11768,10 @@ } }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -11911,9 +11894,9 @@ } }, "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, "funding": [ { @@ -11929,9 +11912,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.1.0", + "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { @@ -13678,9 +13662,9 @@ "license": "ISC" }, "node_modules/stylelint": { - "version": "16.10.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.10.0.tgz", - "integrity": "sha512-z/8X2rZ52dt2c0stVwI9QL2AFJhLhbPkyfpDFcizs200V/g7v+UYY6SNcB9hKOLcDDX/yGLDsY/pX08sLkz9xQ==", + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.11.0.tgz", + "integrity": "sha512-zrl4IrKmjJQ+h9FoMp69UMCq5SxeHk0URhxUBj4d3ISzo/DplOFBJZc7t7Dr6otB+1bfbbKNLOmCDpzKSlW+Nw==", "dev": true, "funding": [ { @@ -13692,17 +13676,18 @@ "url": "https://github.com/sponsors/stylelint" } ], + "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.1", - "@csstools/css-tokenizer": "^3.0.1", - "@csstools/media-query-list-parser": "^3.0.1", - "@csstools/selector-specificity": "^4.0.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2", + "@csstools/selector-specificity": "^5.0.0", "@dual-bundle/import-meta-resolve": "^4.1.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", "css-functions-list": "^3.2.3", - "css-tree": "^3.0.0", + "css-tree": "^3.0.1", "debug": "^4.3.7", "fast-glob": "^3.3.2", "fastest-levenshtein": "^1.0.16", @@ -13714,16 +13699,16 @@ "ignore": "^6.0.2", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.34.0", + "known-css-properties": "^0.35.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", - "picocolors": "^1.0.1", - "postcss": "^8.4.47", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", "postcss-resolve-nested-selector": "^0.1.6", "postcss-safe-parser": "^7.0.1", - "postcss-selector-parser": "^6.1.2", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -13788,6 +13773,53 @@ "stylelint": "^14.0.0 || ^15.0.0 || ^16.0.1" } }, + "node_modules/stylelint/node_modules/@csstools/media-query-list-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", + "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/stylelint/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", @@ -13829,6 +13861,20 @@ "node": ">= 4" } }, + "node_modules/stylelint/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/stylelint/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", diff --git a/package.json b/package.json index ba7322cbf..f1acc238c 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", "postcss-less": "^6.0.0", - "stylelint": "^16.10.0", + "stylelint": "^16.11.0", "stylelint-config-recess-order": "^5.1.1", "stylelint-config-recommended": "^14.0.1", "supertest": "^7.0.0" From e252a39bd2e08dfd7f58ce2991edb8400dc3e71f Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 1 Dec 2024 11:41:29 -0600 Subject: [PATCH 61/75] Implement Gazook89's suggested fix --- client/homebrew/brewRenderer/brewRenderer.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 36d263040..5eba86a6a 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -217,7 +217,7 @@ const BrewRenderer = (props)=>{ } const renderedStyle = useMemo(()=>renderStyle(), [props.style, props.themeBundle]); - renderedPages = useMemo(()=>renderPages(), [props.text]); + renderedPages = useMemo(()=>renderPages(), [displayOptions.pageShadows, props.text]); return ( <> From e17db0788c0b07ff03cdcbd166ae7f3503b28993 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 2 Dec 2024 16:18:18 +1300 Subject: [PATCH 62/75] Convert any `tags` strings to arrays --- shared/helpers.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/helpers.js b/shared/helpers.js index d60da885d..e0e66fc35 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -21,6 +21,8 @@ const splitTextStyleAndMetadata = (brew)=>{ brew.snippets = brew.text.slice(11, index - 1); brew.text = brew.text.slice(index + 5); } + + if(typeof brew.tags === 'string') brew.tags = brew.tags ? [brew.tags] : []; }; const printCurrentBrew = ()=>{ From 4b21538e3ef581ea31d1205e012f487a13ea6900 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Mon, 2 Dec 2024 17:14:45 +1300 Subject: [PATCH 63/75] Add splitTextStyleAndMetadata tests --- server/homebrew.api.spec.js | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 84ffc3052..814db26f8 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -1,5 +1,7 @@ /* eslint-disable max-lines */ +import { splitTextStyleAndMetadata } from '../shared/helpers.js'; + describe('Tests for api', ()=>{ let api; let google; @@ -968,4 +970,57 @@ brew`); expect(res.send).toHaveBeenCalledWith(''); }); }); + describe('Split Text, Style, and Metadata', ()=>{ + + it('basic splitting', async ()=>{ + const testBrew = { + text : '```metadata\n' + + 'title: title\n' + + 'description: description\n' + + 'tags: [ \'tag a\' , \'tag b\' ]\n' + + 'systems: [ test system ]\n' + + 'renderer: legacy\n' + + 'theme: 5ePHB\n' + + 'lang: en\n' + + '\n' + + '```\n' + + '\n' + + '```css\n' + + 'style\n' + + 'style\n' + + 'style\n' + + '```\n' + + '\n' + + 'text\n' + }; + + splitTextStyleAndMetadata(testBrew); + + // Metadata + expect(testBrew.title).toEqual('title'); + expect(testBrew.description).toEqual('description'); + expect(testBrew.tags).toEqual(['tag a', 'tag b']); + expect(testBrew.systems).toEqual(['test system']); + expect(testBrew.renderer).toEqual('legacy'); + expect(testBrew.theme).toEqual('5ePHB'); + expect(testBrew.lang).toEqual('en'); + // Style + expect(testBrew.style).toEqual('style\nstyle\nstyle'); + // Text + expect(testBrew.text).toEqual('text\n'); + }); + + it('convert tags string to array', async ()=>{ + const testBrew = { + text : '```metadata\n' + + 'tags: tag a\n' + + '```\n\n' + }; + + splitTextStyleAndMetadata(testBrew); + + // Metadata + expect(testBrew.tags).toEqual(['tag a']); + }); + }); }); From 9f9948f5315aa7334aba0c0cb53b3382f3997a2e Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 2 Dec 2024 12:23:54 -0500 Subject: [PATCH 64/75] Add comment --- shared/helpers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/helpers.js b/shared/helpers.js index e0e66fc35..b2190cdcd 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -22,6 +22,7 @@ const splitTextStyleAndMetadata = (brew)=>{ brew.text = brew.text.slice(index + 5); } + // Handle old brews that still have empty strings in the tags metadata if(typeof brew.tags === 'string') brew.tags = brew.tags ? [brew.tags] : []; }; From 6e4e35c7ad2eea3af25de3c318433d0286836ab9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:27:52 +0000 Subject: [PATCH 65/75] Bump dompurify from 3.2.1 to 3.2.2 Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.2.1 to 3.2.2. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/3.2.1...3.2.2) --- updated-dependencies: - dependency-name: dompurify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 762c8be12..b86b657f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "cookie-parser": "^1.4.7", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", - "dompurify": "^3.2.1", + "dompurify": "^3.2.2", "expr-eval": "^2.0.2", "express": "^4.21.1", "express-async-handler": "^1.2.0", @@ -5460,9 +5460,10 @@ } }, "node_modules/dompurify": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.1.tgz", - "integrity": "sha512-NBHEsc0/kzRYQd+AY6HR6B/IgsqzBABrqJbpCDQII/OK6h7B7LXzweZTDsqSW2LkTRpoxf18YUP+YjGySk6B3w==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.2.tgz", + "integrity": "sha512-YMM+erhdZ2nkZ4fTNRTSI94mb7VG7uVF5vj5Zde7tImgnhZE3R6YW/IACGIHb2ux+QkEXMhe591N+5jWOmL4Zw==", + "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" } diff --git a/package.json b/package.json index f1acc238c..90a6306e1 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "cookie-parser": "^1.4.7", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", - "dompurify": "^3.2.1", + "dompurify": "^3.2.2", "expr-eval": "^2.0.2", "express": "^4.21.1", "express-async-handler": "^1.2.0", From 5177c9a64e397b02abc9735544bb15afbe4bbeea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:04:50 +0000 Subject: [PATCH 66/75] Bump eslint from 9.15.0 to 9.16.0 Bumps [eslint](https://github.com/eslint/eslint) from 9.15.0 to 9.16.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v9.15.0...v9.16.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 18 ++++++++++-------- package.json | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index b86b657f5..1cc2af50c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.2.1", - "eslint": "^9.15.0", + "eslint": "^9.16.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", "globals": "^15.12.0", @@ -1909,10 +1909,11 @@ } }, "node_modules/@eslint/js": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", - "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -5770,17 +5771,18 @@ "license": "MIT" }, "node_modules/eslint": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", - "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", + "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.9.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.15.0", + "@eslint/js": "9.16.0", "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", diff --git a/package.json b/package.json index 90a6306e1..bf77fbc94 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ "devDependencies": { "@stylistic/stylelint-plugin": "^3.1.1", "babel-plugin-transform-import-meta": "^2.2.1", - "eslint": "^9.15.0", + "eslint": "^9.16.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", "globals": "^15.12.0", From 23bd0309b98fb9d9edc6d893fda355fd8cb81c7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:17:58 +0000 Subject: [PATCH 67/75] Bump nanoid from 5.0.8 to 5.0.9 Bumps [nanoid](https://github.com/ai/nanoid) from 5.0.8 to 5.0.9. - [Release notes](https://github.com/ai/nanoid/releases) - [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md) - [Commits](https://github.com/ai/nanoid/compare/5.0.8...5.0.9) --- updated-dependencies: - dependency-name: nanoid dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1cc2af50c..5247ad655 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.8.3", - "nanoid": "5.0.8", + "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -11033,15 +11033,16 @@ "optional": true }, "node_modules/nanoid": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.8.tgz", - "integrity": "sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz", + "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.js" }, diff --git a/package.json b/package.json index bf77fbc94..4c65c529a 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", "mongoose": "^8.8.3", - "nanoid": "5.0.8", + "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", "react-dom": "^18.3.1", From 4e5a971f0a5da700175c0482d50ed8c9b46498d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:22:41 +0000 Subject: [PATCH 68/75] Bump globals from 15.12.0 to 15.13.0 Bumps [globals](https://github.com/sindresorhus/globals) from 15.12.0 to 15.13.0. - [Release notes](https://github.com/sindresorhus/globals/releases) - [Commits](https://github.com/sindresorhus/globals/compare/v15.12.0...v15.13.0) --- updated-dependencies: - dependency-name: globals dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5247ad655..3a4fc600c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,7 +56,7 @@ "eslint": "^9.16.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", - "globals": "^15.12.0", + "globals": "^15.13.0", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", @@ -6959,10 +6959,11 @@ } }, "node_modules/globals": { - "version": "15.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz", - "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==", + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", + "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, diff --git a/package.json b/package.json index 4c65c529a..ccc557f75 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "eslint": "^9.16.0", "eslint-plugin-jest": "^28.9.0", "eslint-plugin-react": "^7.37.2", - "globals": "^15.12.0", + "globals": "^15.13.0", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", "jsdom-global": "^3.0.2", From c62bb5366095bc025981a296cdc6a394a9b7246f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Tue, 3 Dec 2024 20:16:42 +0100 Subject: [PATCH 69/75] turn back checkboxes to default, fix button styles and filter bar to correct font. --- .../homebrew/pages/vaultPage/vaultPage.less | 44 ++----------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/client/homebrew/pages/vaultPage/vaultPage.less b/client/homebrew/pages/vaultPage/vaultPage.less index d29a5f4e1..a69bcb33b 100644 --- a/client/homebrew/pages/vaultPage/vaultPage.less +++ b/client/homebrew/pages/vaultPage/vaultPage.less @@ -92,49 +92,11 @@ &:invalid { background : rgb(255, 188, 181); } - &[type='checkbox'] { - position : relative; - display : inline-block; - width : 50px; - height : 30px; - font-family : 'WalterTurncoat'; - font-size : 20px; - font-weight : 800; - color : white; - letter-spacing : 2px; - appearance : none; - background : red; - isolation : isolate; - border-radius : 5px; - - &::before,&::after { - position : absolute; - inset : 0; - z-index : 5; - padding-top : 2px; - text-align : center; - } - - &::before { - display : block; - content : 'No'; - } - - &::after { - display : none; - content : 'Yes'; - } - - &:checked { - background : green; - - &::before { display : none; } - &::after { display : block; } - } - } + } #searchButton { + .colorButton(@green); position : absolute; right : 20px; bottom : 0; @@ -152,7 +114,6 @@ flex-direction : column; height : 100%; overflow-y : auto; - font-family : 'BookInsanityRemake'; font-size : 0.34cm; h3 { @@ -356,6 +317,7 @@ } button { + .colorButton(@green); width : max-content; &.previousPage { grid-area : previousPage; } From 14a0f79ac8d604704663776e93dcadf7a3ff745d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 03:16:54 +0000 Subject: [PATCH 70/75] Bump @babel/preset-react from 7.25.9 to 7.26.3 Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.25.9 to 7.26.3. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.3/packages/babel-preset-react) --- updated-dependencies: - dependency-name: "@babel/preset-react" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a4fc600c..d823b571f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@babel/core": "^7.26.0", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", - "@babel/preset-react": "^7.25.9", + "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^8.14.0", "body-parser": "^1.20.2", "classnames": "^2.5.1", @@ -1661,9 +1661,10 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.9.tgz", - "integrity": "sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", + "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-validator-option": "^7.25.9", diff --git a/package.json b/package.json index ccc557f75..f8d34800d 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "@babel/core": "^7.26.0", "@babel/plugin-transform-runtime": "^7.25.9", "@babel/preset-env": "^7.26.0", - "@babel/preset-react": "^7.25.9", + "@babel/preset-react": "^7.26.3", "@googleapis/drive": "^8.14.0", "body-parser": "^1.20.2", "classnames": "^2.5.1", From 3178c8722e204f8e803ab1bd34ece8d745db91d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2024 03:07:01 +0000 Subject: [PATCH 71/75] Bump mongoose from 8.8.3 to 8.8.4 Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.3 to 8.8.4. - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/8.8.3...8.8.4) --- updated-dependencies: - dependency-name: mongoose dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a4fc600c..034fe5659 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.8.3", + "mongoose": "^8.8.4", "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", @@ -10877,9 +10877,9 @@ } }, "node_modules/mongoose": { - "version": "8.8.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.3.tgz", - "integrity": "sha512-/I4n/DcXqXyIiLRfAmUIiTjj3vXfeISke8dt4U4Y8Wfm074Wa6sXnQrXN49NFOFf2mM1kUdOXryoBvkuCnr+Qw==", + "version": "8.8.4", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.4.tgz", + "integrity": "sha512-yJbn695qCsqDO+xyPII29x2R7flzXhxCDv09mMZPSGllf0sm4jKw3E9s9uvQ9hjO6bL2xjU8KKowYqcY9eSTMQ==", "license": "MIT", "dependencies": { "bson": "^6.7.0", diff --git a/package.json b/package.json index ccc557f75..9bce9981c 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.8.3", + "mongoose": "^8.8.4", "nanoid": "5.0.9", "nconf": "^0.12.1", "react": "^18.3.1", From ffa9666bb99a3f3ec9394b43d21a4b4e8514e05c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2024 21:29:54 +0000 Subject: [PATCH 72/75] Bump express from 4.21.1 to 4.21.2 Bumps [express](https://github.com/expressjs/express) from 4.21.1 to 4.21.2. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md) - [Commits](https://github.com/expressjs/express/compare/4.21.1...4.21.2) --- updated-dependencies: - dependency-name: express dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 22 ++++++++++++++-------- package.json | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index d823b571f..820e01c46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "dedent-tabs": "^0.10.3", "dompurify": "^3.2.2", "expr-eval": "^2.0.2", - "express": "^4.21.1", + "express": "^4.21.2", "express-async-handler": "^1.2.0", "express-static-gzip": "2.2.0", "fs-extra": "11.2.0", @@ -6254,9 +6254,10 @@ "license": "MIT" }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -6277,7 +6278,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -6292,6 +6293,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express-async-handler": { @@ -11743,9 +11748,10 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", diff --git a/package.json b/package.json index f8d34800d..d5ea0b1de 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "dedent-tabs": "^0.10.3", "dompurify": "^3.2.2", "expr-eval": "^2.0.2", - "express": "^4.21.1", + "express": "^4.21.2", "express-async-handler": "^1.2.0", "express-static-gzip": "2.2.0", "fs-extra": "11.2.0", From 74a79837576bf5de0242ecc42374bbfbf5c5eb15 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 8 Dec 2024 23:39:26 -0500 Subject: [PATCH 73/75] Refactor and clean up "getBrew()" Some redundant logic and sprawling formatting --- server/homebrew.api.js | 70 ++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index b8d4024ad..f536ec45e 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -87,76 +87,66 @@ const api = { // Create middleware with the accessType passed in as part of the scope return async (req, res, next)=>{ // Get relevant IDs for the brew - const { id, googleId } = api.getId(req); + let { id, googleId } = api.getId(req); const accessMap = { edit : { editId: id }, share : { shareId: id }, - admin : { - $or : [ - { editId: id }, - { 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. let stub = await HomebrewModel.get(accessMap[accessType]) .catch((err)=>{ - if(googleId) { + if(googleId) console.warn(`Unable to find document stub for ${accessType}Id ${id}`); - } else { + else console.warn(err); - } }); stub = stub?.toObject(); + googleId ??= stub?.googleId; + + const isAuthor = stub?.authors?.includes(req.account?.username); + const isInvited = stub?.invitedAuthors?.includes(req.account?.username); + + if(accessType === 'edit' && !(isOwner || isAuthor || isInvited)) { + const accessError = { name: 'Access Error', status: 401, authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId }; + if(req.account) + throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03' }; + else + throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04' }; + } if(stub?.lock?.locked && accessType != 'edit') { throw { HBErrorCode: '51', code: stub.lock.code, message: stub.lock.shareMessage, brewId: stub.shareId, brewTitle: stub.title }; } // If there is a google id, try to find the google brew - if(!stubOnly && (googleId || stub?.googleId)) { - let googleError; const googleBrew = await GoogleActions.getGoogleBrew(googleId || stub?.googleId, id, accessType) - .catch((err)=>{ - googleError = err; + if(!stubOnly && googleId) { + + .catch((googleError)=>{ + const reason = googleError.errors?.[0].reason; + if(reason == 'notFound') + throw { ...googleError, HBErrorCode: '02', authors: stub?.authors, account: req.account?.username }; + else + throw { ...googleError, HBErrorCode: '01' }; }); - // Throw any error caught while attempting to retrieve Google brew. - if(googleError) { - const reason = googleError.errors?.[0].reason; - if(reason == 'notFound') { - throw { ...googleError, HBErrorCode: '02', authors: stub?.authors, account: req.account?.username }; - } else { - throw { ...googleError, HBErrorCode: '01' }; - } - } + // Combine the Homebrewery stub with the google brew, or if the stub doesn't exist just use the google brew stub = stub ? _.assign({ ...api.excludeStubProps(stub), stubbed: true }, api.excludeGoogleProps(googleBrew)) : googleBrew; } - const authorsExist = stub?.authors?.length > 0; - const isAuthor = stub?.authors?.includes(req.account?.username); - const isInvited = stub?.invitedAuthors?.includes(req.account?.username); - if(accessType === 'edit' && (authorsExist && !(isAuthor || isInvited))) { - const accessError = { name: 'Access Error', status: 401 }; - if(req.account){ - throw { ...accessError, message: 'User is not an Author', HBErrorCode: '03', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId }; - } - throw { ...accessError, message: 'User is not logged in', HBErrorCode: '04', authors: stub.authors, brewTitle: stub.title, shareId: stub.shareId }; - } // If after all of that we still don't have a brew, throw an exception - if(!stub && !stubOnly) { + if(!stub) throw { name: 'BrewLoad Error', message: 'Brew not found', status: 404, HBErrorCode: '05', accessType: accessType, brewId: id }; - } // Clean up brew: fill in missing fields with defaults / fix old invalid values - if(stub) { - stub.tags = stub.tags || undefined; // Clear empty strings - stub.renderer = stub.renderer || undefined; // Clear empty strings - stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields - } + stub.tags = stub.tags || undefined; // Clear empty strings + stub.renderer = stub.renderer || undefined; // Clear empty strings + stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields - req.brew = stub ?? {}; + req.brew = stub; next(); }; }, From 9758797e2b1c887e335f12680f91b645a809b864 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 8 Dec 2024 23:42:14 -0500 Subject: [PATCH 74/75] If user is owner, fetch Google Brew with user auth Fixes the case where a user can see a Google Brew under their account (`listBrew()` uses their personal auth) but can't actually delete it (`getBrew()` only uses the serviceAccount). Occurs if a Google brew has lost its permissions somehow (set to "restricted", etc.) such that serviceAccount can no longer interact with it. --- server/googleActions.js | 4 ++-- server/homebrew.api.js | 4 +++- server/homebrew.api.spec.js | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/server/googleActions.js b/server/googleActions.js index ec541e5f5..51da56218 100644 --- a/server/googleActions.js +++ b/server/googleActions.js @@ -241,8 +241,8 @@ const GoogleActions = { return obj.data.id; }, - getGoogleBrew : async (id, accessId, accessType)=>{ - const drive = googleDrive.drive({ version: 'v3', auth: defaultAuth }); + getGoogleBrew : async (auth, id, accessId, accessType)=>{ + const drive = googleDrive.drive({ version: 'v3', auth: auth || defaultAuth }); const obj = await drive.files.get({ fileId : id, diff --git a/server/homebrew.api.js b/server/homebrew.api.js index f536ec45e..a75887742 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -106,6 +106,7 @@ const api = { stub = stub?.toObject(); googleId ??= stub?.googleId; + const isOwner = stub?.authors?.length === 0 || stub?.authors?.[0] === req.account?.username; const isAuthor = stub?.authors?.includes(req.account?.username); const isInvited = stub?.invitedAuthors?.includes(req.account?.username); @@ -122,9 +123,10 @@ const api = { } // If there is a google id, try to find the google brew - const googleBrew = await GoogleActions.getGoogleBrew(googleId || stub?.googleId, id, accessType) if(!stubOnly && googleId) { + const oAuth2Client = isOwner? GoogleActions.authCheck(req.account, res) : undefined; + const googleBrew = await GoogleActions.getGoogleBrew(oAuth2Client, googleId, id, accessType) .catch((googleError)=>{ const reason = googleError.errors?.[0].reason; if(reason == 'notFound') diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 814db26f8..8270b1568 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -298,7 +298,7 @@ describe('Tests for api', ()=>{ expect(next).toHaveBeenCalled(); expect(api.getId).toHaveBeenCalledWith(req); expect(model.get).toHaveBeenCalledWith({ shareId: '1' }); - expect(google.getGoogleBrew).toHaveBeenCalledWith('2', '1', 'share'); + expect(google.getGoogleBrew).toHaveBeenCalledWith(undefined, '2', '1', 'share'); }); it('access is denied to a locked brew', async()=>{ From c7d94b077963fd5b964053ac84c95f5f7c8f350f Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 8 Dec 2024 23:59:27 -0500 Subject: [PATCH 75/75] Small cleanup --- server/googleActions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/googleActions.js b/server/googleActions.js index 51da56218..2c2cbac73 100644 --- a/server/googleActions.js +++ b/server/googleActions.js @@ -241,8 +241,8 @@ const GoogleActions = { return obj.data.id; }, - getGoogleBrew : async (auth, id, accessId, accessType)=>{ - const drive = googleDrive.drive({ version: 'v3', auth: auth || defaultAuth }); + getGoogleBrew : async (auth = defaultAuth, id, accessId, accessType)=>{ + const drive = googleDrive.drive({ version: 'v3', auth: auth }); const obj = await drive.files.get({ fileId : id,