Upgrade back-end code from Django 4.2 to 5.2 LTS#8052
Conversation
|
Warning Review limit reached
Next review available in: 49 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughChangesDjango 5.2 dependencies are introduced alongside path-based URL routing, field compatibility updates, a migration for many-to-many relationships, and pytest configuration. Frontend logout entry points now use a routed logout component that posts to the accounts endpoint before redirecting to login. Django platform upgrade
Frontend logout flow
Sequence Diagram(s)sequenceDiagram
participant User
participant Router
participant Logout
participant AccountsLogout
participant LoginPage
User->>Router: Open command/logout
Router->>Logout: Load Logout component
Logout->>AccountsLogout: POST /accounts/logout/
AccountsLogout-->>Logout: Logout response
Logout->>LoginPage: Redirect with next=/specify/
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Warning One or more dependencies are approaching or past End-of-Life. |
Triggered by ffecf67 on branch refs/heads/issue-8046
We decided that since we would be mocking all the calls, testing is a fruitless endevor for this component
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
specifyweb/frontend/js_src/lib/components/ChooseCollection/index.tsx (1)
175-177: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAvoid posting logout twice in this flow.
The
pingcall performs a POST, then the redirect mountsLogout, which POSTs to/accounts/logout/again. Let one layer own the logout request; verify whether the pre-redirect POST is still required.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@specifyweb/frontend/js_src/lib/components/ChooseCollection/index.tsx` around lines 175 - 177, Update the logout flow around the ping call and redirect to ensure /accounts/logout/ is POSTed only once. Determine whether Logout owns the required logout request, then remove the redundant pre-redirect ping POST if so, while preserving the redirect to formatUrl('/specify/command/logout/', { next: nextUrl }).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@requirements-testing.txt`:
- Around line 2-3: Update the mypy dependency pin in requirements-testing.txt to
a version supported by django-stubs==5.2.9, such as mypy==1.13.0; retain the
django-stubs pin and do not keep the incompatible mypy==1.5.1 combination.
In `@requirements.txt`:
- Line 14: Update the PyJWT dependency version in requirements.txt from 2.12.1
to 2.13.0 or later, ensuring the pinned version includes the PyJWKClient
scheme-validation fix.
In `@specifyweb/backend/context/testurls.py`:
- Line 12: Update the URL pattern for views.viewsets to use a string-compatible
path converter instead of <int:level>, so the level argument remains a string
when passed to testsviews.viewsets().
In `@specifyweb/frontend/js_src/lib/components/Logout/index.tsx`:
- Line 17: Update the logout redirect callback in the Logout component to read
and validate the route’s next value, preserving it when valid and falling back
to “/specify/” otherwise. Use that resolved value in the formatUrl call instead
of always passing the fixed “/specify/” target.
- Around line 16-22: Update the logout failure handler in the promise chain
around softError so a failed POST transitions away from the indefinitely
displayed LoadingScreen. Render an error/retry state or navigate to a terminal
fallback on rejection, while preserving the existing successful redirect
behavior.
- Around line 11-20: Move the logout request and its loading/redirect error
handling from the component render path into a mount-only effect, using the
component’s existing effect and loading utilities. Ensure the POST to
/accounts/logout/ starts once after mount, while preserving the current success
redirect and softError behavior.
---
Nitpick comments:
In `@specifyweb/frontend/js_src/lib/components/ChooseCollection/index.tsx`:
- Around line 175-177: Update the logout flow around the ping call and redirect
to ensure /accounts/logout/ is POSTed only once. Determine whether Logout owns
the required logout request, then remove the redundant pre-redirect ping POST if
so, while preserving the redirect to formatUrl('/specify/command/logout/', {
next: nextUrl }).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3501db84-1148-48c2-861a-22071020f1f5
📒 Files selected for processing (20)
pytest.inirequirements-testing.txtrequirements.txtspecifyweb/backend/batch_identify/urls.pyspecifyweb/backend/context/testurls.pyspecifyweb/backend/context/urls.pyspecifyweb/backend/inheritance/urls.pyspecifyweb/backend/setup_tool/urls.pyspecifyweb/backend/trees/urls.pyspecifyweb/frontend/js_src/lib/components/Atoms/Icons.tsxspecifyweb/frontend/js_src/lib/components/ChooseCollection/index.tsxspecifyweb/frontend/js_src/lib/components/Core/Main.tsxspecifyweb/frontend/js_src/lib/components/Header/userToolDefinitions.tsspecifyweb/frontend/js_src/lib/components/Logout/index.tsxspecifyweb/frontend/js_src/lib/components/Router/Routes.tsxspecifyweb/settings/__init__.pyspecifyweb/specify/migrations/0045_alter_many_to_many_through_fields.pyspecifyweb/specify/urls.pyspecifyweb/specify/utils/case_insensitive_bool.pyspecifyweb/urls.py
💤 Files with no reviewable changes (1)
- specifyweb/settings/init.py
| django-stubs==5.2.9 | ||
| mypy==1.5.1 |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== requirements-testing.txt =="
cat -n requirements-testing.txt
echo
echo "== nearby django-stubs/mypy pins =="
rg -n 'django-stubs|mypy' requirements*.txt pyproject.toml setup.cfg tox.ini 2>/dev/null || true
echo
echo "== lock/config references =="
fd -a '.*requirements.*|.*constraints.*|pyproject.toml|setup.cfg|tox.ini' . | sed 's#^\./##' | head -100Repository: specify/specify7
Length of output: 792
🌐 Web query:
django-stubs 5.2.9 mypy compatibility supported versions
💡 Result:
For django-stubs version 5.2.9, the supported environment configurations are as follows [1][2]: Mypy versions: 1.13 through 1.19 [1][2] Django versions: 5.2 (full support), with partial support for Django 5.1 and 5.0 [1][2] Python versions: 3.10 through 3.13 [1][2] Version 5.2.9 was the final release of the 5.2.x series for django-stubs, designed to target Django 5.2 [3][4]. Subsequent releases transitioned to supporting Django 6.0 [3][4]. When using "partial support" for older Django versions, the stubs may contain newer type definitions (e.g., if a return type changed between versions) or include symbols not present in your specific, older Django installation [5]. It is generally recommended to use the version of django-stubs that corresponds to your installed Django version to ensure full compatibility [5].
Citations:
- 1: https://pypi.org/project/django-stubs/5.2.9/
- 2: https://github.com/typeddjango/django-stubs/blob/master/README.md
- 3: https://github.com/typeddjango/django-stubs/releases/tag/5.2.9
- 4: https://github.com/typeddjango/django-stubs/releases
- 5: What version of `django-stubs` should I use with Django 4.2 LTS? typeddjango/django-stubs#2101
Align mypy with django-stubs 5.2.9.
django-stubs 5.2.9 documents supported mypy versions as 1.13–1.19, but this file pins mypy==1.5.1. Use a supported mypy pin here, such as mypy==1.13.0, or keep the older django-stubs version if mypy 1.5.1 is required.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@requirements-testing.txt` around lines 2 - 3, Update the mypy dependency pin
in requirements-testing.txt to a version supported by django-stubs==5.2.9, such
as mypy==1.13.0; retain the django-stubs pin and do not keep the incompatible
mypy==1.5.1 combination.
| sqlalchemy2-stubs | ||
| requests==2.32.4 | ||
| pycryptodome==3.21.0 | ||
| PyJWT==2.12.1 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== requirements.txt =="
sed -n '1,60p' requirements.txt 2>/dev/null || true
echo
echo "== PyJWT references in repo =="
rg -n --fixed-strings "PyJWKClient|PyJWT|requests_jwt|jwt\." -S . --glob '!*.lock' --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | head -200 || true
echo
echo "== lockfiles mentioning PyJWT =="
for f in $(git ls-files | rg '(^|/)(requirements.*\.txt|poetry\.lock|Pipfile\.lock|uv\.lock|package-lock\.json|yarn\.lock|pnpm-lock\.yaml)$'); do
echo "--- $f"
rg -n --fixed-strings "PyJWT|pyjwt|jwk|jwk-set" "$f" || true
doneRepository: specify/specify7
Length of output: 673
🌐 Web query:
OSV GHSA-993g-76c3-p5m4 PyJWT PyJWKClient scheme-validation fixed version
💡 Result:
The vulnerability GHSA-993g-76c3-p5m4 (also tracked as CVE-2026-48522) involves a missing scheme allowlist in PyJWT's PyJWKClient, which allowed the library to fetch URIs using schemes beyond the expected http and https (such as file://, ftp://, and data:) [1][2][3]. This flaw enabled potential Server-Side Request Forgery (SSRF) and, in specific configurations, token forgery [2][4]. The vulnerability is fixed in PyJWT version 2.13.0 [3][5]. In this release, PyJWKClient was updated to strictly reject any URI scheme that is not explicitly http or https [5][6]. Additionally, a new allowed_schemes initialization parameter was added to allow for future configuration of allowed schemes [1][2].
Citations:
- 1: https://osv.dev/vulnerability/GHSA-993g-76c3-p5m4
- 2: GHSA-993g-76c3-p5m4
- 3: https://osv.dev/vulnerability/CVE-2026-48522
- 4: GHSA-993g-76c3-p5m4
- 5: https://github.com/jpadilla/pyjwt/releases/tag/2.13.0
- 6: https://pyjwt.readthedocs.io/en/stable/changelog.html
🌐 Web query:
GitHub PyJWKClient GHSA-993g-76c3-p5m4 fixed commit PyJWT 2.12.1 PyJWT 2.13.0 allow_schemes
💡 Result:
The vulnerability GHSA-993g-76c3-p5m4, also identified as CVE-2026-48522, addressed a security flaw in PyJWT's PyJWKClient where it lacked a scheme allowlist [1][2]. This allowed the client to fetch JWKS data using unintended schemes such as file://, ftp://, and data:, potentially leading to SSRF or token forgery if an application accepted attacker-influenced URIs [1][3]. This issue was fixed in PyJWT version 2.13.0 [4][5]. The fix introduced an allowed_schemes parameter to the PyJWKClient constructor [6][7]. Key details of the fix: - PyJWKClient now defaults to allowed_schemes=("http", "https") [7]. - The library performs pre-validation of the URI scheme before invoking urllib.request.urlopen [1][7]. - If a scheme is not in the allowed list, PyJWKClient raises a PyJWKClientError [1][7]. - This change allows developers to maintain backward compatibility for standard HTTP/HTTPS use cases while providing the flexibility to enable other schemes explicitly if required [6][7]. It is important to note that this update specifically addresses the URI scheme restriction [1][5]. It is distinct from another security fix, GHSA-jq35-7prp-9v3f, which was also released in PyJWT 2.13.0 and addressed an algorithm allow-list bypass when using PyJWK keys [8][9].
Citations:
- 1: GHSA-993g-76c3-p5m4
- 2: GHSA-993g-76c3-p5m4
- 3: https://test.osv.dev/vulnerability/CVE-2026-48522
- 4: https://github.com/jpadilla/pyjwt/releases/tag/2.13.0
- 5: https://pyjwt.readthedocs.io/en/stable/changelog.html
- 6: Add allowed_schemes to PyJWKClient jpadilla/pyjwt#1176
- 7: GHSA-993g-76c3-p5m4
- 8: GHSA-jq35-7prp-9v3f
- 9: https://github.com/jpadilla/pyjwt/blob/2.13.0/CHANGELOG.rst
Upgrade PyJWT to avoid known PyJWKClient vulnerabilities.
PyJWT==2.12.1 is affected by PyJWKClient scheme-validation issues; update to 2.13.0 or later so the default JWKS fetches are limited to allowed HTTP(S) schemes.
🧰 Tools
🪛 OSV Scanner (2.4.0)
[HIGH] 14-14: pyjwt 2.12.1: undefined
(PYSEC-2026-175)
[HIGH] 14-14: pyjwt 2.12.1: undefined
(PYSEC-2026-177)
[HIGH] 14-14: pyjwt 2.12.1: undefined
(PYSEC-2026-178)
[HIGH] 14-14: pyjwt 2.12.1: undefined
(PYSEC-2026-179)
[HIGH] 14-14: pyjwt 2.12.1: PyJWKClient: missing scheme allowlist enables CVE-2024-21643-class SSRF + token forgery via file://, ftp://, data: schemes
[HIGH] 14-14: pyjwt 2.12.1: PyJWKClient unbounded JWKS endpoint requests via attacker-controlled kid values (DoS)
[HIGH] 14-14: pyjwt 2.12.1: PyJWT: Algorithm allow-list bypass when decoding with PyJWK / PyJWKClient keys
[HIGH] 14-14: pyjwt 2.12.1: PyJWT: Unauthenticated DoS via unbounded Base64URL decoding of unused payload segment in b64=false detached JWS
[HIGH] 14-14: pyjwt 2.12.1: PyJWT: Public-key JWK accepted as HMAC secret enables forged HS256 tokens when mixed families are allowed
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@requirements.txt` at line 14, Update the PyJWT dependency version in
requirements.txt from 2.12.1 to 2.13.0 or later, ensuring the pinned version
includes the PyJWKClient scheme-validation fix.
Source: Linters/SAST tools
| re_path(r'^app.resource$', views.app_resource), | ||
| re_path(r'^available_related_searches.json$', views.available_related_searches), | ||
| path('domain.json', views.domain), | ||
| path('viewsets/<int:level>.xml', views.viewsets), |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Files matching testurls.py:\n'
fd 'testurls\.py$' . || true
printf '\nGit-tracked context testurls.py:\n'
git ls-files | rg '(^|/)testurls\.py$' | sed -n '1,50p'
printf '\nRelevant snippets in context testurls.py:\n'
while IFS= read -r f; do
echo "--- $f"
nl -ba "$f" | sed -n '1,40p'
done < <(git ls-files | rg 'context/testurls\.py$' || true)
printf '\nSearch for viewsets and level=':
rg -n "def viewsets|viewsets|'viewset_'\+level|viewset_|level\.xml" --glob '*.py' .Repository: specify/specify7
Length of output: 392
🏁 Script executed:
#!/bin/bash
set -u
echo "### testurls.py"
nl -ba specifyweb/backend/context/testurls.py | sed -n '1,80p'
echo
echo "### viewsets usages / level handling"
rg -n "def viewsets|viewsets|'viewset_'|\"viewset_|level\.xml|viewset_" --glob '*.py' .
echo
echo "### Django int converter behavior probe"
python3 - <<'PY'
try:
from django.urls.converters import IntConverter
ic = IntConverter()
converted = ic.to_python('05')
print(type(converted).__name__, repr(converted))
print(type(converted).__name__, type('').__name__, isinstance('', str))
print(converted + '/abc.xml')
except Exception as e:
print(type(e).__name__, str(e))
PYRepository: specify/specify7
Length of output: 3369
🏁 Script executed:
#!/bin/bash
set -u
echo "### specifyweb/backend/context/testurls.py"
awk '{printf "%6d\t%s\n", NR, $0}' specifyweb/backend/context/testurls.py | sed -n '1,80p'
echo
echo "### specifyweb/backend/context/testsviews.py"
awk '{printf "%6d\t%s\n", NR, $0}' specifyweb/backend/context/testsviews.py | sed -n '1,60p'
echo
echo "### viewsets path/url/import references"
rg -n "testurls|testsviews|viewsets/<int:level>|def viewsets\(request, level\)" --glob '*.py' .Repository: specify/specify7
Length of output: 2308
🌐 Web query:
Django URL converters int converter documentation
💡 Result:
In Django, the int URL converter is used within path patterns to match a sequence of digits and convert the captured value into a Python integer [1][2]. Key technical details: - Matching behavior: The int converter matches zero or any positive integer [1][2]. - Type conversion: It automatically converts the captured string value into a Python int before passing it as a keyword argument to the view function [1][3]. - Implementation: Internally, it uses the regular expression [0-9]+ to identify matching segments [4]. - Usage: You use it in a URL pattern by placing it inside angle brackets, such as path('articles/int:year/', views.year_archive) [1][2]. If you need different matching logic (for example, to support negative numbers or specific constraints), you can register a custom path converter using the register_converter function [1][2][3].
Citations:
- 1: https://docs.djangoproject.com/en/5.2/topics/http/urls/
- 2: https://docs.djangoproject.com/en/6.0/topics/http/urls/
- 3: https://docs.djangoproject.com/en/5.2/ref/urls/
- 4: https://docs.djangoproject.com/en/4.2/_modules/django/urls/converters/
Keep level as a string.
Django’s <int:level> converter passes an int, while testsviews.viewsets() concatenates it with strings, raising a TypeError for this URL when called.
Proposed fix
- path('viewsets/<int:level>.xml', views.viewsets),
+ path('viewsets/<str:level>.xml', views.viewsets),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| path('viewsets/<int:level>.xml', views.viewsets), | |
| path('viewsets/<str:level>.xml', views.viewsets), |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@specifyweb/backend/context/testurls.py` at line 12, Update the URL pattern
for views.viewsets to use a string-compatible path converter instead of
<int:level>, so the level argument remains a string when passed to
testsviews.viewsets().
| loading( | ||
| ajax<string>('/accounts/logout/', { | ||
| method: 'POST', | ||
| headers: { }, | ||
| }) | ||
| .then( | ||
| () => globalThis.location.assign(formatUrl("/accounts/login/", {next: "/specify/"})), | ||
| (error) => softError(error) | ||
| ) | ||
| ) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate file =="
fd -a 'index\.tsx$' . | sed 's#^\./##' | grep 'frontend/js_src/lib/components/Logout/index.tsx' || true
echo "== file contents =="
cat -n specifyweb/frontend/js_src/lib/components/Logout/index.tsx
echo "== definitions/usages =="
rg -n "function Loading|const Loading|export .*Loading|function ajax|const ajax|function softError|const softError|loading\\(" specifyweb/frontend/js_src/lib/components specifyweb/frontend/js_src/lib 2>/dev/null | head -200Repository: specify/specify7
Length of output: 22738
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== candidate files for LoadingContext/loading/softError/Route components =="
rg -n "LoadingContext|LoadingScreen|loading\\(|softError|formatUrl\\(" specifyweb/frontend/js_src/lib -S
echo "== structural scan for Loading component definition =="
ast-grep scan --lang tsx --rule 'kind: Component; matcher: {kind: FunctionDeclaration, has: {kind: BlockStatement}}' specifyweb/frontend/js_src/lib/components 2>/dev/null || trueRepository: specify/specify7
Length of output: 50372
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== LoadingContext implementation =="
sed -n '1,230p' specifyweb/frontend/js_src/lib/components/Core/Contexts.tsx
echo "== ajax implementation relevant section =="
sed -n '1,155p' specifyweb/frontend/js_src/lib/utils/ajax/index.ts
echo "== static checker for render-time loading calls =="
python3 - <<'PY'
from pathlib import Path
p = Path('specifyweb/frontend/js_src/lib/components/Logout/index.tsx')
text = p.read_text()
print('contains ajax call:', 'ajax<string>' in text)
print('inside function body:')
start = text.index('export function Logout')
end = text.index('return <LoadingScreen />') + len('return <LoadingScreen />')
body = text[start:end]
print(body)
print('has useEffect:', 'useEffect' in body)
PYRepository: specify/specify7
Length of output: 14011
Move the logout request into an effect.
ajax<...>('/accounts/logout/', ...) creates a new fetch promise during every render, so rerenders can submit logout multiple times; start this one-time POST from a stable effect.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@specifyweb/frontend/js_src/lib/components/Logout/index.tsx` around lines 11 -
20, Move the logout request and its loading/redirect error handling from the
component render path into a mount-only effect, using the component’s existing
effect and loading utilities. Ensure the POST to /accounts/logout/ starts once
after mount, while preserving the current success redirect and softError
behavior.
| .then( | ||
| () => globalThis.location.assign(formatUrl("/accounts/login/", {next: "/specify/"})), | ||
| (error) => softError(error) | ||
| ) | ||
| ) | ||
|
|
||
| return <LoadingScreen /> |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Handle failures without leaving an endless loading screen.
softError only logs in production, while LoadingScreen resolves its pending promise only on unmount. A failed POST therefore leaves the user stuck on the loading screen. Render an error/retry state or navigate to a terminal fallback.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@specifyweb/frontend/js_src/lib/components/Logout/index.tsx` around lines 16 -
22, Update the logout failure handler in the promise chain around softError so a
failed POST transitions away from the indefinitely displayed LoadingScreen.
Render an error/retry state or navigate to a terminal fallback on rejection,
while preserving the existing successful redirect behavior.
| headers: { }, | ||
| }) | ||
| .then( | ||
| () => globalThis.location.assign(formatUrl("/accounts/login/", {next: "/specify/"})), |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Preserve the collection return target.
ChooseCollection passes nextUrl to /specify/command/logout/, but this component always redirects with next: '/specify/'. Read and validate the route’s next value, using /specify/ only as the fallback.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@specifyweb/frontend/js_src/lib/components/Logout/index.tsx` at line 17,
Update the logout redirect callback in the Logout component to read and validate
the route’s next value, preserving it when valid and falling back to “/specify/”
otherwise. Use that resolved value in the formatUrl call instead of always
passing the fixed “/specify/” target.
Fixes #8046
Upgrade Django from 4.2 to LTS version 5.2.
https://docs.djangoproject.com/en/6.0/releases/5.2/
Changes:
USE_L10N(A localization setting, that is now defaulted to true)GETrequest to logout to aPOSTrequest to be in HTTP (and django) speclogOutuser tool (inHeader/userToolDefinitions) to point to a new front-end endpoint:/specify/command/logoutto match the cache clearing endpointRouter/Routes.tsx) renders theLogoutcomponentLogoutcomponent makes the POST request to the backend and returns a loading screenChecklist
self-explanatory (or properly documented)
Testing instructions
Summary by CodeRabbit
New Features
Bug Fixes
Refactor