feat(permissions): add LIMIT_ONE_SEASON permission#2752
feat(permissions): add LIMIT_ONE_SEASON permission#2752dangerouslaser wants to merge 7 commits intoseerr-team:developfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Permission.LIMIT_ONE_SEASON and enforces a single-season request rule: backend exports Changes
Sequence DiagramsequenceDiagram
participant User as User (Limited)
participant Modal as TV Request Modal
participant API as POST /api/v1/request
participant Server as MediaRequest Handler
participant Resp as HTTP Response
User->>Modal: select seasons (attempt >1)
Modal->>Modal: evaluate isOneSeasonLimited (permission + not admin/manager)
alt client restricts selection
Modal->>Modal: enforce single selection / show alert
else client sends payload with >1 season
Modal->>API: POST /api/v1/request (seasons payload)
API->>Server: validate request
Server->>Server: MediaRequest.validateSeasonLimit(user, seasons)
alt multiple seasons & limited
Server->>Server: throw SeasonLimitError
Server->>Resp: 403 Forbidden (error.message)
Resp->>Modal: display error
else valid single season
Server->>Resp: 200 OK
Resp->>Modal: success
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/RequestModal/TvRequestModal.tsx (1)
440-465:⚠️ Potential issue | 🟡 MinorFinish threading
isOneSeasonLimitedthrough the remaining quota-only branches.The CTA state now treats limited users like partial-request mode, but the auto-approve alert and
QuotaDisplaybelow still only key offpartialRequestsEnabled. When partial requests are globally off, a limited user can still see over-limit/zero-remaining messaging based on the full unrequested season count even though selecting one season is valid.🔧 Suggested follow-up
) && !( quota?.tv.limit && - !settings.currentSettings.partialRequestsEnabled && + !settings.currentSettings.partialRequestsEnabled && + !isOneSeasonLimited && unrequestedSeasons.length > (quota?.tv.remaining ?? 0) ) && getAllRequestedSeasons().length < getAllSeasons().length && !editRequest && ( @@ <QuotaDisplay mediaType="tv" quota={quota?.tv} remaining={ - !settings.currentSettings.partialRequestsEnabled && + !settings.currentSettings.partialRequestsEnabled && + !isOneSeasonLimited && unrequestedSeasons.length > (quota?.tv.remaining ?? 0) ? 0 : currentlyRemaining } @@ overLimit={ - !settings.currentSettings.partialRequestsEnabled && + !settings.currentSettings.partialRequestsEnabled && + !isOneSeasonLimited && unrequestedSeasons.length > (quota?.tv.remaining ?? 0) ? unrequestedSeasons.length : undefined }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/RequestModal/TvRequestModal.tsx` around lines 440 - 465, The UI still treats quota messaging and the QuotaDisplay/auto-approve alert as if only settings.currentSettings.partialRequestsEnabled matters; thread isOneSeasonLimited into those checks so limited users are treated like partial-requests-enabled. Update all conditional checks that currently read settings.currentSettings.partialRequestsEnabled (or its negation) in the quota-only branches (including the auto-approve alert logic and the QuotaDisplay rendering) to use (settings.currentSettings.partialRequestsEnabled || isOneSeasonLimited) (or its negation) and ensure unrequestedSeasons/quota comparisons use the effective mode; keep references to isOneSeasonLimited, quota, unrequestedSeasons, getAllRequestedSeasons, getAllSeasons, selectedSeasons, QuotaDisplay and the auto-approve alert logic in your changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@server/entity/MediaRequest.ts`:
- Around line 438-448: The LIMIT_ONE_SEASON check is applied to requestUser in
MediaRequest.request(), which diverges from the frontend (TvRequestModal) that
derives the flag from the logged-in user and is not enforced on edits (PUT
/api/v1/request/:id); extract and centralize this logic into a reusable
validator (e.g., MediaRequest.ensureOneSeasonLimit or
MediaRequest.validateSeasonLimit) that accepts the principal performing the
action (logged-in/acting user) and the request payload (finalSeasons), use
Permission.LIMIT_ONE_SEASON and throw SeasonLimitError when violated, then call
this validator from both MediaRequest.request() and the update handler for PUT
/api/v1/request/:id so on-behalf requests use the same principal and the same
403 behavior.
In `@src/components/PermissionEdit/index.tsx`:
- Around line 190-200: The UI toggle for the permission with id
'limit-one-season' (Permission.LIMIT_ONE_SEASON) only appears when the edited
user has Permission.REQUEST or Permission.REQUEST_TV; update its requires entry
so it also includes 4K-only request permissions (Permission.REQUEST_4K and
Permission.REQUEST_4K_TV) in the permissions array (keeping type: 'or') so users
who only have 4K request bits can be configured from the admin UI.
---
Outside diff comments:
In `@src/components/RequestModal/TvRequestModal.tsx`:
- Around line 440-465: The UI still treats quota messaging and the
QuotaDisplay/auto-approve alert as if only
settings.currentSettings.partialRequestsEnabled matters; thread
isOneSeasonLimited into those checks so limited users are treated like
partial-requests-enabled. Update all conditional checks that currently read
settings.currentSettings.partialRequestsEnabled (or its negation) in the
quota-only branches (including the auto-approve alert logic and the QuotaDisplay
rendering) to use (settings.currentSettings.partialRequestsEnabled ||
isOneSeasonLimited) (or its negation) and ensure unrequestedSeasons/quota
comparisons use the effective mode; keep references to isOneSeasonLimited,
quota, unrequestedSeasons, getAllRequestedSeasons, getAllSeasons,
selectedSeasons, QuotaDisplay and the auto-approve alert logic in your changes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9d98ff30-f512-4fd5-af74-81f00ac814b3
📒 Files selected for processing (5)
server/entity/MediaRequest.tsserver/lib/permissions.tsserver/routes/request.tssrc/components/PermissionEdit/index.tsxsrc/components/RequestModal/TvRequestModal.tsx
523d8d2 to
ca988a6
Compare
|
Thanks, small but impactful feature with a high cost-benefit ratio. This would also partially address #1351. It would be great to see this included in an upcoming release fairly soon, as many users are eagerly waiting for this 👍 |
9e4e331 to
f2abeca
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/RequestModal/TvRequestModal.tsx`:
- Around line 555-557: The season selection UI in TvRequestModal uses checkbox
semantics even when isOneSeasonLimited is true, which should be radio semantics;
update the rendering where (!settings.currentSettings.partialRequestsEnabled ||
isOneSeasonLimited) controls visibility so that when isOneSeasonLimited you
render a radiogroup container and each season item uses role="radio" (and
aria-checked) instead of checkbox input/role, and ensure keyboard/ARIA behaviors
match radio semantics; locate the season-row rendering logic in TvRequestModal
(references: settings.currentSettings.partialRequestsEnabled,
isOneSeasonLimited) and switch the markup/role/aria attributes accordingly for
the single-season mode (also apply the same change at the other occurrences
noted around the other blocks).
- Around line 284-288: The isOneSeasonLimited flag currently uses the signed-in
user's permissions via hasPermission(Permission.LIMIT_ONE_SEASON), which is
wrong when a manager/admin is submitting on behalf of requestOverrides.user;
change the logic to derive this flag from the effective/request owner instead:
resolve the selected user id (requestOverrides.user or the modal's selected
user), fetch or compute that user's permissions (e.g., via the same
hasPermission call scoped to that user or by loading their permission set), and
then set isOneSeasonLimited based on whether that target user has
Permission.LIMIT_ONE_SEASON and lacks MANAGE_REQUESTS/ADMIN; update any UI
gating (multi-season select) to use this computed flag to prevent a 403 on
submit.
- Around line 309-311: The one-season branch (isOneSeasonLimited) replaces
selection via setSelectedSeasons([seasonNumber]) but the quota checks and
messaging still assume selections only grow; update the guard that uses
currentlyRemaining and the quota message logic that uses
unrequestedSeasons.length so they respect replacement semantics when
isOneSeasonLimited is true (i.e., compute remaining and over-limit using the
effective post-replacement set instead of the additive logic), and mirror this
same change in the other quota branch referenced around the 457-465 area; use
the existing symbols isOneSeasonLimited, setSelectedSeasons, currentlyRemaining,
unrequestedSeasons, and partialRequestsEnabled to locate and adjust the checks
and messages.
🪄 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
Run ID: 226717d2-4f62-4209-bad6-c836df5dee07
📒 Files selected for processing (5)
server/entity/MediaRequest.tsserver/lib/permissions.tsserver/routes/request.tssrc/components/PermissionEdit/index.tsxsrc/components/RequestModal/TvRequestModal.tsx
✅ Files skipped from review due to trivial changes (2)
- server/lib/permissions.ts
- server/routes/request.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- server/entity/MediaRequest.ts
Add a new user permission that restricts series requests to one season at a time. When enabled, the request modal switches to single-select mode for seasons, hides the select-all toggle, and the backend rejects multi-season requests with a 403. Admins and users with Manage Requests are exempt from the restriction. This is intended to be paired with an external prefetch service (e.g. Prefetcharr) that automatically requests additional seasons based on user watch progress.
- Centralize season limit validation into MediaRequest.validateSeasonLimit() - Derive isOneSeasonLimited from effective request user (requestOverrides) - Fix quota logic to allow season replacement in single-season mode - Use radio semantics (role=radio/radiogroup) for a11y in single-season mode
1568e09 to
483b1f6
Compare
Description
Adds a new
LIMIT_ONE_SEASONpermission that restricts users to requesting only one TV season at a time. This gives admins more granular control over request behavior without disabling partial requests entirely.Changes in this PR:
Backend: Added
Permission.LIMIT_ONE_SEASON(536870912) andSeasonLimitError. Centralized validation intoMediaRequest.validateSeasonLimit(), enforced in bothPOST /api/v1/requestandPUT /api/v1/request/:id.Frontend (PermissionEdit): Added the permission toggle with
requirescovering standard and 4K request permissions.Frontend (TvRequestModal): Season selection switches to single-select (replace) mode. The limit is derived from the effective request user (supports on-behalf requests). Quota logic accounts for replacement semantics. Uses
role="radio"/role="radiogroup"for a11y when in single-season mode.Partially addresses [Feature] Limit number of seasons per request #1351
How Has This Been Tested?
Screenshots / Logs (if applicable)
N/A
AI Disclosure
AI was used to assist with code review feedback implementation.
Checklist: