Skip to content

fix(request): correct delete permission check and await movie save#2742

Open
dougrathbone wants to merge 1 commit intoseerr-team:developfrom
dougrathbone:dougrathbone/fix/request-delete-permission
Open

fix(request): correct delete permission check and await movie save#2742
dougrathbone wants to merge 1 commit intoseerr-team:developfrom
dougrathbone:dougrathbone/fix/request-delete-permission

Conversation

@dougrathbone
Copy link
Copy Markdown

@dougrathbone dougrathbone commented Mar 22, 2026

Description

Two bugs in server/routes/request.ts:

1. Anyone can delete any pending request

The DELETE /request/:id handler used three top-level && conditions to gate deletion:

// Before
if (
  !req.user?.hasPermission(Permission.MANAGE_REQUESTS) &&
  request.requestedBy.id !== req.user?.id &&
  request.status !== 1
) {

Because all three must be true to deny, the third condition short-circuits the check whenever a request is PENDING -- meaning any authenticated user can delete any pending request they did not create. The intended behaviour is that non-admins may only retract their own requests while they are still pending.

// After
if (
  !req.user?.hasPermission(Permission.MANAGE_REQUESTS) &&
  (request.requestedBy.id !== req.user?.id ||
    request.status !== MediaRequestStatus.PENDING)
) {

Also replaces the magic number 1 with MediaRequestStatus.PENDING.

2. Movie request update is not awaited

The movie branch of PUT /request/:id called requestRepository.save() without await, returning the 200 response before the write completed. The TV branch in the same handler correctly awaits the save.

// Before
requestRepository.save(request);

// After
await requestRepository.save(request);

How Has This Been Tested?

pnpm test -- 30/30 tests pass including a new server/routes/request.test.ts suite covering:

  • Owner can delete their own pending request
  • Admin can delete any request
  • Non-owner non-admin is denied when deleting a pending request (catches bug 1)
  • Owner is denied when deleting an approved request (catches bug 1)
  • Movie update changes are persisted to the database before the response is returned (catches bug 2)

Screenshots / Logs (if applicable)

▶ DELETE /request/:requestId
  ✔ allows the owner to delete their own pending request (287ms)
  ✔ allows an admin to delete any pending request (248ms)
  ✔ prevents a non-owner non-admin from deleting a pending request (240ms)
  ✔ prevents the owner from deleting an approved request (242ms)
  ✔ returns 404 for a non-existent request (236ms)
✔ DELETE /request/:requestId (1427ms)
▶ PUT /request/:requestId (movie)
  ✔ persists server and root folder changes to the database (239ms)
✔ PUT /request/:requestId (movie) (240ms)
ℹ tests 6
ℹ pass  6
ℹ fail  0

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

AI was used for code completion. All testing and interaction with the codebase was done manually.

Summary by CodeRabbit

  • Bug Fixes
    • Corrected request deletion authorization to properly restrict non-pending requests.
    • Fixed persistence of server-side settings when updating movie requests.

Two bugs in the request route handler:

1. DELETE /request/:id used three top-level && conditions to gate
deletion, meaning any authenticated user could delete any PENDING
request because the third condition (status !== PENDING) short-circuits
the denial. The intent is: non-admins may only retract their own
requests while they are still pending. Fixed by grouping the ownership
and status checks with || inside a single outer && against the admin
check.

   Before: !admin && !owner && !pending  (allows deletion if pending)
   After:  !admin && (!owner || !pending) (owner + pending required)

   Also replaces the magic number 1 with MediaRequestStatus.PENDING.

2. The movie branch of PUT /request/:id called requestRepository.save()
without await, returning the 200 response before the write completed.
The TV branch in the same handler correctly awaits the save. Fixed by
adding the missing await.

Tests cover: owner can delete own pending request, admin can delete any
request, non-owner non-admin is denied on a pending request, owner is
denied on an approved request, and movie update changes are persisted
before the response is returned.
@dougrathbone dougrathbone requested a review from a team as a code owner March 22, 2026 01:45
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 06044e7e-110f-439f-9d34-ba2d5796eae3

📥 Commits

Reviewing files that changed from the base of the PR and between dbe1fca and 5315b28.

📒 Files selected for processing (2)
  • server/routes/request.test.ts
  • server/routes/request.ts

📝 Walkthrough

Walkthrough

A new comprehensive test file validates request route handlers (DELETE and PUT endpoints), while the production code fixes async/await handling in the movie request update flow and refines authorization logic in the delete handler to use explicit status enumerations.

Changes

Cohort / File(s) Summary
Request Route Tests
server/routes/request.test.ts
New test suite covering DELETE and PUT /request/:requestId endpoints, including authorization checks, request ownership validation, status-based permission rules, and server-side field persistence with database assertions.
Request Route Handler
server/routes/request.ts
Fixed async/await consistency in movie request PUT handler by awaiting requestRepository.save(), and refactored DELETE authorization logic to explicitly compare against MediaRequestStatus.PENDING instead of magic status code.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Routes now tested with care so bright,
Awaits aligned, permissions set right,
DELETE and PUT dance in harmony,
A bugless hop through quality! ✨

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes both main changes: the DELETE permission check correction and the addition of await for the movie save operation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant