0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-24 03:23:02 +00:00

Compare commits

...

89 Commits

Author SHA1 Message Date
Trevor Buckner
fde21868cd Add emoji tests to circleci 2024-12-19 23:20:01 -05:00
Trevor Buckner
980a7bd57e Merge pull request #3954 from naturalcrit/dependabot/npm_and_yarn/globals-15.14.0
Bump globals from 15.13.0 to 15.14.0
2024-12-18 23:52:01 -05:00
Trevor Buckner
6b0022ad00 Merge branch 'master' into dependabot/npm_and_yarn/globals-15.14.0 2024-12-18 23:22:22 -05:00
Trevor Buckner
0f33973e58 Merge pull request #3953 from G-Ambatte/fixAdminAddedAsAuthor-#3952
Fix admin added as author #3952
2024-12-18 23:22:06 -05:00
G.Ambatte
7a41a140fd Merge branch 'master' into fixAdminAddedAsAuthor-#3952 2024-12-19 17:00:26 +13:00
Trevor Buckner
57467701d0 Fetch Google Brew if only stub requested but nothing found
/update/ requests only the stub for updating. But if no stub exists, we should fetch the full brew so we return *something*.
2024-12-18 23:00:01 -05:00
dependabot[bot]
9dbfb26e6c Bump globals from 15.13.0 to 15.14.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.13.0 to 15.14.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.13.0...v15.14.0)

---
updated-dependencies:
- dependency-name: globals
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-19 03:47:25 +00:00
G.Ambatte
7a169cbd9e Linter clean up 2024-12-19 16:20:28 +13:00
G.Ambatte
2dc8a8fbe9 Remove req.account from update request 2024-12-19 16:20:04 +13:00
Trevor Buckner
5f14f656ef Logging 2024-12-18 17:23:38 -05:00
Trevor Buckner
6e8a0d7314 current user owns 0-author brew only if edit mode
Previous code was treating /share/ visits to google brews with no stub as visits by owner, thus using their own credentials to open the file instead of serviceaccount
2024-12-18 17:07:09 -05:00
Trevor Buckner
e61144beb8 Mark as owner if stub doesn't exist
Old Google Drive files without a stub have no author, so if no stub exists, consider the current user the owner.
2024-12-18 13:45:53 -05:00
Trevor Buckner
64b792c645 Fix case where no stub is found
When retrieving a Google Brew with no stub yet, if the user is not logged in or has expired credentials, we enter this error handler. However, the error message itself tries to send a list of authors.

If there was no stub, we crash here with a 500 error.

This adds conditional operator to any stub value so we can send the actual "not logged in" error in case of no stub.
2024-12-18 13:02:14 -05:00
Trevor Buckner
aee5b7a8cc Require user to be logged in to change name 2024-12-18 12:14:08 -05:00
Trevor Buckner
0148eafce0 Merge pull request #3951 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.9.1
Bump mongoose from 8.9.0 to 8.9.1
2024-12-17 19:34:44 -05:00
dependabot[bot]
a3ec5b8d3b Bump mongoose from 8.9.0 to 8.9.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.9.0 to 8.9.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.9.0...8.9.1)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-17 03:25:20 +00:00
Trevor Buckner
4ded48df1e Merge pull request #3905 from naturalcrit/fixContentNegotiationTestFail-#3904
Fixes #3904 - content negotiation test failure
2024-12-16 18:11:52 -05:00
Trevor Buckner
bc14246fe7 fix import 2024-12-16 17:58:08 -05:00
Trevor Buckner
fcf985a115 Restore content-negotiation test 2024-12-16 17:42:06 -05:00
Trevor Buckner
a060fd123c Merge branch 'master' into fixContentNegotiationTestFail-#3904 2024-12-16 17:39:34 -05:00
Víctor Losada Hernández
7c7e143365 Merge pull request #3950 from naturalcrit/quickfix-CORS
Remove app.js logs to avoid cluttering and buffer overflow errors in heroku
2024-12-16 22:16:12 +01:00
Víctor Losada Hernández
efa8f3fedf remove unnecessary, cluttering logs 2024-12-16 22:13:14 +01:00
Víctor Losada Hernández
972a93d292 Merge pull request #3949 from naturalcrit/quickfix-CORS
quickfix to the CORS policy
2024-12-16 16:47:09 +01:00
Víctor Losada Hernández
35be1e9b94 quickfix 2024-12-16 16:43:40 +01:00
Trevor Buckner
1a91c390f8 Merge pull request #3948 from naturalcrit/dependabot/npm_and_yarn/stylelint-16.12.0
Bump stylelint from 16.11.0 to 16.12.0
2024-12-16 00:09:18 -05:00
dependabot[bot]
206e4fbda8 Bump stylelint from 16.11.0 to 16.12.0
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.11.0 to 16.12.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.11.0...16.12.0)

---
updated-dependencies:
- dependency-name: stylelint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 05:01:24 +00:00
Trevor Buckner
af98cb3867 Merge pull request #3947 from naturalcrit/dependabot/npm_and_yarn/eslint-9.17.0
Bump eslint from 9.16.0 to 9.17.0
2024-12-16 00:00:08 -05:00
dependabot[bot]
f8fc6f7aa4 Bump eslint from 9.16.0 to 9.17.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.16.0 to 9.17.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.16.0...v9.17.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 04:59:23 +00:00
Trevor Buckner
eb0fa28a03 Merge pull request #3946 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.9.0
Bump mongoose from 8.8.4 to 8.9.0
2024-12-15 23:58:09 -05:00
Trevor Buckner
4ab1a22eb3 Merge pull request #3863 from 5e-Cleric/fix-reddit-link-generation-crashing-website-if-encodeURI-fails
Fix crashes if title is invalid as URI
2024-12-15 23:57:38 -05:00
Trevor Buckner
962a46a670 Merge branch 'master' into fix-reddit-link-generation-crashing-website-if-encodeURI-fails 2024-12-15 23:46:54 -05:00
Trevor Buckner
cb16b32016 tabs 2024-12-15 23:45:54 -05:00
Trevor Buckner
56f348f7ed Replace with toWellFormed() 2024-12-15 23:44:56 -05:00
dependabot[bot]
b7c99b2d52 Bump mongoose from 8.8.4 to 8.9.0
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.8.4 to 8.9.0.
- [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.4...8.9.0)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-16 03:57:07 +00:00
Trevor Buckner
889f80f537 Replace react-router-dom with react-router
react-router-dom has been replaced by react-router, so changing packages
2024-12-14 21:48:13 -05:00
Trevor Buckner
c270a69bb9 Merge pull request #3933 from naturalcrit/dependabot/npm_and_yarn/react-router-dom-7.0.2
Bump react-router-dom from 6.28.0 to 7.0.2
2024-12-14 21:36:20 -05:00
Trevor Buckner
db0df82202 Change imports 2024-12-14 21:31:49 -05:00
Trevor Buckner
1346361f80 Merge branch 'dependabot/npm_and_yarn/react-router-dom-7.0.2' of https://github.com/naturalcrit/homebrewery into dependabot/npm_and_yarn/react-router-dom-7.0.2 2024-12-14 19:13:44 -05:00
dependabot[bot]
fdaf9d4808 Bump react-router-dom from 6.28.0 to 7.0.2
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.28.0 to 7.0.2.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.0.2/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-15 00:10:44 +00:00
Víctor Losada Hernández
3cdfae4270 Merge pull request #3942 from naturalcrit/re-author-brews-on-batch
Create backend batch re-author framework
2024-12-15 00:09:48 +01:00
Víctor Losada Hernández
a9275698fa add comment to tell future me to remove logs when feature comes 2024-12-14 23:41:05 +01:00
Víctor Losada Hernández
99f2972079 fixes as asked 2024-12-14 23:34:12 +01:00
Víctor Losada Hernández
afc92c4545 fix check client version middleware to stop checking outside calls 2024-12-14 22:30:24 +01:00
Víctor Losada Hernández
b26526a2f1 lint and logging pass prepared for in server auth from this end 2024-12-14 22:24:52 +01:00
Víctor Losada Hernández
4f57f006ce log cookies at auth middleware 2024-12-14 21:20:39 +01:00
Víctor Losada Hernández
666a94cd65 fix log 2024-12-14 21:15:16 +01:00
Víctor Losada Hernández
f0c094e9d8 logs to account middleware 2024-12-14 21:12:35 +01:00
Víctor Losada Hernández
a1c228b1d1 log req account 2024-12-14 21:01:38 +01:00
Víctor Losada Hernández
5e5c637c79 revert api catch on wrong route middleware 2024-12-14 20:59:51 +01:00
Víctor Losada Hernández
d573129f31 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into re-author-brews-on-batch 2024-12-14 20:34:41 +01:00
Trevor Buckner
57cb334c15 Update pull_request_template.md 2024-12-10 13:35:16 -05:00
Víctor Losada Hernández
c29e1905bf add localhost to allowed origins only if in local, also remake regex 2024-12-10 19:24:23 +01:00
Trevor Buckner
52d00b17a4 Merge branch 'master' into fixContentNegotiationTestFail-#3904 2024-12-10 11:58:05 -05:00
dependabot[bot]
35364c400a Bump react-router-dom from 6.28.0 to 7.0.2
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.28.0 to 7.0.2.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.0.2/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-10 16:23:58 +00:00
Trevor Buckner
77f0c1bf56 Merge pull request #3944 from naturalcrit/dependabot/npm_and_yarn/dompurify-3.2.3
Bump dompurify from 3.2.2 to 3.2.3
2024-12-10 11:22:39 -05:00
dependabot[bot]
2d281072fa Bump dompurify from 3.2.2 to 3.2.3
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.2.2...3.2.3)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-10 03:53:51 +00:00
Víctor Losada Hernández
83b8f9c3b7 Merge pull request #3809 from 5e-Cleric/adress-small-accessibility-concerns
Adress small accessibility concerns
2024-12-09 22:28:52 +01:00
Víctor Losada Hernández
3a20452214 hide unusable editors 2024-12-09 22:18:15 +01:00
Víctor Losada Hernández
3e4ba89ed9 change div selector 2024-12-09 22:11:10 +01:00
Víctor Losada Hernández
2c5c3d40df revert toolbar changes 2024-12-09 22:08:39 +01:00
Víctor Losada Hernández
213240327d resolve issues 2024-12-09 22:05:04 +01:00
Víctor Losada Hernández
eca0f59b40 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into adress-small-accessibility-concerns 2024-12-09 21:52:25 +01:00
Trevor Buckner
51936a1b99 Merge pull request #3936 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.8.4
Bump mongoose from 8.8.3 to 8.8.4
2024-12-09 13:44:42 -05:00
Trevor Buckner
6136b78395 Merge pull request #3943 from naturalcrit/Fix_#2954
Get Google Brews with user auth if owner
2024-12-09 13:44:01 -05:00
Víctor Losada Hernández
81f56ec91d add heroku apps to cors 2024-12-09 18:59:48 +01:00
Víctor Losada Hernández
4eb8abf1e7 Update CORS error message in app.js 2024-12-08 23:46:27 +01:00
Víctor Losada Hernández
23910cc94c add cors policy and rename route 2024-12-08 23:43:32 +01:00
Víctor Losada Hernández
ef0ee78758 revert check client version changes 2024-12-08 23:43:06 +01:00
Víctor Losada Hernández
1b20c00842 log headers 2024-12-08 20:46:02 +01:00
Víctor Losada Hernández
db9212bd12 log req 2024-12-08 20:45:43 +01:00
Víctor Losada Hernández
7348ecbb3d Merge branch 'master' of https://github.com/naturalcrit/homebrewery into re-author-brews-on-batch 2024-12-08 12:07:53 +01:00
Víctor Losada Hernández
31a22703c1 initial commit 2024-12-08 12:05:01 +01:00
Trevor Buckner
33f8f6bf38 Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.8.4 2024-12-07 21:32:53 -05:00
Trevor Buckner
406f5d4e14 Merge branch 'master' into dependabot/npm_and_yarn/mongoose-8.8.4 2024-12-06 16:29:02 -05:00
dependabot[bot]
3178c8722e 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] <support@github.com>
2024-12-06 03:07:01 +00:00
G.Ambatte
7a76c67038 Merge branch 'master' into fixContentNegotiationTestFail-#3904 2024-11-24 20:44:24 +13:00
G.Ambatte
108d368d45 Add content-negotiation test to CircleCI config 2024-11-21 18:54:23 +13:00
G.Ambatte
bd413cfc55 Add content negotiation test command 2024-11-21 18:53:20 +13:00
G.Ambatte
1af13b4e94 Fixes #3904 - content negotiation test failure 2024-11-21 18:46:59 +13:00
Víctor Losada Hernández
2abc2b13f0 wrap encodeURI in try catch 2024-10-30 22:47:17 +01:00
Trevor Buckner
35856ad01e Merge branch 'master' into adress-small-accessibility-concerns 2024-10-11 23:50:39 -04:00
Víctor Losada Hernández
766fd40b72 set cursor in code less for disabled elements 2024-10-11 00:35:43 +02:00
Víctor Losada Hernández
3e6884b506 dynamic input width 2024-10-11 00:32:28 +02:00
Víctor Losada Hernández
2118142faa not allowed cursor 2024-10-11 00:16:36 +02:00
Víctor Losada Hernández
2b270ccdb7 linting 2024-10-11 00:14:12 +02:00
Víctor Losada Hernández
08eabf8102 proper snippetbar styles 2024-10-11 00:12:52 +02:00
Víctor Losada Hernández
c1d85bc216 remove annoying class 2024-10-11 00:12:39 +02:00
Víctor Losada Hernández
3a2c213cf8 linting codeeditor.les 2024-10-11 00:02:00 +02:00
Víctor Losada Hernández
99dc0deb08 foldgutter styles 2024-10-11 00:00:57 +02:00
17 changed files with 363 additions and 1055 deletions

View File

@@ -73,6 +73,9 @@ jobs:
- run:
name: Test - Variables
command: npm run test:variables
- run:
name: Test - Emojis
command: npm run test:emojis
- run:
name: Test - Routes
command: npm run test:route
@@ -82,6 +85,9 @@ jobs:
- run:
name: Test - Coverage
command: npm run test:coverage
- run:
name: Test - Content Negotiation
command: npm run test:content-negotiation
workflows:
build_and_test:

View File

@@ -1,26 +1,29 @@
<!--
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.
- 🚩 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?
- 💡 Is the solution agreed upon? Save rework time by discussing strategy before coding.
-->
> [!TIP]
> 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.
> - 🚩 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?
> - 💡 Is the solution agreed upon? Save rework time by discussing strategy before coding.
## 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
> [!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 #
## QA Instructions, Screenshots, Recordings
_Please replace this line with instructions on how to test or view your changes, as well as any before/after
images for UI changes._
_Replace this line with instructions on how to test or view your changes, as well as any before/after
screenshots or recordings for UI changes._
### 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 *
- [ ] 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
- [ ] Identify opportunities for simplification and refactoring
- [ ] Check for code legibility and appropriate comments
<details><summary>Copy this list</summary>

View File

@@ -115,10 +115,10 @@
color : #D3D3D3;
accent-color : #D3D3D3;
&::-webkit-slider-thumb, &::-moz-slider-thumb {
&::-webkit-slider-thumb, &::-moz-range-thumb {
width : 5px;
height : 5px;
cursor : pointer;
cursor : ew-resize;
outline : none;
}

View File

@@ -207,19 +207,11 @@ const Snippetbar = createClass({
renderEditorButtons : function(){
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'>
<div className='historyTools'>
return (
<div className='editors'>
{this.props.view !== 'meta' && <><div className='historyTools'>
<div className={`editorTool snippetGroup history ${this.state.historyExists ? 'active' : ''}`}
onClick={this.toggleHistoryMenu} >
<i className='fas fa-clock-rotate-left' />
@@ -235,14 +227,21 @@ const Snippetbar = createClass({
</div>
</div>
<div className='codeTools'>
{foldButtons}
<div className={`editorTool editorTheme ${this.state.themeSelector ? 'active' : ''}`}
<div className={`editorTool foldAll ${this.props.foldCode ? '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} >
<i className='fas fa-palette' />
{this.state.themeSelector && this.renderThemeSelector()}
</div>
</div>
</div></>}
<div className='tabs'>
<div className={cx('text', { selected: this.props.view === 'text' })}
@@ -259,7 +258,8 @@ const Snippetbar = createClass({
</div>
</div>
</div>;
</div>
)
},
render : function(){

View File

@@ -22,7 +22,7 @@
justify-content : flex-end;
min-width : 225px;
&:only-child { margin-left : auto; }
&:only-child { margin-left : auto;min-width:unset;}
>div {
display : flex;
@@ -38,6 +38,11 @@
line-height : @menuHeight;
text-align : center;
cursor : pointer;
&.editorTool:not(.active) {
cursor:not-allowed;
}
&:hover,&.selected { background-color : #999999; }
&.text {
.tooltipLeft('Brew Editor');

View File

@@ -1,8 +1,8 @@
require('./homebrew.less');
const React = require('react');
const createClass = require('create-react-class');
const { StaticRouter:Router } = require('react-router-dom/server');
const { Route, Routes, useParams, useSearchParams } = require('react-router-dom');
const { StaticRouter:Router } = require('react-router');
const { Route, Routes, useParams, useSearchParams } = require('react-router');
const HomePage = require('./pages/homePage/homePage.jsx');
const EditPage = require('./pages/editPage/editPage.jsx');

View File

@@ -381,7 +381,7 @@ const EditPage = createClass({
**[Homebrewery Link](${global.config.publicUrl}/share/${shareLink})**`;
return `https://www.reddit.com/r/UnearthedArcana/submit?title=${encodeURIComponent(title)}&text=${encodeURIComponent(text)}`;
return `https://www.reddit.com/r/UnearthedArcana/submit?title=${encodeURIComponent(title.toWellFormed())}&text=${encodeURIComponent(text)}`;
},
renderNavbar : function(){

1080
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,7 @@
"test:api-unit:themes": "jest \"server/.*.spec.js\" -t \"theme bundle\" --verbose",
"test:api-unit:css": "jest \"server/.*.spec.js\" -t \"Get CSS\" --verbose",
"test:api-unit:notifications": "jest \"server/.*.spec.js\" -t \"Notifications\" --verbose",
"test:content-negotiation": "jest \"server/middleware/.*.spec.js\" --verbose",
"test:coverage": "jest --coverage --silent --runInBand",
"test:dev": "jest --verbose --watch",
"test:basic": "jest tests/markdown/basic.test.js --verbose",
@@ -91,9 +92,10 @@
"classnames": "^2.5.1",
"codemirror": "^5.65.6",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
"dompurify": "^3.2.2",
"dompurify": "^3.2.3",
"expr-eval": "^2.0.2",
"express": "^4.21.2",
"express-async-handler": "^1.2.0",
@@ -111,13 +113,13 @@
"marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
"mongoose": "^8.8.3",
"mongoose": "^8.9.1",
"nanoid": "5.0.9",
"nconf": "^0.12.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-frame-component": "^4.1.3",
"react-router-dom": "6.28.0",
"react-router": "^7.0.2",
"sanitize-filename": "1.6.3",
"superagent": "^10.1.1",
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
@@ -125,15 +127,15 @@
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.1",
"babel-plugin-transform-import-meta": "^2.2.1",
"eslint": "^9.16.0",
"eslint": "^9.17.0",
"eslint-plugin-jest": "^28.9.0",
"eslint-plugin-react": "^7.37.2",
"globals": "^15.13.0",
"globals": "^15.14.0",
"jest": "^29.7.0",
"jest-expect-message": "^1.1.3",
"jsdom-global": "^3.0.2",
"postcss-less": "^6.0.0",
"stylelint": "^16.11.0",
"stylelint": "^16.12.0",
"stylelint-config-recess-order": "^5.1.1",
"stylelint-config-recommended": "^14.0.1",
"supertest": "^7.0.0"

View File

@@ -1,5 +1,5 @@
import {model as HomebrewModel } from './homebrew.model.js';
import {model as NotificationModel } from './notifications.model.js';
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';
@@ -108,6 +108,9 @@ router.put('/admin/clean/script/:id', asyncHandler(HomebrewAPI.getBrew('admin',
req.body = brew;
// Remove Account from request to prevent Admin user from being added to brew as an Author
req.account = undefined;
return await HomebrewAPI.updateBrew(req, res);
});

View File

@@ -2,7 +2,7 @@
// Set working directory to project root
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import packageJSON from './../package.json' with { type: "json" };
import packageJSON from './../package.json' with { type: 'json' };
const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(`${__dirname}/..`);
@@ -26,7 +26,7 @@ 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';
import { model as HomebrewModel } from './homebrew.model.js';
import { DEFAULT_BREW } from './brewDefaults.js';
import { splitTextStyleAndMetadata } from '../shared/helpers.js';
@@ -47,7 +47,7 @@ const sanitizeBrew = (brew, accessType)=>{
return brew;
};
app.set('trust proxy', 1 /* number of proxies between user and server */)
app.set('trust proxy', 1 /* number of proxies between user and server */);
app.use('/', serveCompressedStaticAssets(`build`));
app.use(contentNegotiation);
@@ -55,6 +55,40 @@ app.use(bodyParser.json({ limit: '25mb' }));
app.use(cookieParser());
app.use(forceSSL);
import cors from 'cors';
const nodeEnv = config.get('node_env');
const isLocalEnvironment = config.get('local_environments').includes(nodeEnv);
const corsOptions = {
origin : (origin, callback)=>{
const allowedOrigins = [
'https://homebrewery.naturalcrit.com',
'https://www.naturalcrit.com',
'https://naturalcrit-stage.herokuapp.com',
'https://homebrewery-stage.herokuapp.com',
];
if(isLocalEnvironment) {
allowedOrigins.push('http://localhost:8000', 'http://localhost:8010');
}
const herokuRegex = /^https:\/\/(?:homebrewery-pr-\d+\.herokuapp\.com|naturalcrit-pr-\d+\.herokuapp\.com)$/; // Matches any Heroku app
if(!origin || allowedOrigins.includes(origin) || herokuRegex.test(origin)) {
callback(null, true);
} else {
console.log(origin, 'not allowed');
callback(new Error('Not allowed by CORS, if you think this is an error, please contact us'));
}
},
methods : ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
credentials : true,
};
app.use(cors(corsOptions));
//Account Middleware
app.use((req, res, next)=>{
if(req.cookies && req.cookies.nc_session){
@@ -62,7 +96,9 @@ app.use((req, res, next)=>{
req.account = jwt.decode(req.cookies.nc_session, config.get('secret'));
//console.log("Just loaded up JWT from cookie:");
//console.log(req.account);
} catch (e){}
} catch (e){
console.log(e);
}
}
req.config = {
@@ -273,7 +309,7 @@ app.get('/user/:username', async (req, res, next)=>{
console.log(err);
});
brews.forEach(brew => brew.stubbed = true); //All brews from MongoDB are "stubbed"
brews.forEach((brew)=>brew.stubbed = true); //All brews from MongoDB are "stubbed"
if(ownAccount && req?.account?.googleId){
const auth = await GoogleActions.authCheck(req.account, res);
@@ -312,6 +348,34 @@ app.get('/user/:username', async (req, res, next)=>{
return next();
});
//Change author name on brews
app.put('/api/user/rename', async (req, res)=>{
const { username, newUsername } = req.body;
const ownAccount = req.account && (req.account.username == newUsername);
if(!username || !newUsername)
return res.status(400).json({ error: 'Username and newUsername are required.' });
if(!ownAccount)
return res.status(403).json({ error: 'Must be logged in to change your username' });
try {
const brews = await HomebrewModel.getByUser(username, true, ['authors']);
const renamePromises = brews.map(async (brew)=>{
const updatedAuthors = brew.authors.map((author)=>author === username ? newUsername : author
);
return HomebrewModel.updateOne(
{ _id: brew._id },
{ $set: { authors: updatedAuthors } }
);
});
await Promise.all(renamePromises);
return res.json({ success: true, message: `Brews for ${username} renamed to ${newUsername}.` });
} catch (error) {
console.error('Error renaming brews:', error);
return res.status(500).json({ error: 'Failed to rename brews.' });
}
});
//Edit Page
app.get('/edit/:id', asyncHandler(getBrew('edit')), asyncHandler(async(req, res, next)=>{
req.brew = req.brew.toObject ? req.brew.toObject() : req.brew;
@@ -399,7 +463,7 @@ app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, r
app.get('/account', asyncHandler(async (req, res, next)=>{
const data = {};
data.title = 'Account Information Page';
if(!req.account) {
res.set('WWW-Authenticate', 'Bearer realm="Authorization Required"');
const error = new Error('No valid account');
@@ -413,7 +477,7 @@ app.get('/account', asyncHandler(async (req, res, next)=>{
let googleCount = [];
if(req.account) {
if(req.account.googleId) {
auth = await GoogleActions.authCheck(req.account, res, false)
auth = await GoogleActions.authCheck(req.account, res, false);
googleCount = await GoogleActions.listGoogleBrews(auth)
.catch((err)=>{
@@ -448,8 +512,6 @@ app.get('/account', asyncHandler(async (req, res, next)=>{
return next();
}));
const nodeEnv = config.get('node_env');
const isLocalEnvironment = config.get('local_environments').includes(nodeEnv);
// Local only
if(isLocalEnvironment){
// Login
@@ -477,8 +539,8 @@ app.get('/vault', asyncHandler(async(req, res, next)=>{
//Send rendered page
app.use(asyncHandler(async (req, res, next)=>{
if (!req.route) return res.redirect('/'); // Catch-all for invalid routes
if(!req.route) return res.redirect('/'); // Catch-all for invalid routes
const page = await renderPage(req, res);
if(!page) return;
res.send(page);

View File

@@ -106,12 +106,12 @@ const api = {
stub = stub?.toObject();
googleId ??= stub?.googleId;
const isOwner = stub?.authors?.length === 0 || stub?.authors?.[0] === req.account?.username;
const isOwner = (accessType == 'edit' && (!stub || 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 };
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
@@ -119,13 +119,13 @@ const api = {
}
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(!stubOnly && googleId) {
const oAuth2Client = isOwner? GoogleActions.authCheck(req.account, res) : undefined;
// If there's a google id, get it if requesting the full brew or if no stub found yet
if(googleId && (!stubOnly || !stub)) {
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;
@@ -467,12 +467,11 @@ const api = {
}
};
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));
router.delete('/api/:id', asyncHandler(api.deleteBrew));
router.get('/api/remove/:id', asyncHandler(api.deleteBrew));
router.post('/api', checkClientVersion, asyncHandler(api.newBrew));
router.put('/api/:id', checkClientVersion, asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew));
router.put('/api/update/:id', checkClientVersion, asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew));
router.delete('/api/:id', checkClientVersion, asyncHandler(api.deleteBrew));
router.get('/api/remove/:id', checkClientVersion, asyncHandler(api.deleteBrew));
router.get('/api/theme/:renderer/:id', asyncHandler(api.getThemeBundle));
export default api;

View File

@@ -1,10 +1,10 @@
import packageJSON from '../../package.json' with { type: "json" };
const version = packageJSON.version;
import packageJSON from '../../package.json' with { type: 'json' };
export default (req, res, next)=>{
const userVersion = req.get('Homebrewery-Version');
const version = packageJSON.version;
if(userVersion != version) {
if(userVersion !== version) {
return res.status(412).send({
message : `Client version ${userVersion} is out of date. Please save your changes elsewhere and refresh to pick up client version ${version}.`
});
@@ -12,3 +12,4 @@ export default (req, res, next)=>{
next();
};

View File

@@ -6,7 +6,7 @@ export default (req, res, next)=>{
const isImageRequest = req.get('Accept')?.split(',')
?.filter((h)=>!h.includes('q='))
?.every((h)=>/image\/.*/.test(h));
if(isImageRequest && !isLocalEnvironment && !req.url?.startsWith('/staticImages')) {
if(isImageRequest && !(isLocalEnvironment && req.url?.startsWith('/staticImages'))) {
return res.status(406).send({
message : 'Request for image at this URL is not supported'
});

View File

@@ -0,0 +1,41 @@
import contentNegotiationMiddleware from './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();
});
});

View File

@@ -11,49 +11,54 @@
@import (less) './themes/fonts/iconFonts/fontAwesome.less';
@keyframes sourceMoveAnimation {
50% {background-color: red; color: white;}
100% {background-color: unset; color: unset;}
50% { color : white;background-color : red;}
100% { color : unset;background-color : unset;}
}
.codeEditor{
@media screen and (pointer : coarse) {
font-size : 16px;
}
.CodeMirror-foldmarker {
font-family: inherit;
text-shadow: none;
font-weight: 600;
color: grey;
}
.codeEditor {
@media screen and (pointer : coarse) {
font-size : 16px;
}
.CodeMirror-foldmarker {
font-family : inherit;
font-weight : 600;
color : grey;
text-shadow : none;
}
.sourceMoveFlash .CodeMirror-line{
animation-name: sourceMoveAnimation;
animation-duration: 0.4s;
}
.CodeMirror-foldgutter {
cursor : pointer;
border-left : 1px solid #EEEEEE;
transition : background 0.1s;
&:hover { background : #DDDDDD; }
}
.CodeMirror-vscrollbar {
&::-webkit-scrollbar {
width: 20px;
}
&::-webkit-scrollbar-thumb {
width: 20px;
background: linear-gradient(90deg, #858585 15px, #808080 15px);
}
}
.sourceMoveFlash .CodeMirror-line {
animation-name : sourceMoveAnimation;
animation-duration : 0.4s;
}
.CodeMirror-vscrollbar {
&::-webkit-scrollbar { width : 20px; }
&::-webkit-scrollbar-thumb {
width : 20px;
background : linear-gradient(90deg, #858585 15px, #808080 15px);
}
}
//.cm-tab {
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right;
//}
//.cm-tab {
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAQAAACOs/baAAAARUlEQVR4nGJgIAG8JkXxUAcCtDWemcGR1lY4MvgzCEKY7jSBjgxBDAG09UEQzAe0AMwMHrSOAwEGRtpaMIwAAAAA//8DAG4ID9EKs6YqAAAAAElFTkSuQmCC) no-repeat right;
//}
//.cm-trailingspace {
// .cm-space {
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) no-repeat right;
// }
//}
//.cm-trailingspace {
// .cm-space {
// background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQAgMAAABW5NbuAAAACVBMVEVHcEwAAAAAAAAWawmTAAAAA3RSTlMAPBJ6PMxpAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAFUlEQVQI12NgwACcCQysASAEZGAAACMuAX06aCQUAAAAAElFTkSuQmCC) no-repeat right;
// }
//}
}
.emojiPreview {
font-size: 1.5em;
line-height: 1.2em;
font-size : 1.5em;
line-height : 1.2em;
}

View File

@@ -43,5 +43,6 @@ html,body, #reactRoot{
}
&:disabled{
background-color : @silver !important;
cursor:not-allowed;
}
}