mirror of
https://github.com/Athou/commafeed.git
synced 2026-10-24 05:59:11 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
689c20d367 | ||
|
|
43588df2b4 | ||
|
|
d2aaddea33 | ||
|
|
de233f8ae5 | ||
|
|
3179e74dc7 | ||
|
|
6f5e9f5d49 | ||
|
|
8a43fdf200 | ||
|
|
69051e5bbb | ||
|
|
c648e7e0ec | ||
|
|
c91cf376ad | ||
|
|
f4e07597d0 | ||
|
|
64b64d3340 | ||
|
|
57ea87871e | ||
|
|
6154d80bb9 | ||
|
|
ad85745f85 | ||
|
|
41fc77322c | ||
|
|
1b83c26417 | ||
|
|
10ea5f0b93 | ||
|
|
032684de68 | ||
|
|
3efec5ce58 | ||
|
|
4ed32964d9 | ||
|
|
05c1d0cc6e | ||
|
|
3c54924971 | ||
|
|
e57dfc0e3f | ||
|
|
eff8bb16a0 | ||
|
|
87e681b71e | ||
|
|
ac73ef4ea7 | ||
|
|
20945e7443 | ||
|
|
b7b1278111 | ||
|
|
6f9378404f | ||
|
|
79787aca6e |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -113,7 +113,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
|
||||
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
|
||||
|
||||
- name: Install required packages
|
||||
run: sudo apt-get install -y rename unzip
|
||||
|
||||
117
CHANGELOG.md
117
CHANGELOG.md
@@ -1,23 +1,30 @@
|
||||
# Changelog
|
||||
|
||||
## [7.3.2]
|
||||
|
||||
- Prevent users from starring/tagging entries that are not theirs and subsequently reading them (GHSA-prfv-88mm-5gpg)
|
||||
|
||||
## [7.3.1]
|
||||
|
||||
- Prevent Host header injection attacks on the password recovery endpoint. A new setting
|
||||
`commafeed.password-recovery-public-base-url` has been added to specify the base URL to use in password recovery
|
||||
(GHSA-hp8h-jqfm-v7x5)
|
||||
emails. This setting is only required when the password recovery feature is enabled, which is not the default.
|
||||
|
||||
## [7.3.0]
|
||||
|
||||
- Add support for the Google Reader API for native mobile apps that don't support the Fever API
|
||||
- The profile menu now works again on mobile when action buttons are at the bottom of the screen
|
||||
- More SSRF protection regarding IPv6
|
||||
- More SSRF protection regarding IPv6 (GHSA-q5qw-345w-55xg)
|
||||
- Changed the default value of `blockLocalAddresses` to make CommaFeed more secure out-of-the-box. See the "Access to
|
||||
local address blocked" section of the README if you subscribe to feeds that are only available on your local network.
|
||||
|
||||
## [7.2.1]
|
||||
|
||||
- correctly handle favicons hosted at the root of the domain for feeds with non-default ports
|
||||
- prevent XXS injections in third party apps. The CommaFeed React client was already stripping malicious "javascript:" URLs, they are now filtered during feed parsing and no longer stored in the database/served through the REST API.
|
||||
- prevent XXS injections in third party apps. The CommaFeed React client was already stripping malicious "javascript:"
|
||||
URLs, they are now filtered during feed parsing and no longer stored in the database/served through the REST API
|
||||
(GHSA-44pq-9929-f8mq)
|
||||
|
||||
## [7.2.0]
|
||||
|
||||
@@ -27,26 +34,36 @@
|
||||
- Small performance improvements to the feed refresh engine
|
||||
- Removed the Pocket sharing feature because the Pocket service has been discontinued
|
||||
- Prevent the image proxy feature to access any URL to avoid SSRF attacks
|
||||
- Strengthened the SSRF protection by also blocking ULA and CGNAT ranges
|
||||
- Prevent DDOS attacks by filtering OPML files during imports
|
||||
- Strengthened the SSRF protection by also blocking ULA and CGNAT ranges (GHSA-hgrr-mjfp-gmr6)
|
||||
- Prevent DDOS attacks by filtering OPML files during imports (GHSA-83jp-rww3-57rr)
|
||||
|
||||
## [7.1.0]
|
||||
|
||||
- Display the unread count in the header on mobile, since the tree is hidden by default and the unread count is not visible otherwise (#2055)
|
||||
- Display the unread count in the header on mobile, since the tree is hidden by default and the unread count is not
|
||||
visible otherwise (#2055)
|
||||
- The feed refresh engine is now a little bit more performant (#2089)
|
||||
- On shutdown, give the feed refresh engine some time to finish refreshing feeds before killing it. This is controlled by the new `commafeed.shutdown-timeout` setting, which defaults to 2 seconds
|
||||
- On shutdown, give the feed refresh engine some time to finish refreshing feeds before killing it. This is controlled
|
||||
by the new `commafeed.shutdown-timeout` setting, which defaults to 2 seconds
|
||||
|
||||
## [7.0.0]
|
||||
|
||||
- Replaced the JEXL filter expression for marking feed entries as read automatically with a user-friendly visual query builder. Expressions are now evaluated with Common Expression Language, which is safer than JEXL and sanboxed by default.
|
||||
- Added a per-feed setting for sending push notifications to ntfy, Gotify or Pushover when new feed entries are discovered (#1610)
|
||||
- Replaced the JEXL filter expression for marking feed entries as read automatically with a user-friendly visual query
|
||||
builder. Expressions are now evaluated with Common Expression Language, which is safer than JEXL and sanboxed by
|
||||
default.
|
||||
- Added a per-feed setting for sending push notifications to ntfy, Gotify or Pushover when new feed entries are
|
||||
discovered (#1610)
|
||||
- Added a per-feed setting for marking entries as read after a number of days (#2041)
|
||||
- The default value of `commafeed.http-client.block-local-addresses` is now false, allowing users to subscribe to feeds only available on their local network. This may be a security risk (SSRF) if your instance is accessible by untrusted users, so you may want to set it to true if you host a public instance of CommaFeed with user registeration enabled.
|
||||
- When `commafeed.http-client.block-local-addresses` is enabled, SSRF is now also mitigated by blocking public websites redirecting to local ones.
|
||||
- The default value of `commafeed.http-client.block-local-addresses` is now false, allowing users to subscribe to feeds
|
||||
only available on their local network. This may be a security risk (SSRF) if your instance is accessible by untrusted
|
||||
users, so you may want to set it to true if you host a public instance of CommaFeed with user registeration enabled.
|
||||
- When `commafeed.http-client.block-local-addresses` is enabled, SSRF is now also mitigated by blocking public websites
|
||||
redirecting to local ones.
|
||||
|
||||
## [6.2.0]
|
||||
|
||||
- Starred entries are no longer deleted after a certain amount of time, they are now kept indefinitely. The new `commafeed.database.cleanup.keep-starred-entries` setting can be disabled to restore the previous behavior if you want to keep deleting starred entries during normal entries cleanup (#1581)
|
||||
- Starred entries are no longer deleted after a certain amount of time, they are now kept indefinitely. The new
|
||||
`commafeed.database.cleanup.keep-starred-entries` setting can be disabled to restore the previous behavior if you want
|
||||
to keep deleting starred entries during normal entries cleanup (#1581)
|
||||
|
||||
## [6.1.1]
|
||||
|
||||
@@ -54,16 +71,21 @@
|
||||
|
||||
## [6.1.0]
|
||||
|
||||
- When clicking on the password reset link, a random password is no longer generated automatically. The user is now redirected to a page where they can set their own password (#2023)
|
||||
- When clicking on the password reset link, a random password is no longer generated automatically. The user is now
|
||||
redirected to a page where they can set their own password (#2023)
|
||||
- Use browser preferred language instead of English when using CommaFeed for the first time (#2018)
|
||||
- The profile menu is now closed when scrolling the page (#2019)
|
||||
- The "disable pull to refresh" feature is now disabled by default (#2030)
|
||||
|
||||
## [6.0.0]
|
||||
|
||||
- When booting CommaFeed for the first time, the default "admin" account is no longer created automatically. A setup wizard will guide you through the creation of an admin account
|
||||
- Default password complexity requirements have been lowered for local network deployments, where strict password rules are often unnecessary. The `commafeed.users.strict-password-policy` setting has been replaced by `commafeed.users.minimum-password-length` with a default value of `4` (#1916)
|
||||
- Email addresses are no longer required when creating users and when they update their profile. The `commafeed.users.email-address-required` setting has been added to restore the previous behavior (#1914)
|
||||
- When booting CommaFeed for the first time, the default "admin" account is no longer created automatically. A setup
|
||||
wizard will guide you through the creation of an admin account
|
||||
- Default password complexity requirements have been lowered for local network deployments, where strict password rules
|
||||
are often unnecessary. The `commafeed.users.strict-password-policy` setting has been replaced by
|
||||
`commafeed.users.minimum-password-length` with a default value of `4` (#1916)
|
||||
- Email addresses are no longer required when creating users and when they update their profile. The
|
||||
`commafeed.users.email-address-required` setting has been added to restore the previous behavior (#1914)
|
||||
- Java 25+ is now required to build and run CommaFeed
|
||||
|
||||
## [5.12.1]
|
||||
@@ -93,15 +115,18 @@
|
||||
|
||||
## [5.10.0]
|
||||
|
||||
- Add an indicator next to each feed's unread count in the tree to show when new entries are discovered while the app is open (#1762)
|
||||
- Add an indicator next to each feed's unread count in the tree to show when new entries are discovered while the app is
|
||||
open (#1762)
|
||||
- Feeds with uppercase HTTP:// or HTTPS:// URLs are now correctly handled again
|
||||
- The aarch64 native executable now also works on the Raspberry Pi 5 (#1795)
|
||||
- Improve general performance of the UI by reducing the number of re-renders, especially when a lot of entries are displayed (#1087)
|
||||
- Improve general performance of the UI by reducing the number of re-renders, especially when a lot of entries are
|
||||
displayed (#1087)
|
||||
|
||||
## [5.9.0]
|
||||
|
||||
- A lot of CSS classes have been added to the elements of the application to ease custom CSS rules (#1757)
|
||||
- Added a link in the README to the [documentation](https://athou.github.io/commafeed/documentation/custom-css/) of the new CSS classes
|
||||
- Added a link in the README to the [documentation](https://athou.github.io/commafeed/documentation/custom-css/) of the
|
||||
new CSS classes
|
||||
- Static resources are now cached for much longer (#1782)
|
||||
|
||||
## [5.8.0]
|
||||
@@ -110,7 +135,8 @@
|
||||
- A font size slider is now available to change the size of the text of feed entries (#1462)
|
||||
- The "mark all as read" confirmation setting now also applies to the "shift+a" keyboard shortcut (#1744)
|
||||
- CommaFeed wil try to match the language of the browser before defaulting to english (#1767)
|
||||
- The default value for the number of entries to keep above the selected entry when scrolling is now 1 instead of 0 to match what other feed readers do
|
||||
- The default value for the number of entries to keep above the selected entry when scrolling is now 1 instead of 0 to
|
||||
match what other feed readers do
|
||||
|
||||
## [5.7.0]
|
||||
|
||||
@@ -129,14 +155,22 @@
|
||||
|
||||
## [5.6.0]
|
||||
|
||||
- To better respect the bandwidth of feed owners, the default value of `commafeed.feed-refresh.interval-empirical` is now true. This means feeds no longer refresh exactly every 5 minutes (the default value of `commafeed.feed-refresh.interval`) but between 5 minutes and 4 hours (the default value of the new `commafeed.feed-refresh.max-interval` setting). The interval is calculated based on feed activity, so highly active feeds refresh more often (#1677)
|
||||
- To better respect the bandwidth of feed owners, the default value of `commafeed.feed-refresh.interval-empirical` is
|
||||
now true. This means feeds no longer refresh exactly every 5 minutes (the default value of
|
||||
`commafeed.feed-refresh.interval`) but between 5 minutes and 4 hours (the default value of the new
|
||||
`commafeed.feed-refresh.max-interval` setting). The interval is calculated based on feed activity, so highly active
|
||||
feeds refresh more often (#1677)
|
||||
- Many previously hardcoded values used in feed refresh interval calculation are now exposed as settings (#1677)
|
||||
- Access to local addresses is now blocked to mitigate server-side request forgery (SSRF) attacks, which could potentially expose internal resources. You might want to disable the new `commafeed.http-client.block-local-addresses` setting if you subscribe to feeds only available on your local network and you trust all your users
|
||||
- If a feed responds with a "429 - Too many requests" response, a backoff mechanism is triggered when the response does not contain a "Retry-After" header
|
||||
- Access to local addresses is now blocked to mitigate server-side request forgery (SSRF) attacks, which could
|
||||
potentially expose internal resources. You might want to disable the new `commafeed.http-client.block-local-addresses`
|
||||
setting if you subscribe to feeds only available on your local network and you trust all your users
|
||||
- If a feed responds with a "429 - Too many requests" response, a backoff mechanism is triggered when the response does
|
||||
not contain a "Retry-After" header
|
||||
|
||||
## [5.5.0]
|
||||
|
||||
- CommaFeed now honors the Retry-After response header and will not try to refresh a feed sooner than the value of this header
|
||||
- CommaFeed now honors the Retry-After response header and will not try to refresh a feed sooner than the value of this
|
||||
header
|
||||
- Audio enclosures (e.g. podcasts) now fill available entry width
|
||||
- Fix an issue with some labels not correctly internationalized
|
||||
|
||||
@@ -153,8 +187,10 @@
|
||||
## [5.3.5]
|
||||
|
||||
- Fixed an issue with the aspect ratio of images of some feeds (#1595)
|
||||
- CommaFeed now honors the Cache-Control response header and will not try to refresh a feed sooner than its max-age property (#1615)
|
||||
- Added support for compilation with JDK 23+. If you're building CommaFeed from sources with a JDK 17 or 21, you may need to update it to the most recent patch version to support `-proc:full` (#1618)
|
||||
- CommaFeed now honors the Cache-Control response header and will not try to refresh a feed sooner than its max-age
|
||||
property (#1615)
|
||||
- Added support for compilation with JDK 23+. If you're building CommaFeed from sources with a JDK 17 or 21, you may
|
||||
need to update it to the most recent patch version to support `-proc:full` (#1618)
|
||||
|
||||
## [5.3.4]
|
||||
|
||||
@@ -181,19 +217,22 @@
|
||||
|
||||
- Added an option to keep a number of entries above the selected entry when scrolling
|
||||
- Added a cache to the HTTP client to reduce the number of requests made to feeds when subscribing (#1431)
|
||||
- Feeds are no longer refreshed between the moment its last user unsubscribes and the moment the feed is cleaned up (every hour)
|
||||
- Feeds are no longer refreshed between the moment its last user unsubscribes and the moment the feed is cleaned up
|
||||
(every hour)
|
||||
- Fixed an issue that could cause entries to not correctly load when using keyboard navigation (#1557)
|
||||
|
||||
## [5.1.1]
|
||||
|
||||
- Fixed database migration issue when upgrading from 5.0.0 to 5.1.0 on MariaDB (#1544)
|
||||
- When feeds without unread entries are hidden from the tree, the feed is displayed in the tree until another one is selected (#1543)
|
||||
- When feeds without unread entries are hidden from the tree, the feed is displayed in the tree until another one is
|
||||
selected (#1543)
|
||||
|
||||
## [5.1.0]
|
||||
|
||||
- Added a setting for showing/hiding unread count in the browser's tab title/favicon (#1518)
|
||||
- Fixed an issue that could prevent the app from starting on some systems (#1532)
|
||||
- Added a cache busting filter for the webapp index.html and openapi documentation to make sure they are always up to date
|
||||
- Added a cache busting filter for the webapp index.html and openapi documentation to make sure they are always up to
|
||||
date
|
||||
- Reduced database cleanup log verbosity
|
||||
|
||||
## [5.0.2]
|
||||
@@ -208,9 +247,9 @@
|
||||
## [5.0.0]
|
||||
|
||||
CommaFeed is now powered by Quarkus instead of Dropwizard. Read the rationale behind this change in
|
||||
the [announcement](https://github.com/Athou/commafeed/discussions/1517).
|
||||
The gist of it is that CommaFeed can now be compiled to a native binary, resulting in blazing fast startup times (around
|
||||
0.3s) and very low memory footprint (< 50M).
|
||||
the [announcement](https://github.com/Athou/commafeed/discussions/1517). The gist of it is that CommaFeed can now be
|
||||
compiled to a native binary, resulting in blazing fast startup times (around 0.3s) and very low memory footprint (<
|
||||
50M).
|
||||
|
||||
- CommaFeed now has a different package for each supported database.
|
||||
- If you are deploying CommaFeed with a precompiled package, please
|
||||
@@ -266,8 +305,8 @@ The gist of it is that CommaFeed can now be compiled to a native binary, resulti
|
||||
- add a button in the entry headers to open links in a new tab (#1333)
|
||||
- add two options in the settings to toggle those buttons
|
||||
- accept .opml file extension when importing and export with the .opml extension
|
||||
- the "mark as read" option is no longer shown in the context menu for entries that are too old to be marked as read (
|
||||
older than `keepStatusDays`) (#1303)
|
||||
- the "mark as read" option is no longer shown in the context menu for entries that are too old to be marked as read
|
||||
(older than `keepStatusDays`) (#1303)
|
||||
|
||||
## [4.3.3]
|
||||
|
||||
@@ -311,9 +350,8 @@ The gist of it is that CommaFeed can now be compiled to a native binary, resulti
|
||||
- it is now possible to open the sidebar on mobile by swiping to the right (#1098)
|
||||
- swiping to mark entries as read/unread changed from swiping right to left because swiping right now opens the sidebar
|
||||
- the full hierarchy of categories are now displayed in the category dropdown (#1045)
|
||||
- added a setting `maxEntriesAgeDays` to delete old entries based on their age during database cleanup.
|
||||
The setting is disabled by default for existing installations, except for the docker image where it is enabled and set
|
||||
to 365 days
|
||||
- added a setting `maxEntriesAgeDays` to delete old entries based on their age during database cleanup. The setting is
|
||||
disabled by default for existing installations, except for the docker image where it is enabled and set to 365 days
|
||||
- if user registrations are disabled on your instance which is the default behavior, users are redirected on the login
|
||||
page instead of the welcome page when not logged in (#1185)
|
||||
- the sidebar resizer is no longer shown in the middle of the screen on mobile
|
||||
@@ -339,8 +377,8 @@ The gist of it is that CommaFeed can now be compiled to a native binary, resulti
|
||||
request, reducing CPU usage
|
||||
- updated UI library Mantine to 7.0, improving performance
|
||||
- the h2 embedded database is now compacted on shutdown to reclaim unused space
|
||||
- the admin connector on port 8084 is now disabled in config.yml.example. Disabling it in your config.yml is
|
||||
recommended (see https://github.com/Athou/commafeed/commit/929df60f09cce56020b0962ab111cd8349b271b0)
|
||||
- the admin connector on port 8084 is now disabled in config.yml.example. Disabling it in your config.yml is recommended
|
||||
(see https://github.com/Athou/commafeed/commit/929df60f09cce56020b0962ab111cd8349b271b0)
|
||||
- migrated documentation from swagger 2 to openapi 3
|
||||
- added a GET method to the fever api to indicate that the endpoint is working correctly when accessed from a browser
|
||||
- the websocket connection can now be disabled, the websocket ping interval and the tree reload interval can now be
|
||||
@@ -582,7 +620,6 @@ The gist of it is that CommaFeed can now be compiled to a native binary, resulti
|
||||
## [2.0.0]
|
||||
|
||||
- The backend has been completely rewritten using Dropwizard instead of TomEE, resulting in a lot less memory
|
||||
consumption and better overall performances.
|
||||
See the README on how to build CommaFeed from now on.
|
||||
consumption and better overall performances. See the README on how to build CommaFeed from now on.
|
||||
- CommaFeed should no longer fetch the same feed multiple times in a row
|
||||
- Users can use their username or email to log in
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.5.8/schema.json",
|
||||
"$schema": "https://biomejs.dev/schemas/2.5.9/schema.json",
|
||||
"formatter": {
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 4,
|
||||
|
||||
198
commafeed-client/package-lock.json
generated
198
commafeed-client/package-lock.json
generated
@@ -20,11 +20,11 @@
|
||||
"@mantine/notifications": "9.5.1",
|
||||
"@mantine/spotlight": "9.5.1",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@react-querybuilder/mantine": "8.22.5",
|
||||
"@react-querybuilder/mantine": "8.23.0",
|
||||
"@reduxjs/toolkit": "2.12.0",
|
||||
"@rolldown/plugin-babel": "0.2.3",
|
||||
"axios": "1.19.0",
|
||||
"dayjs": "1.11.21",
|
||||
"dayjs": "1.11.23",
|
||||
"escape-string-regexp": "5.0.0",
|
||||
"interweave": "13.1.1",
|
||||
"monaco-editor": "0.56.0",
|
||||
@@ -36,7 +36,7 @@
|
||||
"react-draggable": "4.7.1",
|
||||
"react-icons": "5.7.0",
|
||||
"react-infinite-scroller": "1.2.6",
|
||||
"react-querybuilder": "8.22.5",
|
||||
"react-querybuilder": "8.23.0",
|
||||
"react-redux": "9.3.0",
|
||||
"react-router-dom": "7.18.2",
|
||||
"react-swipeable": "7.0.2",
|
||||
@@ -48,13 +48,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/types": "^8.0.4",
|
||||
"@biomejs/biome": "2.5.8",
|
||||
"@biomejs/biome": "2.5.9",
|
||||
"@lingui/babel-plugin-lingui-macro": "6.6.0",
|
||||
"@lingui/cli": "6.6.0",
|
||||
"@lingui/vite-plugin": "6.6.0",
|
||||
"@testing-library/jest-dom": "7.0.1",
|
||||
"@testing-library/react": "16.3.2",
|
||||
"@testing-library/user-event": "14.6.4",
|
||||
"@testing-library/user-event": "14.6.5",
|
||||
"@types/mousetrap": "1.6.15",
|
||||
"@types/react": "19.2.18",
|
||||
"@types/react-dom": "19.2.4",
|
||||
@@ -67,7 +67,7 @@
|
||||
"typescript": "7.0.2",
|
||||
"vite": "8.2.1",
|
||||
"vite-plugin-checker": "0.14.5",
|
||||
"vitest": "4.1.10",
|
||||
"vitest": "4.1.11",
|
||||
"yaml": "2.9.0"
|
||||
}
|
||||
},
|
||||
@@ -592,9 +592,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/biome": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.8.tgz",
|
||||
"integrity": "sha512-aeAeeJB9fSDc7Gq+2GqpQxA0qBj6gj1k2R6L1cYqGePKP/baIq1WX8y6B+D+nRsO5ViQL22K/8IwbqERW0q1nw==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.9.tgz",
|
||||
"integrity": "sha512-KkgCvdHB4IhtpHpF564plA9jo6fDOwWGQ/3jvreLzgOtRLEDoPqr7QO9qejNA8jKwDsSkAKr77hqBHnyUbIw4g==",
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"bin": {
|
||||
@@ -608,20 +608,20 @@
|
||||
"url": "https://opencollective.com/biome"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@biomejs/cli-darwin-arm64": "2.5.8",
|
||||
"@biomejs/cli-darwin-x64": "2.5.8",
|
||||
"@biomejs/cli-linux-arm64": "2.5.8",
|
||||
"@biomejs/cli-linux-arm64-musl": "2.5.8",
|
||||
"@biomejs/cli-linux-x64": "2.5.8",
|
||||
"@biomejs/cli-linux-x64-musl": "2.5.8",
|
||||
"@biomejs/cli-win32-arm64": "2.5.8",
|
||||
"@biomejs/cli-win32-x64": "2.5.8"
|
||||
"@biomejs/cli-darwin-arm64": "2.5.9",
|
||||
"@biomejs/cli-darwin-x64": "2.5.9",
|
||||
"@biomejs/cli-linux-arm64": "2.5.9",
|
||||
"@biomejs/cli-linux-arm64-musl": "2.5.9",
|
||||
"@biomejs/cli-linux-x64": "2.5.9",
|
||||
"@biomejs/cli-linux-x64-musl": "2.5.9",
|
||||
"@biomejs/cli-win32-arm64": "2.5.9",
|
||||
"@biomejs/cli-win32-x64": "2.5.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-arm64": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.8.tgz",
|
||||
"integrity": "sha512-mk1QON9PHllvvLN5gU3f4rMxeh4syK5p9OvKyWH6/W8ueh04uaC8TUXXByhGufWf/y5mQc03ZLM45zU+cmqMjA==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.9.tgz",
|
||||
"integrity": "sha512-am22pX2aBqznqq1eMyIj/bZ++riF3Lk6ct7cbv+gQK0csFhr+d8O0RkOi2FF2qSgFgANbqNkIZ0/PxlnW2pLFg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -636,9 +636,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-x64": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.8.tgz",
|
||||
"integrity": "sha512-bsGwFMBNyHPyiLSsQcZJxdoRrg1V4JL+d7wEsvUBczlP9U9lwM+7mzQHxI4o1mhBsTmdOBbAb6fHU3Z3snN45w==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.9.tgz",
|
||||
"integrity": "sha512-l44KWDHLDvEnD0N/XcrVs7VXb3A18xL7QS3WB0eL93wbmk529ffIG55vleGCqaunpRUjLrdnjK05Qki1dsjylg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -653,9 +653,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.8.tgz",
|
||||
"integrity": "sha512-XmFiA0WPYFC+uiUDC8WRFzAIH9bo7vwQLav38Uoq4ETC+T/+uBi0TsYGJECkugY3r8USl3jc+Ae2/irAF6F2lQ==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.9.tgz",
|
||||
"integrity": "sha512-ICaK+IYaVZvKbBxX2rwrPT0DdUDMnE9Vm3nQGe+mltQPmUg19pONzkPWGdY4FCsoreDETWDynvdt4ysCbF5gNQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -673,9 +673,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64-musl": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.8.tgz",
|
||||
"integrity": "sha512-VcJNbstduTHx83NGAdhp78/JOcP45BZHXL7yNsfI1uGzdUgegAz2s+mSoT7wK6PBNzLoqG0zDOXaz/RQYVtSiw==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.9.tgz",
|
||||
"integrity": "sha512-7ImVPwBLCtkmpR5esd8RHhTqW94f0JLJQum6AneYcy94jRm18TaPPm7slaigGzFhfgt3QiD1Vj52LKmBAnKizA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -693,9 +693,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.8.tgz",
|
||||
"integrity": "sha512-S5wcm9OBDvLHodD4PUaN488hCpco9QD/9ZxuYJiw4euWtr/oQvLR72z2ixItH8Wd5BCm6FZaeb+YNvOoM1xHtQ==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.9.tgz",
|
||||
"integrity": "sha512-z22Q/zFYSvbIJfW1CbfZPu4X8PddS6Qd2ORbc6h+aT6EcwAxUF3m6fA4HjNvA3TU4X0dTJRwNPB165ES3PJXzg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -713,9 +713,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64-musl": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.8.tgz",
|
||||
"integrity": "sha512-kKmiyokeISRGq2FLwvr+TzsgBusfxaZ0FZNLcOYOpCK/78tRrEjeEBLvq3xLZMpqbANgJdRPI7vZX8ZL37u9/w==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.9.tgz",
|
||||
"integrity": "sha512-RXGaD0o1/pTTguYw1aeDJh9ad6Lfrui0fI7mBderTyGr7WuUJkBIttgLkR3XJyoxOkkgfBDspaUT8wXArTqLZw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -733,9 +733,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-arm64": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.8.tgz",
|
||||
"integrity": "sha512-nILH0mzm3Hi3iEdd7o7GpB8kBR/mSQwfQG/tyBqyNrY2GFtcgwfV9nV8xLmbtUpMNY/Oi0Ml1XgfR4flOdq+AA==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.9.tgz",
|
||||
"integrity": "sha512-nHK+/HHC+D0ogAHUxomgoSTdjImb6fmNNVTKmf0tyu4eDL1DqPKIHc+i+UL8+b0RnAu8224qo8F2tCVnaT0A3w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -750,9 +750,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-x64": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.8.tgz",
|
||||
"integrity": "sha512-I2czzXTY61f3nFJxXoMDq80t7MivxDEnCjE+8sDKoFfcKMaoQdkqhIFQ3KyY0XLzeSpUBYeNAXgD+iOV/BU0VA==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.9.tgz",
|
||||
"integrity": "sha512-Yiq0H56LjXSSw/hd9YkXgSLQfzyDJzbzU2TezozxyNw+uKWAqOtqGVvBfzKRRDiaFF5avGAhHdWKx7LtDOShUw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1675,9 +1675,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@react-querybuilder/mantine": {
|
||||
"version": "8.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@react-querybuilder/mantine/-/mantine-8.22.5.tgz",
|
||||
"integrity": "sha512-ciLXWRh6YhFdQQwkS9x0h/z7nxe2thtq3mseTC3/KV2SQBrjBDiBoRVxQe8H2koL0FuasTmdiPU/TqDkqV9Acg==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-querybuilder/mantine/-/mantine-8.23.0.tgz",
|
||||
"integrity": "sha512-gAUV9bkdMH5+ZALKYieTdOVTPMzDa/ZWw+5QdklM6u6r6o4mtgo0pIf2c9b0M008lUISmo71mcR2z1Bn2zCGnQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@mantine/core": ">=7",
|
||||
@@ -1685,7 +1685,7 @@
|
||||
"@mantine/hooks": ">=7",
|
||||
"dayjs": ">=1",
|
||||
"react": ">=18",
|
||||
"react-querybuilder": "8.22.5"
|
||||
"react-querybuilder": "8.23.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit": {
|
||||
@@ -2096,9 +2096,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/user-event": {
|
||||
"version": "14.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.4.tgz",
|
||||
"integrity": "sha512-QCGwP6QrjypBLwyj5cuyfVamkaIEy/XGY+1VDehbtbQqOggYmTFpFOdWR5mPz14vX8vXLMVjDHlRNBcClyO9ew==",
|
||||
"version": "14.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.5.tgz",
|
||||
"integrity": "sha512-FhqjldLTpteueBaKflhNFlMT3+PM0O5fiBUivht6b9CZ1eesJyy7+g3Jr7XwJzt/Hip3ZG5hWwK1MX1FuDiE4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2657,16 +2657,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz",
|
||||
"integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz",
|
||||
"integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "4.1.10",
|
||||
"@vitest/utils": "4.1.10",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"chai": "^6.2.2",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
@@ -2675,13 +2675,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "4.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz",
|
||||
"integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz",
|
||||
"integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "4.1.10",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.21"
|
||||
},
|
||||
@@ -2702,9 +2702,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "4.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz",
|
||||
"integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz",
|
||||
"integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2715,13 +2715,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "4.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz",
|
||||
"integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz",
|
||||
"integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.10",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
@@ -2729,14 +2729,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "4.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz",
|
||||
"integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz",
|
||||
"integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.10",
|
||||
"@vitest/utils": "4.1.10",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
@@ -2745,9 +2745,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "4.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz",
|
||||
"integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz",
|
||||
"integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -2755,13 +2755,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "4.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz",
|
||||
"integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz",
|
||||
"integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.10",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
@@ -3262,9 +3262,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.21",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz",
|
||||
"integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==",
|
||||
"version": "1.11.23",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz",
|
||||
"integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
@@ -5080,12 +5080,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-querybuilder": {
|
||||
"version": "8.22.5",
|
||||
"resolved": "https://registry.npmjs.org/react-querybuilder/-/react-querybuilder-8.22.5.tgz",
|
||||
"integrity": "sha512-UyLmmxB0fp9O54pexYW/fV3skQaQT7rW1wM3LzIEbnzStvXiCj8dEQDYqwOspwDajCOScYyFBVn6tMC05OpYTg==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/react-querybuilder/-/react-querybuilder-8.23.0.tgz",
|
||||
"integrity": "sha512-Pfa/16QVitajArvcJNgqnzqKoAj8lr0W/e7ubqCgLka1Tt9pkxSGQSjUkcKjxumpct8VsnAkKc2IFigAJCSbyg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-querybuilder/core": "^8.22.5",
|
||||
"@react-querybuilder/core": "^8.23.0",
|
||||
"@reduxjs/toolkit": "^2.12.0",
|
||||
"react-redux": "^9.3.0"
|
||||
},
|
||||
@@ -6070,19 +6070,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.1.10",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz",
|
||||
"integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz",
|
||||
"integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.1.10",
|
||||
"@vitest/mocker": "4.1.10",
|
||||
"@vitest/pretty-format": "4.1.10",
|
||||
"@vitest/runner": "4.1.10",
|
||||
"@vitest/snapshot": "4.1.10",
|
||||
"@vitest/spy": "4.1.10",
|
||||
"@vitest/utils": "4.1.10",
|
||||
"@vitest/expect": "4.1.11",
|
||||
"@vitest/mocker": "4.1.11",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"@vitest/runner": "4.1.11",
|
||||
"@vitest/snapshot": "4.1.11",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"magic-string": "^0.30.21",
|
||||
@@ -6110,12 +6110,12 @@
|
||||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||
"@vitest/browser-playwright": "4.1.10",
|
||||
"@vitest/browser-preview": "4.1.10",
|
||||
"@vitest/browser-webdriverio": "4.1.10",
|
||||
"@vitest/coverage-istanbul": "4.1.10",
|
||||
"@vitest/coverage-v8": "4.1.10",
|
||||
"@vitest/ui": "4.1.10",
|
||||
"@vitest/browser-playwright": "4.1.11",
|
||||
"@vitest/browser-preview": "4.1.11",
|
||||
"@vitest/browser-webdriverio": "4.1.11",
|
||||
"@vitest/coverage-istanbul": "4.1.11",
|
||||
"@vitest/coverage-v8": "4.1.11",
|
||||
"@vitest/ui": "4.1.11",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
"@mantine/notifications": "9.5.1",
|
||||
"@mantine/spotlight": "9.5.1",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@react-querybuilder/mantine": "8.22.5",
|
||||
"@react-querybuilder/mantine": "8.23.0",
|
||||
"@reduxjs/toolkit": "2.12.0",
|
||||
"@rolldown/plugin-babel": "0.2.3",
|
||||
"axios": "1.19.0",
|
||||
"dayjs": "1.11.21",
|
||||
"dayjs": "1.11.23",
|
||||
"escape-string-regexp": "5.0.0",
|
||||
"interweave": "13.1.1",
|
||||
"monaco-editor": "0.56.0",
|
||||
@@ -43,7 +43,7 @@
|
||||
"react-draggable": "4.7.1",
|
||||
"react-icons": "5.7.0",
|
||||
"react-infinite-scroller": "1.2.6",
|
||||
"react-querybuilder": "8.22.5",
|
||||
"react-querybuilder": "8.23.0",
|
||||
"react-redux": "9.3.0",
|
||||
"react-router-dom": "7.18.2",
|
||||
"react-swipeable": "7.0.2",
|
||||
@@ -55,13 +55,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/types": "^8.0.4",
|
||||
"@biomejs/biome": "2.5.8",
|
||||
"@biomejs/biome": "2.5.9",
|
||||
"@lingui/babel-plugin-lingui-macro": "6.6.0",
|
||||
"@lingui/cli": "6.6.0",
|
||||
"@lingui/vite-plugin": "6.6.0",
|
||||
"@testing-library/jest-dom": "7.0.1",
|
||||
"@testing-library/react": "16.3.2",
|
||||
"@testing-library/user-event": "14.6.4",
|
||||
"@testing-library/user-event": "14.6.5",
|
||||
"@types/mousetrap": "1.6.15",
|
||||
"@types/react": "19.2.18",
|
||||
"@types/react-dom": "19.2.4",
|
||||
@@ -74,7 +74,7 @@
|
||||
"typescript": "7.0.2",
|
||||
"vite": "8.2.1",
|
||||
"vite-plugin-checker": "0.14.5",
|
||||
"vitest": "4.1.10",
|
||||
"vitest": "4.1.11",
|
||||
"yaml": "2.9.0"
|
||||
},
|
||||
"overrides": {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.commafeed</groupId>
|
||||
<artifactId>commafeed</artifactId>
|
||||
<version>7.3.1</version>
|
||||
<version>7.3.2</version>
|
||||
</parent>
|
||||
<artifactId>commafeed-client</artifactId>
|
||||
<name>CommaFeed Client</name>
|
||||
|
||||
36
commafeed-client/src/app/client.test.ts
Normal file
36
commafeed-client/src/app/client.test.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { i18n } from "@lingui/core"
|
||||
import type { AxiosError } from "axios"
|
||||
import { afterEach, describe, expect, it, vi } from "vitest"
|
||||
import { errorToStrings } from "./client"
|
||||
|
||||
const axiosError = (status: number, data: unknown) =>
|
||||
({
|
||||
isAxiosError: true,
|
||||
response: { status, data },
|
||||
}) as AxiosError
|
||||
|
||||
describe("errorToStrings", () => {
|
||||
afterEach(() => vi.restoreAllMocks())
|
||||
|
||||
it("translates known application error types", () => {
|
||||
vi.spyOn(i18n, "_").mockReturnValue("Translated authentication error")
|
||||
const error = axiosError(401, {
|
||||
type: "WRONG_USERNAME_OR_PASSWORD",
|
||||
message: "wrong username or password",
|
||||
})
|
||||
|
||||
expect(errorToStrings(error)).toEqual(["Translated authentication error"])
|
||||
})
|
||||
|
||||
it("preserves backend messages for unexpected errors", () => {
|
||||
const error = axiosError(500, { message: "unexpected error" })
|
||||
|
||||
expect(errorToStrings(error)).toEqual(["unexpected error"])
|
||||
})
|
||||
|
||||
it("preserves backend messages for unknown application error types", () => {
|
||||
const error = axiosError(400, { type: "UNKNOWN_ERROR", message: "unknown error" })
|
||||
|
||||
expect(errorToStrings(error)).toEqual(["unknown error"])
|
||||
})
|
||||
})
|
||||
@@ -1,3 +1,5 @@
|
||||
import { i18n, type MessageDescriptor } from "@lingui/core"
|
||||
import { msg } from "@lingui/core/macro"
|
||||
import axios, { type AxiosError } from "axios"
|
||||
import type {
|
||||
AddCategoryRequest,
|
||||
@@ -6,6 +8,8 @@ import type {
|
||||
Category,
|
||||
CategoryModificationRequest,
|
||||
CollapseRequest,
|
||||
CommaFeedApplicationError,
|
||||
CommaFeedExceptionType,
|
||||
Entries,
|
||||
FeedInfo,
|
||||
FeedInfoRequest,
|
||||
@@ -31,6 +35,10 @@ import type {
|
||||
UserModel,
|
||||
} from "./types"
|
||||
|
||||
const applicationErrorMessages = {
|
||||
WRONG_USERNAME_OR_PASSWORD: msg`Wrong username or password`,
|
||||
} satisfies Record<CommaFeedExceptionType, MessageDescriptor>
|
||||
|
||||
const axiosInstance = axios.create({ baseURL: "./rest", withCredentials: true })
|
||||
axiosInstance.interceptors.response.use(
|
||||
response => response,
|
||||
@@ -128,14 +136,25 @@ export const errorToStrings = (err: unknown) => {
|
||||
let strings: string[] = []
|
||||
|
||||
if (axios.isAxiosError(err) && err.response) {
|
||||
if (typeof err.response.data === "string") strings.push(err.response.data)
|
||||
if (isMessageError(err)) strings.push(err.response.data.message)
|
||||
if (isMessageArrayError(err)) strings = [...strings, ...err.response.data.errors]
|
||||
if (isCommaFeedApplicationError(err)) {
|
||||
strings.push(i18n._(applicationErrorMessages[err.response.data.type]))
|
||||
} else {
|
||||
if (typeof err.response.data === "string") strings.push(err.response.data)
|
||||
if (isMessageError(err)) strings.push(err.response.data.message)
|
||||
if (isMessageArrayError(err)) strings = [...strings, ...err.response.data.errors]
|
||||
}
|
||||
}
|
||||
|
||||
return strings
|
||||
}
|
||||
|
||||
function isCommaFeedApplicationError(err: AxiosError): err is AxiosError<CommaFeedApplicationError> {
|
||||
const data = err.response?.data
|
||||
if (!data || typeof data !== "object" || !("type" in data)) return false
|
||||
const type = data.type
|
||||
return typeof type === "string" && Object.hasOwn(applicationErrorMessages, type)
|
||||
}
|
||||
|
||||
function isMessageError(err: AxiosError): err is AxiosError<{ message: string }> {
|
||||
return !!err.response && !!err.response.data && typeof err.response.data === "object" && "message" in err.response.data
|
||||
}
|
||||
|
||||
@@ -166,7 +166,6 @@ export const starEntry = createAppAsyncThunk(
|
||||
(arg: { entry: Entry; starred: boolean }) => {
|
||||
client.entry.star({
|
||||
id: arg.entry.id,
|
||||
feedId: +arg.entry.feedId,
|
||||
starred: arg.starred,
|
||||
})
|
||||
},
|
||||
|
||||
@@ -297,7 +297,6 @@ export interface LocalSettings {
|
||||
|
||||
export interface StarRequest {
|
||||
id: string
|
||||
feedId: number
|
||||
starred: boolean
|
||||
}
|
||||
|
||||
@@ -338,3 +337,10 @@ export interface AuthenticationError {
|
||||
message: string
|
||||
allowRegistrations: boolean
|
||||
}
|
||||
|
||||
export type CommaFeedExceptionType = "WRONG_USERNAME_OR_PASSWORD"
|
||||
|
||||
export interface CommaFeedApplicationError {
|
||||
type: CommaFeedExceptionType
|
||||
message: string
|
||||
}
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "موقع الكتروني"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "مرحباً! يبدو أن هذه هي المرة الأولى التي تقوم فيها بتشغيل CommaFeed. يرجى إنشاء حساب مسؤول للبدء."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "أصفر"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Lloc web"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Benvingut! Sembla que aquesta és la primera vegada que executeu CommaFeed. Creeu un compte d'administrador per començar."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Groc"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Webová stránka"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Vítejte! Zdá se, že je to poprvé, co spouštíte CommaFeed. Chcete-li začít, vytvořte si účet správce."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Žlutá"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Gwefan"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Croeso! Ymddengys mai dyma'r tro cyntaf i chi redeg CommaFeed. Creuwch gyfrif gweinyddwr i ddechrau."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Melyn"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Hjemmeside"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Velkommen! Det ser ud til at være første gang, du kører CommaFeed. Opret venligst en administratorkonto for at komme i gang."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Gul"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Webseite"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Willkommen! Dies scheint das erste Mal zu sein, dass Sie CommaFeed ausführen. Bitte erstellen Sie ein Administrator-Konto, um zu beginnen."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Gelb"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Website"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr "Wrong username or password"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Yellow"
|
||||
|
||||
@@ -1151,6 +1151,10 @@ msgstr "Sitio web"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "¡Bienvenido! Parece que esta es la primera vez que ejecutas CommaFeed. Por favor, crea una cuenta de administrador para empezar."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Amarillo"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "وب سایت"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "خوش آمدید! به نظر میرسد این اولین بار است که CommaFeed را اجرا میکنید. لطفاً برای شروع یک حساب مدیر ایجاد کنید."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "زرد"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Verkkosivusto"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Tervetuloa! Näyttää siltä, että suoritat CommaFeediä ensimmäistä kertaa. Luo ylläpitäjän tili aloittaaksesi."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Keltainen"
|
||||
|
||||
@@ -460,11 +460,11 @@ msgstr "Extensions"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
msgid "Google Reader API"
|
||||
msgstr ""
|
||||
msgstr "API Google Reader"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
msgid "Google Reader API URL"
|
||||
msgstr ""
|
||||
msgstr "URL de l'API Google Reader"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Grape"
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Site web"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Bienvenue ! Il semble que ce soit le premier démarrage de Commafeed. Avant tout, vous devez créer un compte administrateur."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr "Utilisateur ou mot de passe incorrect"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Jaune"
|
||||
|
||||
@@ -1151,6 +1151,10 @@ msgstr "Páxina web"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Benvida! Semella que é a primeira vez que executas CommaFeed. Para comezar, crea unha conta de administración."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Amarelo"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Webhely"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Üdvözöljük! Úgy tűnik, ez az első alkalom, hogy a CommaFeedet futtatja. Kérjük, hozzon létre egy rendszergazdai fiókot a kezdéshez."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Sárga"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Situs Web"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Selamat datang! Ini sepertinya pertama kalinya Anda menjalankan CommaFeed. Silakan buat akun administrator untuk memulai."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Kuning"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Sito web"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Benvenuto! Sembra che sia la prima volta che esegui CommaFeed. Crea un account amministratore per iniziare."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Giallo"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "ウェブサイト"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "ようこそ!CommaFeedを初めて実行するようです。開始するには管理者アカウントを作成してください。"
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "イエロー"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "웹사이트"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "환영합니다! CommaFeed를 처음 실행하는 것 같습니다. 시작하려면 관리자 계정을 만드십시오."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "옐로우"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Laman web"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Selamat datang! Ini nampaknya kali pertama anda menjalankan CommaFeed. Sila cipta akaun pentadbir untuk bermula."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Kuning"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Nettsted"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Velkommen! Det ser ut til å være første gang du kjører CommaFeed. Vennligst opprett en administratorkonto for å komme i gang."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Gul"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Website"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Welkom! Dit lijkt de eerste keer te zijn dat je CommaFeed draait. Maak een beheerdersaccount aan om aan de slag te gaan."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Geel"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Nettstad"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Velkomen! Det ser ut til å vera fyrste gongen du køyrer CommaFeed. Ver venleg og opprett ein administratorkonto for å koma i gang."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Gul"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Strona internetowa"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Witaj! Wygląda na to, że uruchamiasz CommaFeed po raz pierwszy. Aby rozpocząć, utwórz konto administratora."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Żółty"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Site"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Bem-vindo! Esta parece ser a primeira vez que você está executando o CommaFeed. Crie uma conta de administrador para começar."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Amarelo"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Веб-сайт"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Добро пожаловать! Похоже, вы запускаете CommaFeed в первый раз. Пожалуйста, создайте учетную запись администратора, чтобы начать работу."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Желтый"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Webová stránka"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Vitajte! Zdá sa, že CommaFeed spúšťate prvýkrát. Ak chcete začať, vytvorte si účet správcu."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Žltá"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Webbplats"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Välkommen! Det verkar vara första gången du kör CommaFeed. Skapa ett administratörskonto för att komma igång."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Gul"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "Web sitesi"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Hoş geldiniz! Görünüşe göre CommaFeed'i ilk kez çalıştırıyorsunuz. Başlamak için lütfen bir yönetici hesabı oluşturun."
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Sarı"
|
||||
|
||||
@@ -1150,6 +1150,10 @@ msgstr "网站"
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "欢迎!当前页仅当您第一次使用CommaFeed时出现,请创建一个管理员帐号以开始使用。"
|
||||
|
||||
#: src/app/client.ts
|
||||
msgid "Wrong username or password"
|
||||
msgstr "用户名或密码错误"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "黄"
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
<parent>
|
||||
<groupId>com.commafeed</groupId>
|
||||
<artifactId>commafeed</artifactId>
|
||||
<version>7.3.1</version>
|
||||
<version>7.3.2</version>
|
||||
</parent>
|
||||
<artifactId>commafeed-server</artifactId>
|
||||
<name>CommaFeed Server</name>
|
||||
<packaging>quarkus</packaging>
|
||||
|
||||
<properties>
|
||||
<quarkus.version>3.38.2</quarkus.version>
|
||||
<querydsl.version>7.5</querydsl.version>
|
||||
<quarkus.version>3.38.3</quarkus.version>
|
||||
<querydsl.version>7.6</querydsl.version>
|
||||
<rome.version>2.1.0</rome.version>
|
||||
<!-- renovate: depName=com.google.googlejavaformat:google-java-format -->
|
||||
<google-java-format.version>1.36.1</google-java-format.version>
|
||||
@@ -35,7 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>4.35.1</version>
|
||||
<version>4.36.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
@@ -245,7 +245,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>13.11.0</version>
|
||||
<version>14.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -302,7 +302,7 @@
|
||||
<dependency>
|
||||
<groupId>com.commafeed</groupId>
|
||||
<artifactId>commafeed-client</artifactId>
|
||||
<version>7.3.1</version>
|
||||
<version>7.3.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- compile-time processors -->
|
||||
@@ -399,7 +399,7 @@
|
||||
<dependency>
|
||||
<groupId>dev.cel</groupId>
|
||||
<artifactId>cel</artifactId>
|
||||
<version>0.13.1</version>
|
||||
<version>0.14.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.passay</groupId>
|
||||
@@ -482,7 +482,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mock-server</groupId>
|
||||
<artifactId>mockserver-junit-jupiter</artifactId>
|
||||
<version>7.5.0</version>
|
||||
<version>7.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ibm-semeru-runtimes:open-jdk-25.0.4.0-jre@sha256:02888a2306c2cb8af22a05b2c41be90fdc9df5f4611861ddf6ea90c874de65e6
|
||||
FROM ibm-semeru-runtimes:open-jdk-25.0.4.0-jre@sha256:524f0d04723aff42ed4142ab2621fa55f22cb691763cd75b59eee86749e2e872
|
||||
EXPOSE 8082
|
||||
|
||||
RUN mkdir -p /commafeed/data
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.commafeed;
|
||||
|
||||
import com.commafeed.frontend.exception.CommaFeedApplicationException;
|
||||
import com.commafeed.frontend.exception.CommaFeedExceptionType;
|
||||
import com.commafeed.security.CookieService;
|
||||
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
@@ -26,6 +28,18 @@ public class ExceptionMappers {
|
||||
private final CookieService cookieService;
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
@ServerExceptionMapper(CommaFeedApplicationException.class)
|
||||
public RestResponse<CommaFeedApplicationError> applicationError(
|
||||
CommaFeedApplicationException e) {
|
||||
ResponseBuilder<CommaFeedApplicationError> response =
|
||||
ResponseBuilder.create(
|
||||
e.type().status(), new CommaFeedApplicationError(e.type(), e.getMessage()));
|
||||
if (e.type().status() == Status.UNAUTHORIZED) {
|
||||
response.cookie(cookieService.buildLogoutCookie());
|
||||
}
|
||||
return response.build();
|
||||
}
|
||||
|
||||
@ServerExceptionMapper(UnauthorizedException.class)
|
||||
public RestResponse<UnauthorizedResponse> unauthorized(UnauthorizedException e) {
|
||||
return RestResponse.status(
|
||||
@@ -55,4 +69,7 @@ public class ExceptionMappers {
|
||||
|
||||
@RegisterForReflection
|
||||
public record ValidationFailed(String message) {}
|
||||
|
||||
@RegisterForReflection
|
||||
public record CommaFeedApplicationError(CommaFeedExceptionType type, String message) {}
|
||||
}
|
||||
|
||||
@@ -98,15 +98,14 @@ public class FeedEntryService {
|
||||
}
|
||||
}
|
||||
|
||||
public void starEntry(User user, Long entryId, Long subscriptionId, boolean starred) {
|
||||
|
||||
FeedSubscription sub = feedSubscriptionDAO.findById(user, subscriptionId);
|
||||
if (sub == null) {
|
||||
public void starEntry(User user, Long entryId, boolean starred) {
|
||||
FeedEntry entry = feedEntryDAO.findById(entryId);
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FeedEntry entry = feedEntryDAO.findById(entryId);
|
||||
if (entry == null) {
|
||||
FeedSubscription sub = feedSubscriptionDAO.findByFeed(user, entry.getFeed());
|
||||
if (sub == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package com.commafeed.backend.service;
|
||||
|
||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||
import com.commafeed.backend.dao.FeedEntryTagDAO;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.FeedEntryTag;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.commafeed.backend.model.User;
|
||||
|
||||
import jakarta.inject.Singleton;
|
||||
@@ -20,6 +22,7 @@ public class FeedEntryTagService {
|
||||
|
||||
private final FeedEntryDAO feedEntryDAO;
|
||||
private final FeedEntryTagDAO feedEntryTagDAO;
|
||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||
|
||||
public void updateTags(User user, Long entryId, List<String> tagNames) {
|
||||
FeedEntry entry = feedEntryDAO.findById(entryId);
|
||||
@@ -27,6 +30,11 @@ public class FeedEntryTagService {
|
||||
return;
|
||||
}
|
||||
|
||||
FeedSubscription sub = feedSubscriptionDAO.findByFeed(user, entry.getFeed());
|
||||
if (sub == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<FeedEntryTag> existingTags = feedEntryTagDAO.findByEntry(user, entry);
|
||||
Set<String> existingTagNames =
|
||||
existingTags.stream().map(FeedEntryTag::getName).collect(Collectors.toSet());
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.commafeed.frontend.exception;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CommaFeedApplicationException extends RuntimeException {
|
||||
|
||||
@Serial private static final long serialVersionUID = 1L;
|
||||
|
||||
private final CommaFeedExceptionType type;
|
||||
|
||||
public CommaFeedApplicationException(CommaFeedExceptionType type) {
|
||||
super(Objects.requireNonNull(type).message());
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public CommaFeedExceptionType type() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.commafeed.frontend.exception;
|
||||
|
||||
import org.jboss.resteasy.reactive.RestResponse.Status;
|
||||
|
||||
public enum CommaFeedExceptionType {
|
||||
WRONG_USERNAME_OR_PASSWORD(Status.UNAUTHORIZED, "wrong username or password");
|
||||
|
||||
private final Status status;
|
||||
private final String message;
|
||||
|
||||
CommaFeedExceptionType(Status status, String message) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Status status() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String message() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,6 @@ public class StarRequest implements Serializable {
|
||||
@Size(max = 128)
|
||||
private String id;
|
||||
|
||||
@Schema(description = "feed id", required = true)
|
||||
private Long feedId;
|
||||
|
||||
@Schema(description = "starred or not", required = true)
|
||||
private boolean starred;
|
||||
}
|
||||
|
||||
@@ -89,11 +89,9 @@ public class EntryREST {
|
||||
@Valid @Parameter(description = "Star Request", required = true) StarRequest req) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getId());
|
||||
Preconditions.checkNotNull(req.getFeedId());
|
||||
|
||||
User user = authenticationContext.getCurrentUser();
|
||||
feedEntryService.starEntry(
|
||||
user, Long.valueOf(req.getId()), req.getFeedId(), req.isStarred());
|
||||
feedEntryService.starEntry(user, Long.valueOf(req.getId()), req.isStarred());
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@@ -388,9 +388,7 @@ public class FeverREST {
|
||||
if ("read".equals(action) || "unread".equals(action)) {
|
||||
feedEntryService.markEntry(user, id, "read".equals(action));
|
||||
} else if ("saved".equals(action) || "unsaved".equals(action)) {
|
||||
FeedEntry entry = feedEntryDAO.findById(id);
|
||||
FeedSubscription sub = feedSubscriptionDAO.findByFeed(user, entry.getFeed());
|
||||
feedEntryService.starEntry(user, id, sub.getId(), "saved".equals(action));
|
||||
feedEntryService.starEntry(user, id, "saved".equals(action));
|
||||
}
|
||||
} else if ("feed".equals(source)) {
|
||||
FeedSubscription subscription = feedSubscriptionDAO.findById(user, id);
|
||||
|
||||
@@ -402,16 +402,11 @@ public class GoogleReaderREST {
|
||||
if (markUnread) {
|
||||
feedEntryService.markEntry(user, entryId, false);
|
||||
}
|
||||
if (star || unstar) {
|
||||
FeedSubscription sub = feedSubscriptionDAO.findByFeed(user, entry.getFeed());
|
||||
if (sub != null) {
|
||||
if (star) {
|
||||
feedEntryService.starEntry(user, entryId, sub.getId(), true);
|
||||
}
|
||||
if (unstar) {
|
||||
feedEntryService.starEntry(user, entryId, sub.getId(), false);
|
||||
}
|
||||
}
|
||||
if (star) {
|
||||
feedEntryService.starEntry(user, entryId, true);
|
||||
}
|
||||
if (unstar) {
|
||||
feedEntryService.starEntry(user, entryId, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@ import com.commafeed.backend.dao.UnitOfWork;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.commafeed.backend.service.UserService;
|
||||
import com.commafeed.frontend.exception.CommaFeedApplicationException;
|
||||
import com.commafeed.frontend.exception.CommaFeedExceptionType;
|
||||
|
||||
import io.quarkus.security.AuthenticationFailedException;
|
||||
import io.quarkus.security.identity.AuthenticationRequestContext;
|
||||
import io.quarkus.security.identity.IdentityProvider;
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
@@ -48,7 +49,8 @@ public class DatabaseUsernamePasswordIdentityProvider
|
||||
new String(
|
||||
request.getPassword().getPassword())));
|
||||
if (user.isEmpty()) {
|
||||
throw new AuthenticationFailedException("wrong username or password");
|
||||
throw new CommaFeedApplicationException(
|
||||
CommaFeedExceptionType.WRONG_USERNAME_OR_PASSWORD);
|
||||
}
|
||||
|
||||
Set<Role> roles = unitOfWork.call(() -> userService.getRoles(user.get()));
|
||||
|
||||
@@ -36,7 +36,7 @@ class AuthentificationIT {
|
||||
page.navigate(getLoginPageUrl());
|
||||
PlaywrightTestUtils.login(page, TestConstants.ADMIN_USERNAME, "wrong_password");
|
||||
PlaywrightAssertions.assertThat(page.getByRole(AriaRole.ALERT))
|
||||
.containsText("wrong username or password");
|
||||
.containsText("Wrong username or password");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.commafeed.integration;
|
||||
|
||||
import com.commafeed.ExceptionMappers.CommaFeedApplicationError;
|
||||
import com.commafeed.ExceptionMappers.UnauthorizedResponse;
|
||||
import com.commafeed.TestConstants;
|
||||
import com.commafeed.frontend.exception.CommaFeedExceptionType;
|
||||
import com.commafeed.frontend.model.Entries;
|
||||
import com.commafeed.frontend.model.UserModel;
|
||||
import com.commafeed.frontend.model.request.MarkRequest;
|
||||
@@ -57,6 +59,27 @@ class SecurityIT extends BaseIT {
|
||||
.statusCode(HttpStatus.SC_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void formLoginWrongPassword() {
|
||||
CommaFeedApplicationError error =
|
||||
RestAssured.given()
|
||||
.auth()
|
||||
.none()
|
||||
.formParams(
|
||||
"j_username",
|
||||
TestConstants.ADMIN_USERNAME,
|
||||
"j_password",
|
||||
"wrong-password")
|
||||
.post("j_security_check")
|
||||
.then()
|
||||
.statusCode(HttpStatus.SC_UNAUTHORIZED)
|
||||
.extract()
|
||||
.as(CommaFeedApplicationError.class);
|
||||
|
||||
Assertions.assertEquals(CommaFeedExceptionType.WRONG_USERNAME_OR_PASSWORD, error.type());
|
||||
Assertions.assertEquals("wrong username or password", error.message());
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicAuthLogin() {
|
||||
RestAssured.given()
|
||||
|
||||
@@ -45,7 +45,6 @@ class DatabaseCleaningIT extends BaseIT {
|
||||
private void starEntry(String entryId, Long subscriptionId) {
|
||||
StarRequest starRequest = new StarRequest();
|
||||
starRequest.setId(entryId);
|
||||
starRequest.setFeedId(subscriptionId);
|
||||
starRequest.setStarred(true);
|
||||
RestAssured.given()
|
||||
.body(starRequest)
|
||||
@@ -58,7 +57,6 @@ class DatabaseCleaningIT extends BaseIT {
|
||||
private void unstarEntry(String entryId, Long subscriptionId) {
|
||||
StarRequest starRequest = new StarRequest();
|
||||
starRequest.setId(entryId);
|
||||
starRequest.setFeedId(subscriptionId);
|
||||
starRequest.setStarred(false);
|
||||
RestAssured.given()
|
||||
.body(starRequest)
|
||||
|
||||
@@ -240,7 +240,6 @@ class CategoryIT extends BaseIT {
|
||||
|
||||
StarRequest starRequest = new StarRequest();
|
||||
starRequest.setId(entry.getId());
|
||||
starRequest.setFeedId(subscriptionId);
|
||||
starRequest.setStarred(true);
|
||||
RestAssured.given()
|
||||
.body(starRequest)
|
||||
|
||||
@@ -121,7 +121,6 @@ class FeverIT extends BaseIT {
|
||||
|
||||
StarRequest starRequest = new StarRequest();
|
||||
starRequest.setId(entry.getId());
|
||||
starRequest.setFeedId(subscriptionId);
|
||||
starRequest.setStarred(true);
|
||||
RestAssured.given().body(starRequest).contentType(ContentType.JSON).post("rest/entry/star");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user