Skip to content

feat(quota): added support for unlimited quota days#2797

Open
Roboroads wants to merge 2 commits intoseerr-team:developfrom
Roboroads:feature-no-time-limit-on-requests
Open

feat(quota): added support for unlimited quota days#2797
Roboroads wants to merge 2 commits intoseerr-team:developfrom
Roboroads:feature-no-time-limit-on-requests

Conversation

@Roboroads
Copy link
Copy Markdown

@Roboroads Roboroads commented Apr 1, 2026

Description

I'm running Seerr on a "low storage" NAS. My friends and family have a limit on how much they can have stored on my server, when they are done watching they ask me to remove their downloads to free up remaining requests (and diskspace). This adds the option that there is no "per x days", but just "in total".

AI Usage: AI was used to figure out where to change the quota code, code is entirely written by myself.

How Has This Been Tested?

I've checked which parts of the application touches the quota API, they still work as the output isn't different. I changed a bit of the text in the quota display - it was not broken, just a little weird.

AI Usage: I have asked AI to review the code.

Screenshots / Logs (if applicable)

image image

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)

Summary by CodeRabbit

  • New Features

    • Added an "Unlimited" (0 days) option to the quota-days selector.
  • Improvements

    • Quota display messages now render "every day" for unlimited quotas and correctly pluralize other day values using plural-aware localization.
    • Internal quota counting logic refined to apply date-window filters only when a quota duration is set, improving accuracy of used-quota calculations.

@Roboroads Roboroads requested a review from a team as a code owner April 1, 2026 21:49
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 1, 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: fb0cc46b-6753-4c12-b828-0bf8e9703d37

📥 Commits

Reviewing files that changed from the base of the PR and between 235d428 and 8148d1a.

📒 Files selected for processing (4)
  • server/entity/User.ts
  • src/components/QuotaSelector/index.tsx
  • src/components/RequestModal/QuotaDisplay/index.tsx
  • src/i18n/locale/en.json
✅ Files skipped from review due to trivial changes (1)
  • server/entity/User.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/RequestModal/QuotaDisplay/index.tsx
  • src/i18n/locale/en.json

📝 Walkthrough

Walkthrough

Backend quota counting omits date filters when quota days are zero (unlimited). The UI adds an "Unlimited" (value="0") option to the quota-days selector. Quota display messages use ICU pluralization to render "every day" for 0 (and singular) and show day counts otherwise.

Changes

Cohort / File(s) Summary
Backend Quota Counting
server/entity/User.ts
Refactored movie and TV quota logic: build a reusable tvQuotaUsedQuery with shared joins/filters and conditionally append request.createdAt > :date only when *_quotaDays is truthy; movie quota similarly omits the createdAt constraint when days is falsy. Normalized restricted booleans via !!(...).
Frontend Quota UI
src/components/QuotaSelector/index.tsx
Added an "Unlimited" <option> with value="0" to the quota-days <select>, allowing zero to represent unlimited days.
Quota Display Messages
src/components/RequestModal/QuotaDisplay/index.tsx
Reworked ICU message usage for {days} to use a plural selector with an =0 case that renders "every day"; otherwise renders the emphasized multi-day phrasing.
Localization
src/i18n/locale/en.json
Updated components.RequestModal.QuotaDisplay.allowedRequests and ...allowedRequestsUser to embed ICU plural rules for =0, one, and other plural forms.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User as Client (UI)
  participant Frontend as Frontend
  participant Backend as Server (User.getQuota)
  participant DB as Database

  User->>Frontend: selects quota days (0 = Unlimited)
  Frontend->>Backend: GET /quota (quotaDays=0)
  Backend->>DB: query used requests (shared joins/filters)
  alt quotaDays truthy
    Backend->>DB: add createdAt > :date filter
  else quotaDays falsy (0)
    Note right of DB: no date filter applied
  end
  DB-->>Backend: used counts
  Backend-->>Frontend: quota response (counts, restricted flags)
  Frontend->>User: render quota display (ICU plural -> "every day" or "every N days")
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hop through code with a cheerful bound,
Zero means freedom — no dates to be found.
Queries skip time, displays learn to say,
"Every day" or numbers that count the relay.
A tiny change, a joyous boundless day.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main feature addition—support for unlimited quota days—which aligns with the primary changes across backend and UI components.
Linked Issues check ✅ Passed The PR implements the core requirement from issue #1234 by adding an unlimited quota option (value=0) that allows enforcing total limits without per-days restrictions.
Out of Scope Changes check ✅ Passed All changes directly support unlimited quota functionality: backend query refactoring for conditional time filters, UI option for unlimited selection, and message updates for zero-day rendering.

✏️ 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.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
server/entity/User.ts (1)

317-335: LGTM! TV quota query refactored consistently with movie quota logic.

The conditional if (tvQuotaDays) check at lines 331-335 mirrors the movie quota behavior, ensuring unlimited time window when tvQuotaDays=0.

Minor: The leftJoin('request.seasons', 'seasons') at line 319 appears unused since the season count is computed via a separate subquery (lines 340-346). Consider removing it to avoid unnecessary join overhead.

♻️ Optional refactor
 const tvQuotaUsedQuery = requestRepository
   .createQueryBuilder('request')
-  .leftJoin('request.seasons', 'seasons')
   .leftJoin('request.requestedBy', 'requestedBy')
   .where('request.type = :requestType', {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/entity/User.ts` around lines 317 - 335, The
leftJoin('request.seasons', 'seasons') in the TV quota query is unused (season
counts are calculated via a separate subquery) and can be removed to avoid
unnecessary join overhead; update the
requestRepository.createQueryBuilder('request') TV query by deleting the
leftJoin('request.seasons', 'seasons') call (refer to the tvQuotaUsedQuery
variable and the TV quota-related logic) so the query still filters by
request.type, requestedBy.id, status, and optional tvQuotaDays/tvQuotaStartDate
but no longer performs the unused seasons join.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@server/entity/User.ts`:
- Around line 317-335: The leftJoin('request.seasons', 'seasons') in the TV
quota query is unused (season counts are calculated via a separate subquery) and
can be removed to avoid unnecessary join overhead; update the
requestRepository.createQueryBuilder('request') TV query by deleting the
leftJoin('request.seasons', 'seasons') call (refer to the tvQuotaUsedQuery
variable and the TV quota-related logic) so the query still filters by
request.type, requestedBy.id, status, and optional tvQuotaDays/tvQuotaStartDate
but no longer performs the unused seasons join.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cead3e42-11b2-44b6-a7a6-88cc57886072

📥 Commits

Reviewing files that changed from the base of the PR and between 1bb638e and cdbda73.

📒 Files selected for processing (4)
  • server/entity/User.ts
  • src/components/QuotaSelector/index.tsx
  • src/components/RequestModal/QuotaDisplay/index.tsx
  • src/i18n/locale/en.json

gauthier-th
gauthier-th previously approved these changes Apr 2, 2026
@seerr-automation-bot seerr-automation-bot added this to the v3.2.0 milestone Apr 2, 2026
@Roboroads Roboroads force-pushed the feature-no-time-limit-on-requests branch from 235d428 to 8148d1a Compare April 2, 2026 14:03
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.

Limit total open requests (instead of daily limit)

4 participants