mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-06 14:22:52 +00:00
Merge branch 'master' into localSnippetEditor
This commit is contained in:
25
.github/pull_request_template.md
vendored
25
.github/pull_request_template.md
vendored
@@ -1,26 +1,29 @@
|
|||||||
<!--
|
> [!TIP]
|
||||||
Before submitting a Pull Request, please consider the following to speed up reviews:
|
> Before submitting a Pull Request, please consider the following to speed up reviews:
|
||||||
- 👷♀️ Create small PRs. Large PRs can usually be broken down into incremental PRs.
|
> - 👷♀️ Create small PRs. Large PRs can usually be broken down into incremental PRs.
|
||||||
- 🚩 Do you already have several open PRs? Consider finishing or asking for help with existing PRs first.
|
> - 🚩 Do you already have several open PRs? Consider finishing or asking for help with existing PRs first.
|
||||||
- 🔧 Does your PR reference a discussed and approved issue, especially for personal or edge-case requests?
|
> - 🔧 Does your PR reference a discussed and approved issue, especially for personal or edge-case requests?
|
||||||
- 💡 Is the solution agreed upon? Save rework time by discussing strategy before coding.
|
> - 💡 Is the solution agreed upon? Save rework time by discussing strategy before coding.
|
||||||
-->
|
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
|
_Describe what your PR accomplishes. Consider walking through the main changes to aid reviewers in following your code, especially if it covers multiple files._
|
||||||
|
|
||||||
## Related Issues or Discussions
|
## Related Issues or Discussions
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> If no issue exists yet, create it, and get agreement on the approach (or paste in a previous agreement from chat, etc.) before moving forward. (Experimental PRs are OK without prior discussion, but do not expect to get merged.)
|
||||||
|
|
||||||
- Closes #
|
- Closes #
|
||||||
|
|
||||||
## QA Instructions, Screenshots, Recordings
|
## QA Instructions, Screenshots, Recordings
|
||||||
|
|
||||||
_Please replace this line with instructions on how to test or view your changes, as well as any before/after
|
_Replace this line with instructions on how to test or view your changes, as well as any before/after
|
||||||
images for UI changes._
|
screenshots or recordings for UI changes._
|
||||||
|
|
||||||
### Reviewer Checklist
|
### Reviewer Checklist
|
||||||
|
|
||||||
_Please replace the list below with specific features you want reviewers to look at._
|
_Replace the list below with specific features you want reviewers to look at._
|
||||||
|
|
||||||
*Reviewers, refer to this list when testing features, or suggest new items *
|
*Reviewers, refer to this list when testing features, or suggest new items *
|
||||||
- [ ] Verify new features are functional
|
- [ ] Verify new features are functional
|
||||||
@@ -32,5 +35,3 @@ _Please replace the list below with specific features you want reviewers to look
|
|||||||
- [ ] Feature A handles negative numbers
|
- [ ] Feature A handles negative numbers
|
||||||
- [ ] Identify opportunities for simplification and refactoring
|
- [ ] Identify opportunities for simplification and refactoring
|
||||||
- [ ] Check for code legibility and appropriate comments
|
- [ ] Check for code legibility and appropriate comments
|
||||||
|
|
||||||
<details><summary>Copy this list</summary>
|
|
||||||
|
|||||||
@@ -115,10 +115,10 @@
|
|||||||
color : #D3D3D3;
|
color : #D3D3D3;
|
||||||
accent-color : #D3D3D3;
|
accent-color : #D3D3D3;
|
||||||
|
|
||||||
&::-webkit-slider-thumb, &::-moz-slider-thumb {
|
&::-webkit-slider-thumb, &::-moz-range-thumb {
|
||||||
width : 5px;
|
width : 5px;
|
||||||
height : 5px;
|
height : 5px;
|
||||||
cursor : pointer;
|
cursor : ew-resize;
|
||||||
outline : none;
|
outline : none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -217,19 +217,11 @@ const Snippetbar = createClass({
|
|||||||
renderEditorButtons : function(){
|
renderEditorButtons : function(){
|
||||||
if(!this.props.showEditButtons) return;
|
if(!this.props.showEditButtons) return;
|
||||||
|
|
||||||
const foldButtons = <>
|
|
||||||
<div className={`editorTool foldAll ${this.props.view !== 'meta' && this.props.foldCode ? 'active' : ''}`}
|
|
||||||
onClick={this.props.foldCode} >
|
|
||||||
<i className='fas fa-compress-alt' />
|
|
||||||
</div>
|
|
||||||
<div className={`editorTool unfoldAll ${this.props.view !== 'meta' && this.props.unfoldCode ? 'active' : ''}`}
|
|
||||||
onClick={this.props.unfoldCode} >
|
|
||||||
<i className='fas fa-expand-alt' />
|
|
||||||
</div>
|
|
||||||
</>;
|
|
||||||
|
|
||||||
return <div className='editors'>
|
return (
|
||||||
<div className='historyTools'>
|
<div className='editors'>
|
||||||
|
{this.props.view !== 'meta' && <><div className='historyTools'>
|
||||||
<div className={`editorTool snippetGroup history ${this.state.historyExists ? 'active' : ''}`}
|
<div className={`editorTool snippetGroup history ${this.state.historyExists ? 'active' : ''}`}
|
||||||
onClick={this.toggleHistoryMenu} >
|
onClick={this.toggleHistoryMenu} >
|
||||||
<i className='fas fa-clock-rotate-left' />
|
<i className='fas fa-clock-rotate-left' />
|
||||||
@@ -245,14 +237,21 @@ const Snippetbar = createClass({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='codeTools'>
|
<div className='codeTools'>
|
||||||
{foldButtons}
|
<div className={`editorTool foldAll ${this.props.foldCode ? 'active' : ''}`}
|
||||||
<div className={`editorTool editorTheme ${this.state.themeSelector ? 'active' : ''}`}
|
onClick={this.props.foldCode} >
|
||||||
|
<i className='fas fa-compress-alt' />
|
||||||
|
</div>
|
||||||
|
<div className={`editorTool unfoldAll ${this.props.unfoldCode ? 'active' : ''}`}
|
||||||
|
onClick={this.props.unfoldCode} >
|
||||||
|
<i className='fas fa-expand-alt' />
|
||||||
|
</div>
|
||||||
|
<div className={`editorTheme ${this.state.themeSelector ? 'active' : ''}`}
|
||||||
onClick={this.toggleThemeSelector} >
|
onClick={this.toggleThemeSelector} >
|
||||||
<i className='fas fa-palette' />
|
<i className='fas fa-palette' />
|
||||||
{this.state.themeSelector && this.renderThemeSelector()}
|
{this.state.themeSelector && this.renderThemeSelector()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div></>}
|
||||||
|
|
||||||
|
|
||||||
<div className='tabs'>
|
<div className='tabs'>
|
||||||
<div className={cx('text', { selected: this.props.view === 'text' })}
|
<div className={cx('text', { selected: this.props.view === 'text' })}
|
||||||
@@ -273,7 +272,8 @@ const Snippetbar = createClass({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>;
|
</div>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
justify-content : flex-end;
|
justify-content : flex-end;
|
||||||
min-width : 225px;
|
min-width : 225px;
|
||||||
|
|
||||||
&:only-child { margin-left : auto; }
|
&:only-child { margin-left : auto;min-width:unset;}
|
||||||
|
|
||||||
>div {
|
>div {
|
||||||
display : flex;
|
display : flex;
|
||||||
@@ -38,6 +38,11 @@
|
|||||||
line-height : @menuHeight;
|
line-height : @menuHeight;
|
||||||
text-align : center;
|
text-align : center;
|
||||||
cursor : pointer;
|
cursor : pointer;
|
||||||
|
|
||||||
|
&.editorTool:not(.active) {
|
||||||
|
cursor:not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover,&.selected { background-color : #999999; }
|
&:hover,&.selected { background-color : #999999; }
|
||||||
&.text {
|
&.text {
|
||||||
.tooltipLeft('Brew Editor');
|
.tooltipLeft('Brew Editor');
|
||||||
|
|||||||
47
package-lock.json
generated
47
package-lock.json
generated
@@ -13,7 +13,7 @@
|
|||||||
"@babel/core": "^7.26.0",
|
"@babel/core": "^7.26.0",
|
||||||
"@babel/plugin-transform-runtime": "^7.25.9",
|
"@babel/plugin-transform-runtime": "^7.25.9",
|
||||||
"@babel/preset-env": "^7.26.0",
|
"@babel/preset-env": "^7.26.0",
|
||||||
"@babel/preset-react": "^7.25.9",
|
"@babel/preset-react": "^7.26.3",
|
||||||
"@googleapis/drive": "^8.14.0",
|
"@googleapis/drive": "^8.14.0",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
@@ -21,9 +21,9 @@
|
|||||||
"cookie-parser": "^1.4.7",
|
"cookie-parser": "^1.4.7",
|
||||||
"create-react-class": "^15.7.0",
|
"create-react-class": "^15.7.0",
|
||||||
"dedent-tabs": "^0.10.3",
|
"dedent-tabs": "^0.10.3",
|
||||||
"dompurify": "^3.2.2",
|
"dompurify": "^3.2.3",
|
||||||
"expr-eval": "^2.0.2",
|
"expr-eval": "^2.0.2",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.2",
|
||||||
"express-async-handler": "^1.2.0",
|
"express-async-handler": "^1.2.0",
|
||||||
"express-static-gzip": "2.2.0",
|
"express-static-gzip": "2.2.0",
|
||||||
"fs-extra": "11.2.0",
|
"fs-extra": "11.2.0",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"marked-smartypants-lite": "^1.0.2",
|
"marked-smartypants-lite": "^1.0.2",
|
||||||
"markedLegacy": "npm:marked@^0.3.19",
|
"markedLegacy": "npm:marked@^0.3.19",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"mongoose": "^8.8.3",
|
"mongoose": "^8.8.4",
|
||||||
"nanoid": "5.0.9",
|
"nanoid": "5.0.9",
|
||||||
"nconf": "^0.12.1",
|
"nconf": "^0.12.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
@@ -1660,9 +1660,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/preset-react": {
|
"node_modules/@babel/preset-react": {
|
||||||
"version": "7.25.9",
|
"version": "7.26.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz",
|
||||||
"integrity": "sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==",
|
"integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.25.9",
|
"@babel/helper-plugin-utils": "^7.25.9",
|
||||||
"@babel/helper-validator-option": "^7.25.9",
|
"@babel/helper-validator-option": "^7.25.9",
|
||||||
@@ -5475,9 +5476,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dompurify": {
|
"node_modules/dompurify": {
|
||||||
"version": "3.2.2",
|
"version": "3.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.3.tgz",
|
||||||
"integrity": "sha512-YMM+erhdZ2nkZ4fTNRTSI94mb7VG7uVF5vj5Zde7tImgnhZE3R6YW/IACGIHb2ux+QkEXMhe591N+5jWOmL4Zw==",
|
"integrity": "sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==",
|
||||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@types/trusted-types": "^2.0.7"
|
"@types/trusted-types": "^2.0.7"
|
||||||
@@ -6269,9 +6270,10 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/express": {
|
"node_modules/express": {
|
||||||
"version": "4.21.1",
|
"version": "4.21.2",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||||
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
|
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "~1.3.8",
|
"accepts": "~1.3.8",
|
||||||
"array-flatten": "1.1.1",
|
"array-flatten": "1.1.1",
|
||||||
@@ -6292,7 +6294,7 @@
|
|||||||
"methods": "~1.1.2",
|
"methods": "~1.1.2",
|
||||||
"on-finished": "2.4.1",
|
"on-finished": "2.4.1",
|
||||||
"parseurl": "~1.3.3",
|
"parseurl": "~1.3.3",
|
||||||
"path-to-regexp": "0.1.10",
|
"path-to-regexp": "0.1.12",
|
||||||
"proxy-addr": "~2.0.7",
|
"proxy-addr": "~2.0.7",
|
||||||
"qs": "6.13.0",
|
"qs": "6.13.0",
|
||||||
"range-parser": "~1.2.1",
|
"range-parser": "~1.2.1",
|
||||||
@@ -6307,6 +6309,10 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express-async-handler": {
|
"node_modules/express-async-handler": {
|
||||||
@@ -10902,9 +10908,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mongoose": {
|
"node_modules/mongoose": {
|
||||||
"version": "8.8.3",
|
"version": "8.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.4.tgz",
|
||||||
"integrity": "sha512-/I4n/DcXqXyIiLRfAmUIiTjj3vXfeISke8dt4U4Y8Wfm074Wa6sXnQrXN49NFOFf2mM1kUdOXryoBvkuCnr+Qw==",
|
"integrity": "sha512-yJbn695qCsqDO+xyPII29x2R7flzXhxCDv09mMZPSGllf0sm4jKw3E9s9uvQ9hjO6bL2xjU8KKowYqcY9eSTMQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bson": "^6.7.0",
|
"bson": "^6.7.0",
|
||||||
@@ -11772,9 +11778,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-to-regexp": {
|
"node_modules/path-to-regexp": {
|
||||||
"version": "0.1.10",
|
"version": "0.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w=="
|
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/path-type": {
|
"node_modules/path-type": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
|
|||||||
@@ -85,7 +85,7 @@
|
|||||||
"@babel/core": "^7.26.0",
|
"@babel/core": "^7.26.0",
|
||||||
"@babel/plugin-transform-runtime": "^7.25.9",
|
"@babel/plugin-transform-runtime": "^7.25.9",
|
||||||
"@babel/preset-env": "^7.26.0",
|
"@babel/preset-env": "^7.26.0",
|
||||||
"@babel/preset-react": "^7.25.9",
|
"@babel/preset-react": "^7.26.3",
|
||||||
"@googleapis/drive": "^8.14.0",
|
"@googleapis/drive": "^8.14.0",
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
@@ -93,9 +93,9 @@
|
|||||||
"cookie-parser": "^1.4.7",
|
"cookie-parser": "^1.4.7",
|
||||||
"create-react-class": "^15.7.0",
|
"create-react-class": "^15.7.0",
|
||||||
"dedent-tabs": "^0.10.3",
|
"dedent-tabs": "^0.10.3",
|
||||||
"dompurify": "^3.2.2",
|
"dompurify": "^3.2.3",
|
||||||
"expr-eval": "^2.0.2",
|
"expr-eval": "^2.0.2",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.2",
|
||||||
"express-async-handler": "^1.2.0",
|
"express-async-handler": "^1.2.0",
|
||||||
"express-static-gzip": "2.2.0",
|
"express-static-gzip": "2.2.0",
|
||||||
"fs-extra": "11.2.0",
|
"fs-extra": "11.2.0",
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
"marked-smartypants-lite": "^1.0.2",
|
"marked-smartypants-lite": "^1.0.2",
|
||||||
"markedLegacy": "npm:marked@^0.3.19",
|
"markedLegacy": "npm:marked@^0.3.19",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"mongoose": "^8.8.3",
|
"mongoose": "^8.8.4",
|
||||||
"nanoid": "5.0.9",
|
"nanoid": "5.0.9",
|
||||||
"nconf": "^0.12.1",
|
"nconf": "^0.12.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
|
|||||||
@@ -241,8 +241,8 @@ const GoogleActions = {
|
|||||||
return obj.data.id;
|
return obj.data.id;
|
||||||
},
|
},
|
||||||
|
|
||||||
getGoogleBrew : async (id, accessId, accessType)=>{
|
getGoogleBrew : async (auth = defaultAuth, id, accessId, accessType)=>{
|
||||||
const drive = googleDrive.drive({ version: 'v3', auth: defaultAuth });
|
const drive = googleDrive.drive({ version: 'v3', auth: auth });
|
||||||
|
|
||||||
const obj = await drive.files.get({
|
const obj = await drive.files.get({
|
||||||
fileId : id,
|
fileId : id,
|
||||||
|
|||||||
@@ -89,76 +89,68 @@ const api = {
|
|||||||
// Create middleware with the accessType passed in as part of the scope
|
// Create middleware with the accessType passed in as part of the scope
|
||||||
return async (req, res, next)=>{
|
return async (req, res, next)=>{
|
||||||
// Get relevant IDs for the brew
|
// Get relevant IDs for the brew
|
||||||
const { id, googleId } = api.getId(req);
|
let { id, googleId } = api.getId(req);
|
||||||
|
|
||||||
const accessMap = {
|
const accessMap = {
|
||||||
edit : { editId: id },
|
edit : { editId: id },
|
||||||
share : { shareId: id },
|
share : { shareId: id },
|
||||||
admin : {
|
admin : { $or : [{ editId: id }, { shareId: id }] }
|
||||||
$or : [
|
|
||||||
{ editId: id },
|
|
||||||
{ shareId: id },
|
|
||||||
] }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine.
|
// Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine.
|
||||||
let stub = await HomebrewModel.get(accessMap[accessType])
|
let stub = await HomebrewModel.get(accessMap[accessType])
|
||||||
.catch((err)=>{
|
.catch((err)=>{
|
||||||
if(googleId) {
|
if(googleId)
|
||||||
console.warn(`Unable to find document stub for ${accessType}Id ${id}`);
|
console.warn(`Unable to find document stub for ${accessType}Id ${id}`);
|
||||||
} else {
|
else
|
||||||
console.warn(err);
|
console.warn(err);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
stub = stub?.toObject();
|
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);
|
||||||
|
|
||||||
|
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') {
|
if(stub?.lock?.locked && accessType != 'edit') {
|
||||||
throw { HBErrorCode: '51', code: stub.lock.code, message: stub.lock.shareMessage, brewId: stub.shareId, brewTitle: stub.title };
|
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 there is a google id, try to find the google brew
|
||||||
if(!stubOnly && (googleId || stub?.googleId)) {
|
if(!stubOnly && googleId) {
|
||||||
let googleError;
|
const oAuth2Client = isOwner? GoogleActions.authCheck(req.account, res) : undefined;
|
||||||
const googleBrew = await GoogleActions.getGoogleBrew(googleId || stub?.googleId, id, accessType)
|
|
||||||
.catch((err)=>{
|
const googleBrew = await GoogleActions.getGoogleBrew(oAuth2Client, googleId, id, accessType)
|
||||||
googleError = err;
|
.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
|
// 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;
|
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 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 };
|
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
|
// Clean up brew: fill in missing fields with defaults / fix old invalid values
|
||||||
if(stub) {
|
stub.tags = stub.tags || undefined; // Clear empty strings
|
||||||
stub.tags = stub.tags || undefined; // Clear empty strings
|
stub.renderer = stub.renderer || undefined; // Clear empty strings
|
||||||
stub.renderer = stub.renderer || undefined; // Clear empty strings
|
stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields
|
||||||
stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields
|
|
||||||
}
|
|
||||||
|
|
||||||
req.brew = stub ?? {};
|
req.brew = stub;
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ describe('Tests for api', ()=>{
|
|||||||
expect(next).toHaveBeenCalled();
|
expect(next).toHaveBeenCalled();
|
||||||
expect(api.getId).toHaveBeenCalledWith(req);
|
expect(api.getId).toHaveBeenCalledWith(req);
|
||||||
expect(model.get).toHaveBeenCalledWith({ shareId: '1' });
|
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()=>{
|
it('access is denied to a locked brew', async()=>{
|
||||||
|
|||||||
@@ -11,49 +11,54 @@
|
|||||||
@import (less) './themes/fonts/iconFonts/fontAwesome.less';
|
@import (less) './themes/fonts/iconFonts/fontAwesome.less';
|
||||||
|
|
||||||
@keyframes sourceMoveAnimation {
|
@keyframes sourceMoveAnimation {
|
||||||
50% {background-color: red; color: white;}
|
50% { color : white;background-color : red;}
|
||||||
100% {background-color: unset; color: unset;}
|
100% { color : unset;background-color : unset;}
|
||||||
}
|
}
|
||||||
|
|
||||||
.codeEditor{
|
.codeEditor {
|
||||||
@media screen and (pointer : coarse) {
|
@media screen and (pointer : coarse) {
|
||||||
font-size : 16px;
|
font-size : 16px;
|
||||||
}
|
}
|
||||||
.CodeMirror-foldmarker {
|
.CodeMirror-foldmarker {
|
||||||
font-family: inherit;
|
font-family : inherit;
|
||||||
text-shadow: none;
|
font-weight : 600;
|
||||||
font-weight: 600;
|
color : grey;
|
||||||
color: grey;
|
text-shadow : none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sourceMoveFlash .CodeMirror-line{
|
.CodeMirror-foldgutter {
|
||||||
animation-name: sourceMoveAnimation;
|
cursor : pointer;
|
||||||
animation-duration: 0.4s;
|
border-left : 1px solid #EEEEEE;
|
||||||
}
|
transition : background 0.1s;
|
||||||
|
&:hover { background : #DDDDDD; }
|
||||||
|
}
|
||||||
|
|
||||||
.CodeMirror-vscrollbar {
|
.sourceMoveFlash .CodeMirror-line {
|
||||||
&::-webkit-scrollbar {
|
animation-name : sourceMoveAnimation;
|
||||||
width: 20px;
|
animation-duration : 0.4s;
|
||||||
}
|
}
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
width: 20px;
|
.CodeMirror-vscrollbar {
|
||||||
background: linear-gradient(90deg, #858585 15px, #808080 15px);
|
&::-webkit-scrollbar { width : 20px; }
|
||||||
}
|
&::-webkit-scrollbar-thumb {
|
||||||
}
|
width : 20px;
|
||||||
|
background : linear-gradient(90deg, #858585 15px, #808080 15px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//.cm-tab {
|
//.cm-tab {
|
||||||
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right;
|
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//.cm-trailingspace {
|
//.cm-trailingspace {
|
||||||
// .cm-space {
|
// .cm-space {
|
||||||
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) no-repeat right;
|
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) no-repeat right;
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
.emojiPreview {
|
.emojiPreview {
|
||||||
font-size: 1.5em;
|
font-size : 1.5em;
|
||||||
line-height: 1.2em;
|
line-height : 1.2em;
|
||||||
}
|
}
|
||||||
@@ -43,5 +43,6 @@ html,body, #reactRoot{
|
|||||||
}
|
}
|
||||||
&:disabled{
|
&:disabled{
|
||||||
background-color : @silver !important;
|
background-color : @silver !important;
|
||||||
|
cursor:not-allowed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user