0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-23 20:53:05 +00:00

Compare commits

..

279 Commits

Author SHA1 Message Date
Trevor Buckner
b9e15746c3 Update app.js 2024-10-11 23:47:45 -04:00
Trevor Buckner
1fff75cc5e Update homebrew.api.js 2024-10-11 23:42:20 -04:00
Trevor Buckner
9037cf1750 Update homebrew.api.js 2024-10-11 23:41:54 -04:00
Trevor Buckner
dfe26280d2 Update app.js 2024-10-11 23:38:00 -04:00
Trevor Buckner
7894d9fbec Update app.js 2024-10-11 23:35:15 -04:00
Trevor Buckner
c3173d2e14 Update homebrew.api.js 2024-10-11 23:25:55 -04:00
Trevor Buckner
4859756ef8 Update homebrew.api.js 2024-10-11 23:23:56 -04:00
Trevor Buckner
1c47d743d6 Remove 429 error 2024-10-11 23:20:32 -04:00
Trevor Buckner
bfbbbe9e86 Update package.json 2024-10-11 23:19:44 -04:00
Trevor Buckner
1aaa146412 Update package-lock.json 2024-10-11 23:19:17 -04:00
Trevor Buckner
086d85c08b Remove Error 55 2024-10-11 23:18:03 -04:00
Trevor Buckner
134fe7d372 Remove /ip path 2024-10-11 23:15:56 -04:00
Trevor Buckner
836dfbade2 SetSaveDelayTo10s 2024-10-11 23:15:03 -04:00
Trevor Buckner
52a7ce9866 Merge branch 'master' into v3.15.2 2024-10-11 23:08:41 -04:00
Trevor Buckner
05f3f40e47 Merge pull request #3812 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.25.8
Bump @babel/preset-env from 7.25.7 to 7.25.8
2024-10-11 12:11:57 -04:00
dependabot[bot]
7cad7fd319 Bump @babel/preset-env from 7.25.7 to 7.25.8
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.7 to 7.25.8.
- [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.25.8/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-11 16:07:18 +00:00
Trevor Buckner
dca9099d00 Merge pull request #3811 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.25.8
Bump @babel/core from 7.25.7 to 7.25.8
2024-10-11 12:06:05 -04:00
dependabot[bot]
fa78d04e89 Bump @babel/core from 7.25.7 to 7.25.8
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.25.7 to 7.25.8.
- [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.25.8/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-11 03:50:24 +00:00
Trevor Buckner
5f9dfc9258 Merge pull request #3688 from G-Ambatte/experimentalDeploymentIdentification 2024-10-10 23:11:14 -04:00
G.Ambatte
d534eddb29 Remove unnecessary useEffect import 2024-10-11 13:14:53 +13:00
G.Ambatte
9099db5ea1 Remove obsolete state and event handlers 2024-10-11 11:56:29 +13:00
G.Ambatte
a9a8b4b9bb Shift static height style to LESS file 2024-10-11 11:55:51 +13:00
G.Ambatte
5d29d40c97 Implement suggested change 2024-10-11 11:42:03 +13:00
G.Ambatte
4291284252 Merge branch 'master' into experimentalDeploymentIdentification 2024-10-11 11:10:28 +13:00
Víctor Losada Hernández
fcede5448e Merge pull request #3492 from 5e-Cleric/fix-vulnerability-admin-pages
Fix admin vulnerability to Brute Force
2024-10-10 23:05:06 +02:00
Víctor Losada Hernández
c47974cb49 suggested changes 2024-10-10 23:00:39 +02:00
Víctor Losada Hernández
4fde4600bc fix pack 2024-10-10 22:58:55 +02:00
Víctor Losada Hernández
27f939201d Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-vulnerability-admin-pages 2024-10-10 22:54:22 +02:00
Víctor Losada Hernández
6e2cde507d revert package completely 2024-10-10 22:50:29 +02:00
Víctor Losada Hernández
95d6e39a44 Revert "remove changes package lock"
This reverts commit 00f1d4a27e.
2024-10-10 22:49:19 +02:00
Víctor Losada Hernández
39b8cbae2a Revert "remove package 2"
This reverts commit 0162232053.
2024-10-10 22:49:16 +02:00
Víctor Losada Hernández
0162232053 remove package 2 2024-10-10 22:44:51 +02:00
Víctor Losada Hernández
00f1d4a27e remove changes package lock 2024-10-10 22:43:13 +02:00
Víctor Losada Hernández
db618fe2ad linting changes 2024-10-10 22:42:47 +02:00
Víctor Losada Hernández
47f2703388 remove unrelated change 2024-10-10 22:38:50 +02:00
Víctor Losada Hernández
52e929ee68 remove spaces added 2024-10-10 22:36:59 +02:00
Víctor Losada Hernández
f74e72a35f remove rate-limit 2024-10-10 22:32:17 +02:00
Trevor Buckner
e3d256aaaf Merge pull request #3800 from G-Ambatte/addIndexedDM-#3763
Change local version history to use Indexed DB
2024-10-10 15:38:52 -04:00
G.Ambatte
f65dee28cb Merge branch 'master' into addIndexedDM-#3763 2024-10-11 07:44:05 +13:00
Trevor Buckner
58dd1b147d Merge pull request #3807 from naturalcrit/dependabot/npm_and_yarn/globals-15.11.0
Bump globals from 15.10.0 to 15.11.0
2024-10-10 13:45:14 -04:00
Trevor Buckner
f84dcd9fce Merge branch 'master' into dependabot/npm_and_yarn/globals-15.11.0 2024-10-10 11:52:18 -04:00
Trevor Buckner
cc1ab35255 Merge pull request #3806 from naturalcrit/dependabot/npm_and_yarn/mongoose-8.7.1
Bump mongoose from 8.7.0 to 8.7.1
2024-10-10 11:52:09 -04:00
G.Ambatte
803ca09ab6 Merge branch 'master' into addIndexedDM-#3763 2024-10-10 21:55:00 +13:00
dependabot[bot]
8a60a4a5cc Bump globals from 15.10.0 to 15.11.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.10.0 to 15.11.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.10.0...v15.11.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-10-10 03:23:29 +00:00
dependabot[bot]
a345b67ffe Bump mongoose from 8.7.0 to 8.7.1
Bumps [mongoose](https://github.com/Automattic/mongoose) from 8.7.0 to 8.7.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.0...8.7.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-10-10 03:23:22 +00:00
Trevor Buckner
456cefd535 Merge pull request #3786 from dbolack-ab/nanoid-fix 2024-10-09 22:24:03 -04:00
G.Ambatte
ab6861675d Comment out history testing values 2024-10-10 09:07:54 +13:00
G.Ambatte
0deb9073cd Remove obsolete file 2024-10-10 08:57:41 +13:00
G.Ambatte
d5cda45d4d Merge branch 'master' into addIndexedDM-#3763 2024-10-10 08:50:39 +13:00
G.Ambatte
36674f4cf2 Add explicit guard clause to renderHistoryItems 2024-10-10 08:48:14 +13:00
G.Ambatte
618de544bf Remove unnecessary check 2024-10-10 08:43:38 +13:00
G.Ambatte
8f5b421531 Fix infinite loop 2024-10-10 08:34:24 +13:00
G.Ambatte
8db12739d3 Remove obsolete function 2024-10-10 08:34:15 +13:00
Trevor Buckner
4cb093c0c0 Merge branch 'master' into nanoid-fix 2024-10-09 15:10:03 -04:00
Trevor Buckner
9f0f9a9169 Merge pull request #2586 from G-Ambatte/experimentalNotificationDB 2024-10-09 15:09:25 -04:00
Trevor Buckner
a9aab5bb0c Add test for error handling deleting notifications 2024-10-09 14:52:56 -04:00
Trevor Buckner
5ca970bdee Typo 2024-10-09 14:46:18 -04:00
Trevor Buckner
9635e1a8eb Change another return to throw 2024-10-09 14:41:37 -04:00
Trevor Buckner
23e3c98a0d Add test for adding notification without dismissKey 2024-10-09 14:40:38 -04:00
Trevor Buckner
346bb0086e Should throw, not return errors, so they land in catch 2024-10-09 14:40:11 -04:00
Trevor Buckner
e873dcf3a8 Fix error messages crashing page 2024-10-09 14:35:16 -04:00
Trevor Buckner
269dd6107c Merge branch 'master' into experimentalNotificationDB 2024-10-09 11:12:23 -04:00
Trevor Buckner
8281db8543 Merge pull request #3804 from naturalcrit/dependabot/npm_and_yarn/cookie-parser-1.4.7 2024-10-09 11:07:27 -04:00
dependabot[bot]
66db3ecdc1 Bump cookie-parser from 1.4.6 to 1.4.7
Bumps [cookie-parser](https://github.com/expressjs/cookie-parser) from 1.4.6 to 1.4.7.
- [Release notes](https://github.com/expressjs/cookie-parser/releases)
- [Changelog](https://github.com/expressjs/cookie-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/cookie-parser/compare/1.4.6...1.4.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-09 15:06:37 +00:00
Trevor Buckner
1ef61b32d4 Merge pull request #3803 from naturalcrit/dependabot/npm_and_yarn/express-4.21.1 2024-10-09 11:05:13 -04:00
G.Ambatte
dc66d36b2d Simplify history loading 2024-10-09 19:35:48 +13:00
G.Ambatte
0bd3b53dd1 Merge branch 'master' into addIndexedDM-#3763 2024-10-09 19:00:45 +13:00
G.Ambatte
5651c66562 Fix race condition 2024-10-09 18:29:15 +13:00
G.Ambatte
fb2d03f5a2 Change to test values 2024-10-09 17:50:26 +13:00
G.Ambatte
0b44e68a36 Simplify garbage collection 2024-10-09 17:27:33 +13:00
dependabot[bot]
fe7ee78cae Bump express from 4.21.0 to 4.21.1
Bumps [express](https://github.com/expressjs/express) from 4.21.0 to 4.21.1.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.0...4.21.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-09 03:25:09 +00:00
G.Ambatte
aa68762294 Simplify historyCheck logic 2024-10-09 15:59:11 +13:00
G.Ambatte
2a9402634f Remove unnecessary guard clause 2024-10-09 14:58:20 +13:00
G.Ambatte
291e16b124 Revert to use local consts instead of config vars 2024-10-09 14:57:04 +13:00
G.Ambatte
e75eb72d3f Remove obsolete function 2024-10-09 14:54:23 +13:00
Trevor Buckner
7bf95dd0ca Merge pull request #3132 from dbolacksn/Issue_1958 2024-10-08 17:13:19 -04:00
Trevor Buckner
80a21e3f27 Merge branch 'master' into Issue_1958 2024-10-08 17:12:05 -04:00
Trevor Buckner
a921d0a9bb Merge pull request #3802 from Gazook89/Remove-Unused-Nav-Components 2024-10-08 17:10:20 -04:00
Trevor Buckner
9acecb63ed Merge branch 'master' into addIndexedDM-#3763 2024-10-08 17:07:39 -04:00
Gazook89
a6efaf0e8b Remove unused Nav components 2024-10-08 10:12:53 -05:00
David Bolack
c4b754e467 Lost a stray ) on update 2024-10-07 14:45:33 -05:00
David Bolack
e82411d3d2 Merge branch 'master' into Issue_1958 2024-10-07 14:35:19 -05:00
David Bolack
5080fd068a Merge branch 'master' into nanoid-fix 2024-10-07 14:32:19 -05:00
Trevor Buckner
88d36bcf85 Merge pull request #3798 from naturalcrit/dependabot/npm_and_yarn/eslint-9.12.0
Bump eslint from 9.11.1 to 9.12.0
2024-10-07 13:24:31 -04:00
dependabot[bot]
e2243efe82 Bump eslint from 9.11.1 to 9.12.0
Bumps [eslint](https://github.com/eslint/eslint) from 9.11.1 to 9.12.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.11.1...v9.12.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-10-07 15:10:37 +00:00
Trevor Buckner
337531a622 Merge pull request #3797 from naturalcrit/dependabot/npm_and_yarn/stylistic/stylelint-plugin-3.1.1
Bump @stylistic/stylelint-plugin from 3.1.0 to 3.1.1
2024-10-07 11:09:18 -04:00
G.Ambatte
7e165c6e61 Remove unnecessary key check 2024-10-07 21:53:24 +13:00
G.Ambatte
5d9ef3fa6c Add custom IDB store 2024-10-07 21:53:05 +13:00
G.Ambatte
24bffacaeb GC functional, config values now actually used 2024-10-07 20:53:32 +13:00
G.Ambatte
1e38ed8d1f Bump max-lines 2024-10-07 20:53:05 +13:00
G.Ambatte
25ce1aa00c Functional history menu 2024-10-07 19:36:17 +13:00
G.Ambatte
97f8493319 Merge branch 'master' into addIndexedDM-#3763 2024-10-07 18:32:05 +13:00
G.Ambatte
c9241e3091 WIP Update 2024-10-07 18:22:06 +13:00
dependabot[bot]
70118022b8 Bump @stylistic/stylelint-plugin from 3.1.0 to 3.1.1
Bumps [@stylistic/stylelint-plugin](https://github.com/stylelint-stylistic/stylelint-stylistic) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/stylelint-stylistic/stylelint-stylistic/releases)
- [Changelog](https://github.com/stylelint-stylistic/stylelint-stylistic/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint-stylistic/stylelint-stylistic/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: "@stylistic/stylelint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-07 03:36:16 +00:00
Trevor Buckner
226e714f32 Merge pull request #3793 from 5e-Cleric/fix-wrong-brew-id-links-generated 2024-10-06 15:57:11 -04:00
Trevor Buckner
f3332fb95b Merge branch 'master' into fix-wrong-brew-id-links-generated 2024-10-06 15:54:37 -04:00
Trevor Buckner
10d4cd4ab3 Merge pull request #3796 from naturalcrit/FixGoogleLinksinUserPage 2024-10-06 15:52:29 -04:00
Trevor Buckner
2a523c4955 Fix links to google drive files in user page
User page was not marking Google Brews as "stubbed" if the brew belongs   to another users' Google Drive or your own credentials are expired (it searches the current user drive for google files and checks if those are stubbed)

This now sets *every* file found on Mongo as "Stubbed", whether the Drive file belongs to the current user or not.
2024-10-06 15:48:10 -04:00
Víctor Losada Hernández
64dd71601c last changes 2024-10-06 19:59:58 +02:00
Víctor Losada Hernández
4968300e7a return correct data 2024-10-06 19:54:41 +02:00
Víctor Losada Hernández
3acb25ce3a adress comments 2024-10-06 19:43:51 +02:00
Víctor Losada Hernández
487a574f50 initital fix 2024-10-06 00:05:12 -04:00
Víctor Losada Hernández
a4e0f1fc0f initital fix 2024-10-04 22:18:11 +02:00
Trevor Buckner
2ada6ce70d Merge pull request #3789 from naturalcrit/dependabot/npm_and_yarn/babel/core-7.25.7
Bump @babel/core from 7.25.2 to 7.25.7
2024-10-04 13:53:11 -04:00
dependabot[bot]
132878fd8c Bump @babel/core from 7.25.2 to 7.25.7
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.25.2 to 7.25.7.
- [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.25.7/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-04 17:49:46 +00:00
Trevor Buckner
0146ab7ce0 Merge pull request #3787 from naturalcrit/dependabot/npm_and_yarn/babel/plugin-transform-runtime-7.25.7
Bump @babel/plugin-transform-runtime from 7.25.4 to 7.25.7
2024-10-04 13:48:31 -04:00
dependabot[bot]
a29addbfa3 Bump @babel/plugin-transform-runtime from 7.25.4 to 7.25.7
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.25.4 to 7.25.7.
- [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.25.7/packages/babel-plugin-transform-runtime)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-runtime"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-04 17:46:56 +00:00
Trevor Buckner
796f8ac8b7 Merge pull request #3788 from naturalcrit/dependabot/npm_and_yarn/babel/preset-env-7.25.7
Bump @babel/preset-env from 7.25.4 to 7.25.7
2024-10-04 13:45:42 -04:00
dependabot[bot]
19d76bd077 Bump @babel/preset-env from 7.25.4 to 7.25.7
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.4 to 7.25.7.
- [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.25.7/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-04 14:51:12 +00:00
Trevor Buckner
f59a250bb1 Merge pull request #3790 from naturalcrit/dependabot/npm_and_yarn/babel/preset-react-7.25.7
Bump @babel/preset-react from 7.24.7 to 7.25.7
2024-10-04 10:49:52 -04:00
David Bolack
5b64052c21 Helps if I update the tests. 2024-10-03 18:49:16 -05:00
David Bolack
f00e76319c Hard code latest as min 2024-10-03 18:44:47 -05:00
David Bolack
a844b29165 Try further down the updates. 2024-10-03 18:40:22 -05:00
David Bolack
fcd1a2de5b Update node version one release. 2024-10-03 09:16:08 -05:00
Víctor Losada Hernández
5eb1456915 fix tests 2 2024-10-03 09:15:08 +02:00
Víctor Losada Hernández
a82e9758b3 fix test errors 2024-10-03 09:08:24 +02:00
Víctor Losada Hernández
6adac74f76 updated test 2024-10-03 09:01:12 +02:00
Víctor Losada Hernández
3c3b4d8466 "Updated mock implementation for deleting a notification in admin API test" 2024-10-03 09:00:57 +02:00
Víctor Losada Hernández
9cc4d2d7c5 add last test 2024-10-03 08:53:27 +02:00
Víctor Losada Hernández
d216216df7 remove unnecessary methods and comments 2024-10-03 08:48:54 +02:00
dependabot[bot]
9fd92e00a1 Bump @babel/preset-react from 7.24.7 to 7.25.7
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.24.7 to 7.25.7.
- [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.25.7/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] <support@github.com>
2024-10-03 03:17:35 +00:00
David Bolack
afeadb5417 Enable --experimental-require-module flag on node build in order to support ESM module only modules. 2024-10-02 22:05:09 -05:00
Trevor Buckner
e9286d4bb7 Merge pull request #3784 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.37.1
Bump eslint-plugin-react from 7.37.0 to 7.37.1
2024-10-01 23:39:13 -04:00
dependabot[bot]
22dbe1ebf0 Bump eslint-plugin-react from 7.37.0 to 7.37.1
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.37.0 to 7.37.1.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.0...v7.37.1)

---
updated-dependencies:
- dependency-name: eslint-plugin-react
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-02 03:34:52 +00:00
Trevor Buckner
53761bc567 Merge pull request #3785 from naturalcrit/dependabot/npm_and_yarn/globals-15.10.0
Bump globals from 15.9.0 to 15.10.0
2024-10-01 23:33:33 -04:00
dependabot[bot]
e6e9029bb7 Bump globals from 15.9.0 to 15.10.0
Bumps [globals](https://github.com/sindresorhus/globals) from 15.9.0 to 15.10.0.
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v15.9.0...v15.10.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-10-02 03:26:23 +00:00
Trevor Buckner
1a325fb3c5 New notification 2024-10-01 22:25:17 -04:00
Trevor Buckner
84f49aebce Add test for "add notification" 2024-10-01 21:54:22 -04:00
Trevor Buckner
8949248bc4 Example test
Added an example test that queries /admin/notification/all and checks if the response returns a list of notifications.

Since we don't have a real database, we overwrite (mock) NotificationModel to just return some fake data, otherwise the test would crash.
2024-10-01 17:15:36 -04:00
Víctor Losada Hernández
df06d8fcd3 update error index 2024-10-01 21:58:52 +02:00
Víctor Losada Hernández
d6ca6592a2 remove rateLimiter 2024-10-01 21:58:42 +02:00
Trevor Buckner
0110c6afed Remove duplicate error log for googleActions.list 2024-10-01 15:06:11 -04:00
Trevor Buckner
0e29620710 Remove delayMiddleware and ratelimiter 2024-10-01 14:13:15 -04:00
Trevor Buckner
c33b44855a Go back to service account for brew updates 2024-10-01 12:17:30 -04:00
G.Ambatte
77f162f7a4 Initial IDB functionality pass 2024-10-01 23:53:35 +13:00
Trevor Buckner
bc475b5ed9 Merge pull request #3762 from naturalcrit/dependabot/npm_and_yarn/eslint-plugin-react-7.37.0
Bump eslint-plugin-react from 7.36.1 to 7.37.0
2024-09-30 14:14:21 -04:00
Trevor Buckner
0415af624a Merge branch 'master' into dependabot/npm_and_yarn/eslint-plugin-react-7.37.0 2024-09-30 13:52:13 -04:00
Trevor Buckner
8a63859546 Merge pull request #3778 from 5e-Cleric/fix-lang-on-share
fix lang on share page
2024-09-30 13:51:50 -04:00
Trevor Buckner
8d5bc9e37c Merge pull request #3767 from G-Ambatte/fixToolbarZoomInPrint-#3744
Add zoom property to BrewRenderer print styling
2024-09-30 13:51:37 -04:00
Trevor Buckner
313f18c74c Merge branch 'master' into fixToolbarZoomInPrint-#3744 2024-09-30 13:50:00 -04:00
Trevor Buckner
0c6bc5d7ac Merge pull request #3757 from naturalcrit/v3.15.1
Fix Rate Limiting
2024-09-30 13:48:53 -04:00
Trevor Buckner
db6c689914 Merge branch 'master' into fix-lang-on-share 2024-09-30 13:48:20 -04:00
Víctor Losada Hernández
d4970ed119 initial commit 2024-09-30 17:48:07 +02:00
Trevor Buckner
e7e35294c6 disable rate limiter 2024-09-30 10:59:43 -04:00
Trevor Buckner
e9c45b216c Add retryconfig and forward user ip 2024-09-30 08:31:39 -04:00
Trevor Buckner
40925253bd autosave to 16 seconds 2024-09-30 00:59:30 -04:00
Trevor Buckner
66433d9e77 5 requests 2024-09-30 00:45:10 -04:00
Trevor Buckner
3a6750613b express proxy settings 2024-09-30 00:31:58 -04:00
dependabot[bot]
e45fddad60 Bump eslint-plugin-react from 7.36.1 to 7.37.0
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.36.1 to 7.37.0.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.36.1...v7.37.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-30 04:24:03 +00:00
Trevor Buckner
a7361f8450 add delay between get and update 2024-09-30 00:14:37 -04:00
Trevor Buckner
32fa272947 reduce rate limit to 60 requests in 5 minutes 2024-09-30 00:03:27 -04:00
Trevor Buckner
68895bdca2 Rate limit /api requests from each IP address
100 requests each 5 minutes.
2024-09-29 23:37:26 -04:00
Trevor Buckner
8ab6a8599d Use personal auth if logged in via google. 2024-09-29 21:47:45 -04:00
Trevor Buckner
ea656e5119 Issue notice 2024-09-29 00:15:26 -04:00
G.Ambatte
570c850c4f Merge branch 'master' into fixToolbarZoomInPrint-#3744 2024-09-28 09:05:22 +12:00
G.Ambatte
17dfacd5c9 Add zoom property to BrewRenderer print styling 2024-09-28 09:03:00 +12:00
Víctor Losada Hernández
ab32695ac9 test admin stuff 2024-09-25 11:34:56 +02:00
David Bolack
672b787cd5 Merge branch 'Issue_1958' of github.com:dbolacksn/homebrewery-broken into Issue_1958 2024-09-18 16:28:19 -05:00
David Bolack
931566636b Merge branch 'master' into Issue_1958 2024-09-18 16:26:39 -05:00
David Bolack
ffaca4ec10 Update server/middleware/content-negotiation.js
Co-authored-by: Trevor Buckner <calculuschild@gmail.com>
2024-09-18 16:21:31 -05:00
Trevor Buckner
fabc0bea83 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into pr/2586 2024-09-18 15:50:55 -04:00
Trevor Buckner
5c2ad7dfee More Linting 2024-09-18 15:50:46 -04:00
Víctor Losada Hernández
3e7d4714a2 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into experimentalNotificationDB 2024-09-18 21:47:05 +02:00
Víctor Losada Hernández
77c4ac6640 deleting useless state 2024-09-18 21:47:03 +02:00
Trevor Buckner
a7c892c1bb Lint 2024-09-18 15:36:48 -04:00
Trevor Buckner
dca7086522 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into pr/2586 2024-09-18 15:35:12 -04:00
Trevor Buckner
6c42a7e180 Lint 2024-09-18 15:34:58 -04:00
Víctor Losada Hernández
e8c2858154 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into experimentalNotificationDB 2024-09-18 21:32:19 +02:00
Víctor Losada Hernández
84f84782f5 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery; branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-09-18 21:32:17 +02:00
Trevor Buckner
3caec793d8 Linting 2024-09-18 15:30:30 -04:00
Trevor Buckner
9717f0cd66 Split state into separate states. 2024-09-18 15:09:53 -04:00
Trevor Buckner
0cdc1947c1 Linting 2024-09-18 14:45:17 -04:00
Víctor Losada Hernández
f024bea493 delete unused error 2024-09-17 19:58:49 +02:00
Víctor Losada Hernández
bbe4b5f978 Merge branch 'master' into fix-vulnerability-admin-pages 2024-09-17 12:47:18 +02:00
Víctor Losada Hernández
14d2534542 linting 2024-09-17 12:46:24 +02:00
Víctor Losada Hernández
3b49b5180e update error to auth 2024-09-17 12:25:54 +02:00
Víctor Losada Hernández
2028f3dccd removing console log 2024-09-16 23:04:30 +02:00
Víctor Losada Hernández
8e4fc01831 linting 2024-09-16 23:03:50 +02:00
Víctor Losada Hernández
e2ae6898fd Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-vulnerability-admin-pages 2024-09-16 23:00:52 +02:00
Víctor Losada Hernández
44262e2aae change initial status code 2024-09-16 22:52:56 +02:00
Víctor Losada Hernández
d8e174e143 update package-lock, apparently 2024-09-16 22:41:59 +02:00
Víctor Losada Hernández
0d2878a7e7 merge from master and change error codes 2024-09-16 22:34:28 +02:00
Víctor Losada Hernández
a0d043439c Merge branch 'master' of https://github.com/naturalcrit/homebrewery into fix-vulnerability-admin-pages 2024-09-16 22:29:16 +02:00
Víctor Losada Hernández
8126271ea3 Merge branch 'fix-vulnerability-admin-pages' of https://github.com/5e-Cleric/homebrewery into fix-vulnerability-admin-pages 2024-09-16 22:25:17 +02:00
David Bolack
67e265b23f Set default values for hb_images and hb_fonts in the config.
Remove stray tab.
2024-09-15 21:55:18 -05:00
David Bolack
dc67c75130 Merge branch 'master' into Issue_1958 2024-09-15 18:15:19 -05:00
Víctor Losada Hernández
ebc3b4ee66 "Updated admin notification management: added error handling and styling, modified notification add and lookup functionality, and refactored server-side API routes and error handling." 2024-09-14 23:58:47 +02:00
Víctor Losada Hernández
9bf28f1433 Merge branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-09-13 23:54:01 +02:00
Víctor Losada Hernández
dbbfb0b628 suggestions added, linted 2024-09-13 23:29:36 +02:00
Víctor Losada Hernández
4f2c2916d6 remove cx 2024-09-13 23:03:40 +02:00
Víctor Losada Hernández
629b51a26c remove logs and unecessary state 2024-09-13 20:33:58 +02:00
Víctor Losada Hernández
d947ff45e2 correct style to be coherent and nice 2024-09-13 20:33:21 +02:00
Víctor Losada Hernández
a2d260c297 remove lookup by id funct and fix lost state functions 2024-09-13 20:29:35 +02:00
Víctor Losada Hernández
c411691fd6 remove lookup by id and admin access middleware from lookup all 2024-09-13 20:29:09 +02:00
Víctor Losada Hernández
f40c5e17ca change to 401 2024-09-12 14:04:35 +02:00
David Bolack
a2497052b4 Merge branch 'master' into Issue_1958 2024-09-06 11:56:04 -05:00
David Bolack
240dfa3954 Merge branch 'Issue_1958' of github.com:dbolacksn/homebrewery-broken into Issue_1958
Only except /staticImages with a `local` NODE_ENV
2024-09-06 11:55:21 -05:00
David Bolack
d19aaf6c78 Except staticImages and staticFonts paths from middleware evaluation if in a local ENV. 2024-09-06 11:50:46 -05:00
G.Ambatte
235969a485 Fix a dropped bracket 2024-09-05 16:50:19 +12:00
G.Ambatte
2e459118aa Update content-negotiation.js 2024-09-05 16:45:07 +12:00
G.Ambatte
ff60ca163f Merge branch 'master' into Issue_1958 2024-09-05 16:38:14 +12:00
David Bolack
4dc5746c71 Merge branch 'master' into Issue_1958 2024-09-04 20:52:46 -05:00
David Bolack
5cf8715dea Merge branch 'master' into Issue_1958 2024-08-31 11:07:45 -05:00
Víctor Losada Hernández
849e5d5d1a Merge branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-08-31 13:15:55 +02:00
Víctor Losada Hernández
188090ee45 revert themes.json 2024-08-31 13:15:11 +02:00
Víctor Losada Hernández
d352b76efe join styles and lint 2024-08-31 13:12:53 +02:00
Víctor Losada Hernández
e88272c684 "Refactor admin UI components: update class names, element types, and nesting in admin.jsx, notificationLookup.jsx, and notificationUtils.jsx" 2024-08-31 12:51:06 +02:00
Víctor Losada Hernández
10ce696333 basic styles 2024-08-31 12:50:53 +02:00
Víctor Losada Hernández
4488fe36db "Refactored notification lookup and management functionality in admin API and model, added new endpoints for getting all notifications and deleting a notification by dismiss key." 2024-08-31 12:17:12 +02:00
Víctor Losada Hernández
c79765396d add notif working 2024-08-31 00:04:44 +02:00
Víctor Losada Hernández
36549f3224 "Added 'required' attribute to several form input fields in NotificationAdd component." 2024-08-30 20:25:39 +02:00
Víctor Losada Hernández
e81a9dab1f add good stylings, and lint 2024-08-29 23:40:13 +02:00
Víctor Losada Hernández
65759e18bd clean inputs 2024-08-29 23:39:54 +02:00
G.Ambatte
f458b98dcf Merge branch 'master' into experimentalDeploymentIdentification 2024-08-29 21:31:55 +12:00
G.Ambatte
cc7fe99760 Initial functionality pass 2024-08-29 21:26:24 +12:00
Víctor Losada Hernández
78642e514d revert console log 2024-08-29 10:47:38 +02:00
Víctor Losada Hernández
4edbfa10b5 log config vars 2024-08-29 10:45:36 +02:00
David Bolack
5e8f74b9bc Merge branch 'master' into Issue_1958 2024-08-28 21:09:07 -05:00
Víctor Losada Hernández
b39e8eea16 Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery; branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-08-29 00:24:22 +02:00
Víctor Losada Hernández
0c6c0c9fd6 use actual inputs and textarea with good attributes 2024-08-29 00:23:22 +02:00
Víctor Losada Hernández
51d3d11bff "Refactor notification utils components to use React Hooks instead of createClass" 2024-08-29 00:01:02 +02:00
Víctor Losada Hernández
46882c4fb4 add error logging on admin route 2024-08-29 00:00:55 +02:00
Víctor Losada Hernández
760c1a9e8c Merge branch 'master' of https://github.com/naturalcrit/homebrewery into experimentalNotificationDB 2024-08-28 22:28:24 +02:00
David Bolack
baf201cc3a Merge branch 'master' into Issue_1958 2024-08-13 12:25:49 -05:00
David Bolack
e2ce1185b6 Merge branch 'master' into Issue_1958 2024-08-02 15:47:50 -05:00
Trevor Buckner
8983d74775 rebuild package lock again? 2024-08-01 21:30:09 -04:00
Trevor Buckner
f084c11936 Update package-lock.json 2024-08-01 21:26:04 -04:00
Trevor Buckner
a442817226 Re-build package-lock. 2024-08-01 17:43:54 -04:00
David Bolack
73e579703a Merge branch 'master' into Issue_1958 2024-08-01 11:19:17 -05:00
Víctor Losada Hernández
4680e7a5cc i messed up authentication entirely, this commit restores it 2024-06-16 17:21:55 +02:00
Víctor Losada Hernández
f07252d670 errors for access denied and authorization required 2024-06-16 17:14:27 +02:00
Víctor Losada Hernández
f15c831b70 proper error page 2024-06-16 17:06:18 +02:00
David Bolack
587831652c Merge branch 'master' into Issue_1958 2024-06-02 12:33:14 -05:00
Víctor Losada Hernández
6e0aff525f Updated rate limiter window name 2024-05-25 20:51:44 +02:00
Víctor Losada Hernández
748c25aae4 "Added express-rate-limit package and implemented rate limiting for admin API login attempts" 2024-05-24 20:42:25 +02:00
David Bolack
f675fd130f Merge branch 'master' into Issue_1958 2024-05-20 13:36:41 -05:00
David Bolack
a69d251f53 Merge branch 'master' into Issue_1958 2024-05-12 10:37:20 -05:00
David Bolack
7ed48f3e70 Merge branch 'master' into Issue_1958 2024-03-09 20:12:03 -06:00
David Bolack
627b4ace0f Merge branch 'master' into Issue_1958 2024-03-06 23:42:11 -06:00
David Bolack
f2d5a8df99 Merge branch 'master' into Issue_1958 2024-03-04 11:45:53 -06:00
David Bolack
0d8026436c Merge branch 'master' into Issue_1958 2024-02-07 20:10:04 -06:00
David Bolack
8656feba44 Merge branch 'master' into Issue_1958 2024-01-25 00:18:47 -06:00
Trevor Buckner
e9a76dd018 Use existing dependency fs-extra instead of adding new one 2023-12-04 22:28:48 -05:00
Trevor Buckner
db0f75c852 Merge branch 'master' into pr/3132 2023-12-04 22:26:05 -05:00
David Bolack
0db6ffe340 Merge branch 'master' into Issue_1958 2023-11-10 23:23:55 -06:00
David Bolack
1b855108bf Correct omitted static path 2023-11-07 21:26:11 -06:00
David Bolack
ffe12ebee7 Add local statics for images and typefaces
This solves issue #1958.

Add static paths /staticImages and /staticFonts

If a local environment is detected ( per existing loginc for login )
paths are added using the values in HB_IMAGES and HB_FONTS or the default values of /staticImages and /staticFonts respectively.
2023-11-07 20:21:19 -06:00
G.Ambatte
e211b0858d Merge branch 'master' into experimentalNotificationDB 2023-08-28 07:51:31 +12:00
G.Ambatte
c8ac3f36fd Merge branch 'master' into experimentalNotificationDB 2023-07-16 09:41:05 +12:00
G.Ambatte
8c0cf4ccd4 Merge branch 'master' into experimentalNotificationDB 2023-07-06 17:55:00 +12:00
G.Ambatte
79eb4d8a9a Merge branch 'master' into experimentalNotificationDB 2023-06-10 14:27:49 +12:00
G.Ambatte
52d5d17561 Merge branch 'master' into experimentalNotificationDB 2023-03-24 07:56:24 +13:00
G.Ambatte
0fc3e03e95 Merge branch 'master' into experimentalNotificationDB 2023-03-12 22:30:53 +13:00
G.Ambatte
28cadcad06 Merge branch 'master' into experimentalNotificationDB 2023-02-22 16:14:19 +13:00
G.Ambatte
1fd8648602 Merge branch 'naturalcrit:master' into experimentalNotificationDB 2023-02-19 15:22:19 +13:00
G.Ambatte
66e10f3b4e Merge branch 'master' into experimentalNotificationDB 2023-02-14 13:00:02 +13:00
G.Ambatte
da0372e44c WIP commit 2023-01-23 15:18:50 +13:00
G.Ambatte
a4e6b2358a Merge branch 'master' into experimentalNotificationDB 2023-01-21 17:59:32 +13:00
G.Ambatte
24adbdc429 Change model to use defaults rather than mergeWith 2023-01-15 23:28:54 +13:00
G.Ambatte
ccd5cacb0c Stub notification deletion function 2023-01-15 23:25:17 +13:00
G.Ambatte
5e2171ceb1 Remove debugging console.log calls 2023-01-15 22:21:06 +13:00
G.Ambatte
b00a962e77 Fix typo 2023-01-15 20:44:41 +13:00
G.Ambatte
c518fc2d23 Merge branch 'naturalcrit:master' into experimentalNotificationDB 2023-01-15 13:55:25 +13:00
G.Ambatte
ca2582fdbd Merge branch 'experimentalNotificationDB' of https://github.com/G-Ambatte/homebrewery into experimentalNotificationDB 2023-01-15 13:54:28 +13:00
G.Ambatte
04916d8931 Initial notificationAdd functionality 2023-01-15 13:54:19 +13:00
G.Ambatte
f781c2bd56 Merge branch 'master' into experimentalNotificationDB 2023-01-07 10:29:54 +13:00
G.Ambatte
8adf5ce463 Add user-specified DismissKey to Add Notification 2023-01-06 13:53:16 +13:00
G.Ambatte
94afbe5417 Merge branch 'master' into experimentalNotificationDB 2023-01-06 13:51:37 +13:00
G.Ambatte
9e169aba91 Tweak LookUp title 2023-01-05 10:56:50 +13:00
G.Ambatte
f5c7761c61 Add styling to active tab 2023-01-05 10:52:24 +13:00
G.Ambatte
ec040cc2bb Add DisplayNames 2023-01-05 10:04:45 +13:00
G.Ambatte
42125f4041 Update Notification schema 2023-01-05 09:03:51 +13:00
G.Ambatte
a499bb3a54 Add basic Notification Lookup functionality 2023-01-04 23:32:35 +13:00
G.Ambatte
35b4c354f2 Add key prop to Admin tabs 2023-01-04 23:20:11 +13:00
G.Ambatte
b8fd8a7a86 Add Notification lookup to Admin API 2023-01-04 22:52:37 +13:00
G.Ambatte
620cb95ae8 Initial pass at Notification Mongoose model 2023-01-04 22:50:24 +13:00
G.Ambatte
f66664a3e2 Tabify Admin page, add Notification tab 2023-01-04 22:49:38 +13:00
G.Ambatte
d7ee004127 Update Admin pages 2023-01-04 22:08:44 +13:00
G.Ambatte
4a449c7895 Update Buffer method 2023-01-04 22:08:22 +13:00
40 changed files with 2077 additions and 1716 deletions

View File

@@ -10,7 +10,7 @@ orbs:
jobs:
build:
docker:
- image: cimg/node:20.8.0
- image: cimg/node:20.17.0
- image: mongo:4.4
working_directory: ~/homebrewery
@@ -27,7 +27,7 @@ jobs:
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run: sudo npm install -g npm@10.2.0
- run: sudo npm install -g npm@10.8.2
- node/install-packages:
app-dir: ~/homebrewery
cache-path: node_modules
@@ -45,7 +45,7 @@ jobs:
test:
docker:
- image: cimg/node:20.8.0
- image: cimg/node:20.17.0
working_directory: ~/homebrewery
parallelism: 1

View File

@@ -2,35 +2,44 @@ require('./admin.less');
const React = require('react');
const createClass = require('create-react-class');
const BrewUtils = require('./brewUtils/brewUtils.jsx');
const NotificationUtils = require('./notificationUtils/notificationUtils.jsx');
const BrewCleanup = require('./brewCleanup/brewCleanup.jsx');
const BrewLookup = require('./brewLookup/brewLookup.jsx');
const BrewCompress = require ('./brewCompress/brewCompress.jsx');
const Stats = require('./stats/stats.jsx');
const tabGroups = ['brew', 'notifications'];
const Admin = createClass({
getDefaultProps : function() {
return {};
},
getInitialState : function(){
return ({
currentTab : 'brew'
});
},
handleClick : function(newTab){
if(this.state.currentTab === newTab) return;
this.setState({
currentTab : newTab
});
},
render : function(){
return <div className='admin'>
<header>
<div className='container'>
<i className='fas fa-rocket' />
homebrewery admin
</div>
</header>
<div className='container'>
<Stats />
<hr />
<BrewLookup />
<hr />
<BrewCleanup />
<hr />
<BrewCompress />
</div>
<main className='container'>
<nav className='tabs'>
{tabGroups.map((tab, idx)=>{ return <button className={tab===this.state.currentTab ? 'active' : ''} key={idx} onClick={()=>{ return this.handleClick(tab); }}>{tab.toUpperCase()}</button>; })}
</nav>
{this.state.currentTab==='brew' && <BrewUtils />}
{this.state.currentTab==='notifications' && <NotificationUtils />}
</main>
</div>;
}
});

View File

@@ -6,39 +6,95 @@
@import 'font-awesome/css/font-awesome.css';
html,body, #reactContainer, .naturalCrit{
min-height : 100%;
}
html,body, #reactContainer, .naturalCrit { min-height : 100%; }
@sidebarWidth : 250px;
body{
background-color : #eee;
font-family : 'Open Sans', sans-serif;
color : #4b5055;
font-weight : 100;
text-rendering : optimizeLegibility;
margin : 0;
body {
height : 100%;
padding : 0;
height : 100%;
margin : 0;
font-family : 'Open Sans', sans-serif;
font-weight : 100;
color : #4B5055;
background-color : #EEEEEE;
text-rendering : optimizeLegibility;
}
.admin{
:where(.admin) {
header{
header {
padding : 20px 0px;
margin-bottom : 30px;
font-size : 2em;
color : white;
background-color : @red;
font-size: 2em;
padding : 20px 0px;
color : white;
margin-bottom: 30px;
i{
margin-right: 30px;
i { margin-right : 30px; }
}
hr { margin : 30px 0px; }
:where(.container) {
input {
height : 33px;
padding : 0px 10px;
margin-bottom : 20px;
font-family : monospace;
}
button {
height : 37px;
vertical-align : middle;
}
dl {
@maxItemWidth : 132px;
dt {
float : left;
width : @maxItemWidth;
clear : left;
text-align : right;
&::after { content : ' : '; }
}
dd {
height : 1em;
padding : 0 0 0.5em 0;
margin-left : @maxItemWidth + 6px;
}
}
.tabs button {
margin-right : 3px;
margin-left : 3px;
color : black;
background-color : #EEEEEE;
border : 1px solid #444444;
border-radius : 5px;
&:hover {
color : #EEEEEE;
background-color : #444444;
}
&.active {
margin-right : 2px;
margin-left : 2px;
text-decoration : underline;
background-color : #CCCCCC;
border : 2px solid #444444;
}
}
.notificationUtils {
display : flex;
gap : 50px;
justify-content : space-between;
}
}
hr{
margin : 30px 0px;
.error {
background: rgb(178, 54, 54);
color:white;
font-weight: 900;
margin-block:10px;
padding:10px;
}
}

View File

@@ -1,10 +0,0 @@
.BrewCleanup{
.removeBox{
margin-top: 20px;
button{
background-color: @red;
margin-right: 10px;
}
}
}

View File

@@ -1,10 +0,0 @@
.BrewCompress{
.removeBox{
margin-top: 20px;
button{
background-color: @red;
margin-right: 10px;
}
}
}

View File

@@ -1,30 +0,0 @@
.brewLookup{
input{
height : 33px;
margin-bottom : 20px;
padding : 0px 10px;
font-family : monospace;
}
button{
vertical-align : middle;
height : 37px;
}
dl{
@maxItemWidth : 132px;
dt{
float : left;
clear : left;
width : @maxItemWidth;
text-align : right;
&::after {
content: " : ";
}
}
dd{
height : 1em;
margin-left : @maxItemWidth + 6px;
padding : 0 0 0.5em 0;
}
}
}

View File

@@ -0,0 +1,9 @@
.BrewCleanup {
.removeBox {
margin-top : 20px;
button {
margin-right : 10px;
background-color : @red;
}
}
}

View File

@@ -0,0 +1,9 @@
.BrewCompress {
.removeBox {
margin-top : 20px;
button {
margin-right : 10px;
background-color : @red;
}
}
}

View File

@@ -1,4 +1,3 @@
require('./brewLookup.less');
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');

View File

@@ -0,0 +1,24 @@
const React = require('react');
const createClass = require('create-react-class');
const BrewCleanup = require('./brewCleanup/brewCleanup.jsx');
const BrewLookup = require('./brewLookup/brewLookup.jsx');
const BrewCompress = require ('./brewCompress/brewCompress.jsx');
const Stats = require('./stats/stats.jsx');
const BrewUtils = createClass({
render : function(){
return <>
<Stats />
<hr />
<BrewLookup />
<hr />
<BrewCleanup />
<hr />
<BrewCompress />
</>;
}
});
module.exports = BrewUtils;

View File

@@ -0,0 +1,13 @@
.Stats {
position : relative;
.pending {
position : absolute;
top : 0px;
left : 0px;
width : 100%;
height : 100%;
background-color : rgba(238,238,238, 0.5);
}
}

View File

@@ -0,0 +1,109 @@
require('./notificationAdd.less');
const React = require('react');
const { useState, useRef } = require('react');
const request = require('superagent');
const NotificationAdd = ()=>{
const [notificationResult, setNotificationResult] = useState(null);
const [searching, setSearching] = useState(false);
const [error, setError] = useState(null);
const dismissKeyRef = useRef(null);
const titleRef = useRef(null);
const textRef = useRef(null);
const startAtRef = useRef(null);
const stopAtRef = useRef(null);
const saveNotification = async ()=>{
const dismissKey = dismissKeyRef.current.value;
const title = titleRef.current.value;
const text = textRef.current.value;
const startAt = new Date(startAtRef.current.value);
const stopAt = new Date(stopAtRef.current.value);
// Basic validation
if(!dismissKey || !title || !text || isNaN(startAt.getTime()) || isNaN(stopAt.getTime())) {
setError('All fields are required');
return;
}
if(startAt >= stopAt) {
setError('End date must be after the start date!');
return;
}
const data = {
dismissKey,
title,
text,
startAt : startAt?.toISOString() ?? '',
stopAt : stopAt?.toISOString() ?? '',
};
try {
setSearching(true);
setError(null);
const response = await request.post('/admin/notification/add').send(data);
console.log(response.body);
// Reset form fields
dismissKeyRef.current.value = '';
titleRef.current.value = '';
textRef.current.value = '';
setNotificationResult('Notification successfully created.');
setSearching(false);
} catch (err) {
console.log(err.response.body.message);
setError(`Error saving notification: ${err.response.body.message}`);
setSearching(false);
}
};
return (
<div className='notificationAdd'>
<h2>Add Notification</h2>
<label className='field'>
Dismiss Key:
<input className='fieldInput' type='text' ref={dismissKeyRef} required
placeholder='GOOGLEDRIVENOTIF'
/>
</label>
<label className='field'>
Title:
<input className='fieldInput' type='text' ref={titleRef} required
placeholder='Stop using Google Drive as image host'
/>
</label>
<label className='field'>
Text:
<textarea className='fieldInput' type='text' ref={textRef} required
placeholder='Google Drive is not an image hosting site, you should not use it as such.'
>
</textarea>
</label>
<label className='field'>
Start Date:
<input type='date' className='fieldInput' ref={startAtRef} required/>
</label>
<label className='field'>
End Date:
<input type='date' className='fieldInput' ref={stopAtRef} required/>
</label>
<div className='notificationResult'>{notificationResult}</div>
<button className='notificationSave' onClick={saveNotification} disabled={searching}>
<i className={`fas ${searching ? 'fa-spin fa-spinner' : 'fa-save'}`}/>
Save Notification
</button>
{error && <div className='error'>{error}</div>}
</div>
);
};
module.exports = NotificationAdd;

View File

@@ -0,0 +1,37 @@
.notificationAdd {
position : relative;
display : flex;
flex-direction : column;
width : 500px;
.field {
display : grid;
grid-template-columns : 120px 150px;
align-items : center;
justify-items : stretch;
width : 100%;
margin-bottom : 20px;
input {
height : 33px;
padding : 0px 10px;
margin-bottom : unset;
font-family : monospace;
}
textarea {
width : 50ch;
min-height : 7em;
max-height : 20em;
resize : vertical;
padding : 10px;
}
}
button {
width: 200px;
i { margin-right : 10px; }
}
}

View File

@@ -0,0 +1,105 @@
require('./notificationLookup.less');
const React = require('react');
const { useState } = require('react');
const request = require('superagent');
const Moment = require('moment');
const NotificationDetail = ({ notification, onDelete })=>(
<>
<dl>
<dt>Key</dt>
<dd>{notification.dismissKey}</dd>
<dt>Title</dt>
<dd>{notification.title || 'No Title'}</dd>
<dt>Text</dt>
<dd>{notification.text || 'No Text'}</dd>
<dt>Created</dt>
<dd>{Moment(notification.createdAt).format('LLLL')}</dd>
<dt>Start</dt>
<dd>{Moment(notification.startAt).format('LLLL') || 'No Start Time'}</dd>
<dt>Stop</dt>
<dd>{Moment(notification.stopAt).format('LLLL') || 'No End Time'}</dd>
</dl>
<button onClick={()=>onDelete(notification.dismissKey)}>DELETE</button>
</>
);
const NotificationLookup = ()=>{
const [searching, setSearching] = useState(false);
const [error, setError] = useState(null);
const [notifications, setNotifications] = useState([]);
const lookupAll = async ()=>{
setSearching(true);
setError(null);
try {
const res = await request.get('/admin/notification/all');
setNotifications(res.body || []);
} catch (err) {
console.log(err);
setError(`Error looking up notifications: ${err.response.body.message}`);
} finally {
setSearching(false);
}
};
const deleteNotification = async (dismissKey)=>{
if(!dismissKey) return;
const confirmed = window.confirm(
`Really delete notification ${dismissKey}?`
);
if(!confirmed) {
console.log('Delete notification cancelled');
return;
}
console.log('Delete notification confirm');
try {
await request.delete(`/admin/notification/delete/${dismissKey}`);
lookupAll();
} catch (err) {
console.log(err);
setError(`Error deleting notification: ${err.response.body.message}`);
};
};
const renderNotificationsList = ()=>{
if(error)
return <div className='error'>{error}</div>;
if(notifications.length === 0)
return <div className='noNotification'>No notifications available.</div>;
return (
<ul className='notificationList'>
{notifications.map((notification)=>(
<li key={notification.dismissKey} >
<details>
<summary>{notification.title || 'No Title'}</summary>
<NotificationDetail notification={notification} onDelete={deleteNotification} />
</details>
</li>
))}
</ul>
);
};
return (
<div className='notificationLookup'>
<h2>Check all Notifications</h2>
<button onClick={lookupAll}>
<i className={`fas ${searching ? 'fa-spin fa-spinner' : 'fa-search'}`} />
</button>
{renderNotificationsList()}
</div>
);
};
module.exports = NotificationLookup;

View File

@@ -0,0 +1,40 @@
.notificationLookup {
width : 450px;
height : fit-content;
.notificationList {
display : flex;
flex-direction : column;
max-height : 500px;
margin-block : 20px;
overflow : auto;
border : 1px solid;
border-radius : 5px;
li {
padding : 10px;
background : #CCCCCC;
&:nth-child(even) { background : #DDDDDD; }
&:first-child {
border-top-left-radius : 5px;
border-top-right-radius : 5px;
}
&:last-child {
border-bottom-right-radius : 5px;
border-bottom-left-radius : 5px;
}
summary {
font-size : 20px;
font-weight : 900;
}
dl dt{
font-weight: 900;
}
}
}
.noNotification { margin-block : 20px; }
}

View File

@@ -0,0 +1,15 @@
const React = require('react');
const NotificationLookup = require('./notificationLookup/notificationLookup.jsx');
const NotificationAdd = require('./notificationAdd/notificationAdd.jsx');
const NotificationUtils = ()=>{
return (
<section className='notificationUtils'>
<NotificationAdd />
<NotificationLookup />
</section>
);
};
module.exports = NotificationUtils;

View File

@@ -1,28 +0,0 @@
.Stats{
position : relative;
.pending{
position : absolute;
top : 0px;
left : 0px;
height : 100%;
width : 100%;
background-color : rgba(238,238,238, 0.5);
}
dl{
@maxItemWidth : 132px;
dt{
float : left;
clear : left;
width : @maxItemWidth;
text-align : right;
&::after {
content: " : ";
}
}
dd{
margin : 0 0 0 @maxItemWidth + 10px;
padding : 0 0 0.5em 0;
}
}
}

View File

@@ -1,7 +1,7 @@
/*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/
require('./brewRenderer.less');
const React = require('react');
const { useState, useRef, useEffect, useCallback } = React;
const { useState, useRef, useCallback } = React;
const _ = require('lodash');
const MarkdownLegacy = require('naturalcrit/markdownLegacy.js');
@@ -64,7 +64,6 @@ const BrewRenderer = (props)=>{
};
const [state, setState] = useState({
height : PAGE_HEIGHT,
isMounted : false,
visibility : 'hidden',
zoom : 100
@@ -78,17 +77,6 @@ const BrewRenderer = (props)=>{
rawPages = props.text.split(/^\\page$/gm);
}
useEffect(()=>{ // Unmounting steps
return ()=>{window.removeEventListener('resize', updateSize);};
}, []);
const updateSize = ()=>{
setState((prevState)=>({
...prevState,
height : mainRef.current.parentNode.clientHeight,
}));
};
const updateCurrentPage = useCallback(_.throttle((e)=>{
const { scrollTop, clientHeight, scrollHeight } = e.target;
const totalScrollableHeight = scrollHeight - clientHeight;
@@ -163,8 +151,6 @@ const BrewRenderer = (props)=>{
const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount"
setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame
updateSize();
window.addEventListener('resize', updateSize);
renderPages(); //Make sure page is renderable before showing
setState((prevState)=>({
...prevState,
@@ -187,6 +173,12 @@ const BrewRenderer = (props)=>{
}));
};
const styleObject = {};
if(global.config.deployment) {
styleObject.backgroundImage = `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='40px' width='200px'><text x='0' y='15' fill='white' font-size='20'>${global.config.deployment}</text></svg>")`;
}
return (
<>
{/*render dummy page while iFrame is mounting.*/}
@@ -212,11 +204,11 @@ const BrewRenderer = (props)=>{
contentDidMount={frameDidMount}
onClick={()=>{emitClick();}}
>
<div className={'brewRenderer'}
<div className={`brewRenderer ${global.config.deployment && 'deployment'}`}
onScroll={updateCurrentPage}
onKeyDown={handleControlKeys}
tabIndex={-1}
style={{ height: state.height }}>
style={ styleObject }>
{/* Apply CSS from Style tab and render pages from Markdown tab */}
{state.isMounted

View File

@@ -4,6 +4,10 @@
overflow-y : scroll;
will-change : transform;
padding-top : 30px;
height : 100vh;
&.deployment {
background-color: darkred;
}
:where(.pages) {
margin : 30px 0px;
& > :where(.page) {
@@ -39,6 +43,7 @@
overflow-y : unset;
.pages {
margin : 0px;
zoom: 100% !important;
& > .page { box-shadow : unset; }
}
}

View File

@@ -4,7 +4,7 @@ const _ = require('lodash');
import Dialog from '../../../components/dialog.jsx';
const DISMISS_KEY = 'dismiss_notification04-09-24';
const DISMISS_KEY = 'dismiss_notification01-10-24';
const DISMISS_BUTTON = <i className='fas fa-times dismiss' />;
const NotificationPopup = ()=>{

View File

@@ -1,11 +1,11 @@
/*eslint max-lines: ["warn", {"max": 250, "skipBlankLines": true, "skipComments": true}]*/
/*eslint max-lines: ["warn", {"max": 350, "skipBlankLines": true, "skipComments": true}]*/
require('./snippetbar.less');
const React = require('react');
const createClass = require('create-react-class');
const _ = require('lodash');
const cx = require('classnames');
import { getHistoryItems, historyExists } from '../../utils/versionHistory.js';
import { loadHistory } from '../../utils/versionHistory.js';
//Import all themes
const ThemeSnippets = {};
@@ -50,30 +50,47 @@ const Snippetbar = createClass({
renderer : this.props.renderer,
themeSelector : false,
snippets : [],
historyExists : false
showHistory : false,
historyExists : false,
historyItems : []
};
},
componentDidMount : async function() {
componentDidMount : async function(prevState) {
const snippets = this.compileSnippets();
this.setState({
snippets : snippets
});
},
componentDidUpdate : async function(prevProps) {
componentDidUpdate : async function(prevProps, prevState) {
if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme || prevProps.snippetBundle != this.props.snippetBundle) {
this.setState({
snippets : this.compileSnippets()
});
};
if(historyExists(this.props.brew) != this.state.historyExists){
// Update history list if it has changed
const checkHistoryItems = await loadHistory(this.props.brew);
// If all items have the noData property, there is no saved data
const checkHistoryExists = !checkHistoryItems.every((historyItem)=>{
return historyItem?.noData;
});
if(prevState.historyExists != checkHistoryExists){
this.setState({
historyExists : !this.state.historyExists
historyExists : checkHistoryExists
});
};
}
// If any history items have changed, update the list
if(checkHistoryExists && checkHistoryItems.some((historyItem, index)=>{
return index >= prevState.historyItems.length || !_.isEqual(historyItem, prevState.historyItems[index]);
})){
this.setState({
historyItems : checkHistoryItems
});
}
},
mergeCustomizer : function(oldValue, newValue, key) {
@@ -151,12 +168,18 @@ const Snippetbar = createClass({
return this.props.updateBrew(item);
},
toggleHistoryMenu : function(){
this.setState({
showHistory : !this.state.showHistory
});
},
renderHistoryItems : function() {
const historyItems = getHistoryItems(this.props.brew);
if(!this.state.historyExists) return;
return <div className='dropdown'>
{_.map(historyItems, (item, index)=>{
if(!item.savedAt) return;
{_.map(this.state.historyItems, (item, index)=>{
if(item.noData || !item.savedAt) return;
const saveTime = new Date(item.savedAt);
const diffMs = new Date() - saveTime;
@@ -197,9 +220,10 @@ const Snippetbar = createClass({
}
return <div className='editors'>
<div className={`editorTool snippetGroup history ${this.state.historyExists ? 'active' : ''}`} >
<div className={`editorTool snippetGroup history ${this.state.historyExists ? 'active' : ''}`}
onClick={this.toggleHistoryMenu} >
<i className='fas fa-clock-rotate-left' />
{this.state.historyExists && this.renderHistoryItems() }
{ this.state.showHistory && this.renderHistoryItems() }
</div>
<div className={`editorTool undo ${this.props.historySize.undo ? 'active' : ''}`}
onClick={this.props.undo} >

View File

@@ -1,34 +0,0 @@
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');
const Nav = require('naturalcrit/nav/nav.jsx');
const MAX_TITLE_LENGTH = 50;
const EditTitle = createClass({
displayName : 'EditTitleNavItem',
getDefaultProps : function() {
return {
title : '',
onChange : function(){}
};
},
handleChange : function(e){
if(e.target.value.length > MAX_TITLE_LENGTH) return;
this.props.onChange(e.target.value);
},
render : function(){
return <Nav.item className='editTitle'>
<input placeholder='Brew Title' type='text' value={this.props.title} onChange={this.handleChange} />
<div className={cx('charCount', { 'max': this.props.title.length >= MAX_TITLE_LENGTH })}>
{this.props.title.length}/{MAX_TITLE_LENGTH}
</div>
</Nav.item>;
},
});
module.exports = EditTitle;

View File

@@ -36,7 +36,7 @@ const RecentItems = createClass({
//== Add current brew to appropriate recent items list (depending on storageKey) ==//
if(this.props.storageKey == 'edit'){
let editId = this.props.brew.editId;
if(this.props.brew.googleId){
if(this.props.brew.googleId && !this.props.brew.stubbed){
editId = `${this.props.brew.googleId}${this.props.brew.editId}`;
}
edited = _.filter(edited, (brew)=>{
@@ -51,7 +51,7 @@ const RecentItems = createClass({
}
if(this.props.storageKey == 'view'){
let shareId = this.props.brew.shareId;
if(this.props.brew.googleId){
if(this.props.brew.googleId && !this.props.brew.stubbed){
shareId = `${this.props.brew.googleId}${this.props.brew.shareId}`;
}
viewed = _.filter(viewed, (brew)=>{
@@ -83,7 +83,7 @@ const RecentItems = createClass({
let edited = JSON.parse(localStorage.getItem(EDIT_KEY) || '[]');
if(this.props.storageKey == 'edit') {
let prevEditId = prevProps.brew.editId;
if(prevProps.brew.googleId){
if(prevProps.brew.googleId && !this.props.brew.stubbed){
prevEditId = `${prevProps.brew.googleId}${prevProps.brew.editId}`;
}
@@ -91,7 +91,7 @@ const RecentItems = createClass({
return brew.id !== prevEditId;
});
let editId = this.props.brew.editId;
if(this.props.brew.googleId){
if(this.props.brew.googleId && !this.props.brew.stubbed){
editId = `${this.props.brew.googleId}${this.props.brew.editId}`;
}
edited.unshift({

View File

@@ -1,44 +0,0 @@
const React = require('react');
const createClass = require('create-react-class');
const Nav = require('naturalcrit/nav/nav.jsx');
const MAIN_URL = 'https://www.reddit.com/r/UnearthedArcana/submit?selftext=true';
const RedditShare = createClass({
displayName : 'RedditShareNavItem',
getDefaultProps : function() {
return {
brew : {
title : '',
sharedId : '',
text : ''
}
};
},
getText : function(){
},
handleClick : function(){
const url = [
MAIN_URL,
`title=${encodeURIComponent(this.props.brew.title ? this.props.brew.title : 'Check out my brew!')}`,
`text=${encodeURIComponent(this.props.brew.text)}`
].join('&');
window.open(url, '_blank');
},
render : function(){
return <Nav.item icon='fa-reddit-alien' color='red' onClick={this.handleClick}>
share on reddit
</Nav.item>;
},
});
module.exports = RedditShare;

View File

@@ -228,8 +228,8 @@ const EditPage = createClass({
htmlErrors : Markdown.validate(prevState.brew.text)
}));
updateHistory(this.state.brew);
versionHistoryGarbageCollection();
await updateHistory(this.state.brew);
await versionHistoryGarbageCollection();
const transfer = this.state.saveGoogle == _.isNil(this.state.brew.googleId);

View File

@@ -172,6 +172,11 @@ const errorIndex = (props)=>{
**Brew Title:** ${props.brew.brewTitle}`,
// ####### Admin page error #######
'52': dedent`
## Access Denied
You need to provide correct administrator credentials to access this page.`,
'90' : dedent` An unexpected error occurred while looking for these brews.
Try again in a few minutes.`,

View File

@@ -119,6 +119,7 @@ const SharePage = createClass({
<BrewRenderer
text={this.props.brew.text}
style={this.props.brew.style}
lang={this.props.brew.lang}
renderer={this.props.brew.renderer}
theme={this.props.brew.theme}
themeBundle={this.state.themeBundle}

View File

@@ -1,8 +1,10 @@
import * as IDB from 'idb-keyval/dist/index.js';
export const HISTORY_PREFIX = 'HOMEBREWERY-HISTORY';
export const HISTORY_SLOTS = 5;
// History values in minutes
const DEFAULT_HISTORY_SAVE_DELAYS = {
const HISTORY_SAVE_DELAYS = {
'0' : 0,
'1' : 2,
'2' : 10,
@@ -10,29 +12,30 @@ const DEFAULT_HISTORY_SAVE_DELAYS = {
'4' : 12 * 60,
'5' : 2 * 24 * 60
};
// const HISTORY_SAVE_DELAYS = {
// '0' : 0,
// '1' : 1,
// '2' : 2,
// '3' : 3,
// '4' : 4,
// '5' : 5
// };
const DEFAULT_GARBAGE_COLLECT_DELAY = 28 * 24 * 60;
const HISTORY_SAVE_DELAYS = global.config?.historyData?.HISTORY_SAVE_DELAYS ?? DEFAULT_HISTORY_SAVE_DELAYS;
const GARBAGE_COLLECT_DELAY = global.config?.historyData?.GARBAGE_COLLECT_DELAY ?? DEFAULT_GARBAGE_COLLECT_DELAY;
const HB_DB = 'HOMEBREWERY-DB';
const HB_STORE = 'HISTORY';
const GARBAGE_COLLECT_DELAY = 28 * 24 * 60;
// const GARBAGE_COLLECT_DELAY = 10;
function getKeyBySlot(brew, slot){
// Return a string representing the key for this brew and history slot
return `${HISTORY_PREFIX}-${brew.shareId}-${slot}`;
};
function getVersionBySlot(brew, slot){
// Read stored brew data
// - If it exists, parse data to object
// - If it doesn't exist, pass default object
const key = getKeyBySlot(brew, slot);
const storedVersion = localStorage.getItem(key);
const output = storedVersion ? JSON.parse(storedVersion) : { expireAt: '2000-01-01T00:00:00.000Z', shareId: brew.shareId, noData: true };
return output;
};
function updateStoredBrew(brew, slot = 0) {
function parseBrewForStorage(brew, slot = 0) {
// Strip out unneeded object properties
// Returns an array of [ key, brew ]
const archiveBrew = {
title : brew.title,
text : brew.text,
@@ -46,44 +49,55 @@ function updateStoredBrew(brew, slot = 0) {
archiveBrew.expireAt.setMinutes(archiveBrew.expireAt.getMinutes() + HISTORY_SAVE_DELAYS[slot]);
const key = getKeyBySlot(brew, slot);
localStorage.setItem(key, JSON.stringify(archiveBrew));
return [key, archiveBrew];
}
export function historyExists(brew){
return Object.keys(localStorage)
.some((key)=>{
return key.startsWith(`${HISTORY_PREFIX}-${brew.shareId}`);
});
// Create a custom IDB store
async function createHBStore(){
return await IDB.createStore(HB_DB, HB_STORE);
}
export function loadHistory(brew){
const history = {};
export async function loadHistory(brew){
const DEFAULT_HISTORY_ITEM = { expireAt: '2000-01-01T00:00:00.000Z', shareId: brew.shareId, noData: true };
// Load data from local storage to History object
const historyKeys = [];
// Create array of all history keys
for (let i = 1; i <= HISTORY_SLOTS; i++){
history[i] = getVersionBySlot(brew, i);
historyKeys.push(getKeyBySlot(brew, i));
};
return history;
// Load all keys from IDB at once
const dataArray = await IDB.getMany(historyKeys, await createHBStore());
return dataArray.map((data)=>{ return data ?? DEFAULT_HISTORY_ITEM; });
}
export function updateHistory(brew) {
const history = loadHistory(brew);
export async function updateHistory(brew) {
const history = await loadHistory(brew);
// Walk each version position
for (let slot = HISTORY_SLOTS; slot > 0; slot--){
for (let slot = HISTORY_SLOTS - 1; slot >= 0; slot--){
const storedVersion = history[slot];
// If slot has expired, update all lower slots and break
if(new Date() >= new Date(storedVersion.expireAt)){
for (let updateSlot = slot - 1; updateSlot>0; updateSlot--){
// Create array of arrays : [ [key1, value1], [key2, value2], ..., [keyN, valueN] ]
// to pass to IDB.setMany
const historyUpdate = [];
for (let updateSlot = slot; updateSlot > 0; updateSlot--){
// Move data from updateSlot to updateSlot + 1
!history[updateSlot]?.noData && updateStoredBrew(history[updateSlot], updateSlot + 1);
if(!history[updateSlot - 1]?.noData) {
historyUpdate.push(parseBrewForStorage(history[updateSlot - 1], updateSlot + 1));
}
};
// Update the most recent brew
updateStoredBrew(brew, 1);
historyUpdate.push(parseBrewForStorage(brew, 1));
await IDB.setMany(historyUpdate, await createHBStore());
// Break out of data checks because we found an expired value
break;
@@ -91,26 +105,15 @@ export function updateHistory(brew) {
};
};
export function getHistoryItems(brew){
const historyArray = [];
export async function versionHistoryGarbageCollection(){
for (let i = 1; i <= HISTORY_SLOTS; i++){
historyArray.push(getVersionBySlot(brew, i));
}
const entries = await IDB.entries(await createHBStore());
return historyArray;
};
export function versionHistoryGarbageCollection(){
Object.keys(localStorage)
.filter((key)=>{
return key.startsWith(HISTORY_PREFIX);
})
.forEach((key)=>{
const collectAt = new Date(JSON.parse(localStorage.getItem(key)).savedAt);
collectAt.setMinutes(collectAt.getMinutes() + GARBAGE_COLLECT_DELAY);
if(new Date() > collectAt){
localStorage.removeItem(key);
}
});
for (const [key, value] of entries){
const expireAt = new Date(value.savedAt);
expireAt.setMinutes(expireAt.getMinutes() + GARBAGE_COLLECT_DELAY);
if(new Date() > expireAt){
await IDB.del(key, await createHBStore());
};
};
};

View File

@@ -6,5 +6,7 @@
"enable_v3" : true,
"enable_themes" : true,
"local_environments" : ["docker", "local"],
"publicUrl" : "https://homebrewery.naturalcrit.com"
"publicUrl" : "https://homebrewery.naturalcrit.com",
"hb_images" : null,
"hb_fonts" : null
}

1500
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,17 +4,17 @@
"version": "3.15.0",
"engines": {
"npm": "^10.2.x",
"node": "^20.8.x"
"node": "^20.17.x"
},
"repository": {
"type": "git",
"url": "git://github.com/naturalcrit/homebrewery.git"
},
"scripts": {
"dev": "node scripts/dev.js",
"quick": "node scripts/quick.js",
"build": "node scripts/buildHomebrew.js && node scripts/buildAdmin.js",
"builddev": "node scripts/buildHomebrew.js --dev",
"dev": "node --experimental-require-module scripts/dev.js",
"quick": "node --experimental-require-module scripts/quick.js",
"build": "node --experimental-require-module scripts/buildHomebrew.js && node --experimental-require-module scripts/buildAdmin.js",
"builddev": "node --experimental-require-module scripts/buildHomebrew.js --dev",
"lint": "eslint --fix",
"lint:dry": "eslint",
"stylelint": "stylelint --fix **/*.{less}",
@@ -25,6 +25,7 @@
"test:api-unit": "jest \"server/.*.spec.js\" --verbose",
"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:coverage": "jest --coverage --silent --runInBand",
"test:dev": "jest --verbose --watch",
"test:basic": "jest tests/markdown/basic.test.js --verbose",
@@ -37,10 +38,10 @@
"test:hard-breaks": "jest tests/markdown/hard-breaks.test.js --verbose --noStackTrace",
"test:emojis": "jest tests/markdown/emojis.test.js --verbose --noStackTrace",
"test:route": "jest tests/routes/static-pages.test.js --verbose",
"phb": "node scripts/phb.js",
"phb": "node --experimental-require-module scripts/phb.js",
"prod": "set NODE_ENV=production && npm run build",
"postinstall": "npm run build",
"start": "node server.js"
"start": "node --experimental-require-module server.js"
},
"author": "stolksdorf",
"license": "MIT",
@@ -85,23 +86,24 @@
]
},
"dependencies": {
"@babel/core": "^7.25.2",
"@babel/plugin-transform-runtime": "^7.25.4",
"@babel/preset-env": "^7.25.4",
"@babel/preset-react": "^7.24.7",
"@babel/core": "^7.25.8",
"@babel/plugin-transform-runtime": "^7.25.7",
"@babel/preset-env": "^7.25.8",
"@babel/preset-react": "^7.25.7",
"@googleapis/drive": "^8.14.0",
"body-parser": "^1.20.2",
"classnames": "^2.5.1",
"codemirror": "^5.65.6",
"cookie-parser": "^1.4.6",
"cookie-parser": "^1.4.7",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
"dompurify": "^3.1.7",
"expr-eval": "^2.0.2",
"express": "^4.21.0",
"express": "^4.21.1",
"express-async-handler": "^1.2.0",
"express-static-gzip": "2.1.8",
"fs-extra": "11.2.0",
"idb-keyval": "^6.2.1",
"js-yaml": "^4.1.0",
"jwt-simple": "^0.5.6",
"less": "^3.13.1",
@@ -113,7 +115,7 @@
"marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
"mongoose": "^8.7.0",
"mongoose": "^8.7.1",
"nanoid": "3.3.4",
"nconf": "^0.12.1",
"react": "^18.3.1",
@@ -125,11 +127,11 @@
"vitreum": "git+https://git@github.com/calculuschild/vitreum.git"
},
"devDependencies": {
"@stylistic/stylelint-plugin": "^3.1.0",
"eslint": "^9.11.1",
"@stylistic/stylelint-plugin": "^3.1.1",
"eslint": "^9.12.0",
"eslint-plugin-jest": "^28.8.3",
"eslint-plugin-react": "^7.36.1",
"globals": "^15.9.0",
"eslint-plugin-react": "^7.37.1",
"globals": "^15.11.0",
"jest": "^29.7.0",
"jest-expect-message": "^1.1.3",
"postcss-less": "^6.0.0",
@@ -138,4 +140,4 @@
"stylelint-config-recommended": "^14.0.1",
"supertest": "^7.0.0"
}
}
}

View File

@@ -1,7 +1,7 @@
const HomebrewModel = require('./homebrew.model.js').model;
const NotificationModel = require('./notifications.model.js').model;
const router = require('express').Router();
const Moment = require('moment');
//const render = require('vitreum/steps/render');
const templateFn = require('../client/template.js');
const zlib = require('zlib');
@@ -22,7 +22,7 @@ const mw = {
if(process.env.ADMIN_USER === username && process.env.ADMIN_PASS === password){
return next();
}
return res.status(401).send('Access denied');
throw { HBErrorCode: '52', code: 401, message: 'Access denied' };
}
};
@@ -138,12 +138,48 @@ router.get('/admin/stats', mw.adminOnly, async (req, res)=>{
}
});
// ####################### NOTIFICATIONS
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 });
}
});
router.post('/admin/notification/add', mw.adminOnly, async (req, res, next)=>{
console.table(req.body);
try {
const notification = await NotificationModel.addNotification(req.body);
return res.status(201).json(notification);
} catch (error) {
console.log('Error adding notification: ', error.message);
return res.status(500).json({ message: error.message });
}
});
router.delete('/admin/notification/delete/:id', mw.adminOnly, async (req, res, next)=>{
try {
const notification = await NotificationModel.deleteNotification(req.params.id);
return res.json(notification);
} catch (error) {
console.error('Error deleting notification: { key: ', req.params.id, ' error: ', error.message, ' }');
return res.status(500).json({ message: error.message });
}
});
router.get('/admin', mw.adminOnly, (req, res)=>{
templateFn('admin', {
url : req.originalUrl
})
.then((page)=>res.send(page))
.catch((err)=>res.sendStatus(500));
.catch((err)=>{
console.log(err);
res.sendStatus(500);
});
});
module.exports = router;

116
server/admin.api.spec.js Normal file
View File

@@ -0,0 +1,116 @@
const supertest = require('supertest');
const app = supertest.agent(require('app.js').app)
.set('X-Forwarded-Proto', 'https');
const NotificationModel = require('./notifications.model.js').model;
describe('Tests for admin api', ()=>{
afterEach(()=>{
jest.resetAllMocks();
});
describe('Notifications', ()=>{
it('should return list of all notifications', async ()=>{
const testNotifications = ['a', 'b'];
jest.spyOn(NotificationModel, 'find')
.mockImplementationOnce(() => {
return { exec: jest.fn().mockResolvedValue(testNotifications) };
});
const response = await app
.get('/admin/notification/all')
.set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`);
expect(response.status).toBe(200);
expect(response.body).toEqual(testNotifications);
});
it('should add a new notification', async ()=>{
const inputNotification = {
title : 'Test Notification',
text : 'This is a test notification',
startAt : new Date().toISOString(),
stopAt : new Date().toISOString(),
dismissKey : 'testKey'
};
const savedNotification = {
...inputNotification,
_id : expect.any(String),
createdAt : expect.any(String),
startAt : inputNotification.startAt,
stopAt : inputNotification.stopAt,
};
jest.spyOn(NotificationModel.prototype, 'save')
.mockImplementationOnce(function() {
return Promise.resolve(this);
});
const response = await app
.post('/admin/notification/add')
.set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`)
.send(inputNotification);
expect(response.status).toBe(201);
expect(response.body).toEqual(savedNotification);
});
it('should handle error adding a notification without dismissKey', async () => {
const inputNotification = {
title : 'Test Notification',
text : 'This is a test notification',
startAt : new Date().toISOString(),
stopAt : new Date().toISOString()
};
//Change 'save' function to just return itself instead of actually interacting with the database
jest.spyOn(NotificationModel.prototype, 'save')
.mockImplementationOnce(function() {
return Promise.resolve(this);
});
const response = await app
.post('/admin/notification/add')
.set('Authorization', 'Basic ' + Buffer.from('admin:password3').toString('base64'))
.send(inputNotification);
expect(response.status).toBe(500);
expect(response.body).toEqual({ message: 'Dismiss key is required!' });
});
it('should delete a notification based on its dismiss key', async ()=>{
const dismissKey = 'testKey';
jest.spyOn(NotificationModel, 'findOneAndDelete')
.mockImplementationOnce((key) => {
return { exec: jest.fn().mockResolvedValue(key) };
});
const response = await app
.delete(`/admin/notification/delete/${dismissKey}`)
.set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`);
expect(NotificationModel.findOneAndDelete).toHaveBeenCalledWith({'dismissKey': 'testKey'});
expect(response.status).toBe(200);
expect(response.body).toEqual({ dismissKey: 'testKey' });
});
it('should handle error deleting a notification that doesnt exist', async ()=>{
const dismissKey = 'testKey';
jest.spyOn(NotificationModel, 'findOneAndDelete')
.mockImplementationOnce(() => {
return { exec: jest.fn().mockResolvedValue() };
});
const response = await app
.delete(`/admin/notification/delete/${dismissKey}`)
.set('Authorization', `Basic ${Buffer.from('admin:password3').toString('base64')}`);
expect(NotificationModel.findOneAndDelete).toHaveBeenCalledWith({'dismissKey': 'testKey'});
expect(response.status).toBe(500);
expect(response.body).toEqual({ message: 'Notification not found' });
});
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,15 @@ if(!config.get('service_account')){
const defaultAuth = serviceAuth || config.get('google_api_key');
const retryConfig = {
retry: 3, // Number of retry attempts
retryDelay: 100, // Initial delay in milliseconds
retryDelayMultiplier: 2, // Multiplier for exponential backoff
maxRetryDelay: 32000, // Maximum delay in milliseconds
httpMethodsToRetry: ['PATCH'], // Only retry PATCH requests
statusCodesToRetry: [[429, 429]], // Only retry on 429 status code
};
const GoogleActions = {
authCheck : (account, res, updateTokens=true)=>{
@@ -112,9 +121,7 @@ const GoogleActions = {
})
.catch((err)=>{
console.log(`Error Listing Google Brews`);
console.error(err);
throw (err);
//TODO: Should break out here, but continues on for some reason.
});
fileList.push(...obj.data.files);
NextPageToken = obj.data.nextPageToken;
@@ -147,8 +154,9 @@ const GoogleActions = {
return brews;
},
updateGoogleBrew : async (brew)=>{
const drive = googleDrive.drive({ version: 'v3', auth: defaultAuth });
updateGoogleBrew : async (brew, auth = defaultAuth, userIp)=>{
const drive = googleDrive.drive({ version: 'v3', auth: auth });
console.log(auth == defaultAuth ? 'UPDATE w SERVICEACC' : 'UPDATE w USERACC')
await drive.files.update({
fileId : brew.googleId,
@@ -168,7 +176,11 @@ const GoogleActions = {
media : {
mimeType : 'text/plain',
body : brew.text
}
},
headers: {
'X-Forwarded-For': userIp, // Set the X-Forwarded-For header
},
retryConfig
})
.catch((err)=>{
console.log('Error saving to google');

View File

@@ -1,12 +1,16 @@
const config = require('../config.js');
const nodeEnv = config.get('node_env');
const isLocalEnvironment = config.get('local_environments').includes(nodeEnv);
module.exports = (req, res, next)=>{
const isImageRequest = req.get('Accept')?.split(',')
?.filter((h)=>!h.includes('q='))
?.every((h)=>/image\/.*/.test(h));
if(isImageRequest) {
if(isImageRequest && !isLocalEnvironment && !req.url?.startsWith('/staticImages')) {
return res.status(406).send({
message : 'Request for image at this URL is not supported'
});
}
next();
};
};

View File

@@ -0,0 +1,62 @@
const mongoose = require('mongoose');
const _ = require('lodash');
const NotificationSchema = new mongoose.Schema({
dismissKey : { type: String, unique: true, required: true },
title : { type: String, default: '' },
text : { type: String, default: '' },
createdAt : { type: Date, default: Date.now },
startAt : { type: Date, default: Date.now },
stopAt : { type: Date, default: Date.now },
}, { versionKey: false });
NotificationSchema.statics.addNotification = async function(data) {
if(!data.dismissKey) throw { message: 'Dismiss key is required!' };
const defaults = {
title : '',
text : '',
startAt : new Date(),
stopAt : new Date(),
};
const notificationData = _.defaults(data, defaults);
try {
const newNotification = new this(notificationData);
const savedNotification = await newNotification.save();
return savedNotification;
} catch (err) {
throw { message: err.message || 'Error saving notification' };
}
};
NotificationSchema.statics.deleteNotification = async function(dismissKey) {
if(!dismissKey) throw { message: 'Dismiss key is required!' };
try {
const deletedNotification = await this.findOneAndDelete({ dismissKey }).exec();
if(!deletedNotification) {
throw { message: 'Notification not found' };
}
return deletedNotification;
} catch (err) {
throw { message: err.message || 'Error deleting notification' };
}
};
NotificationSchema.statics.getAll = async function() {
try {
const notifications = await this.find().exec();
return notifications;
} catch (err) {
throw { message: err.message || 'Error retrieving notifications' };
}
};
const Notification = mongoose.model('Notification', NotificationSchema);
module.exports = {
schema : NotificationSchema,
model : Notification,
};