Skip to content

feat(requests): allow admins to bypass user quota limits#2026

Open
0xSysR3ll wants to merge 6 commits intodevelopfrom
0xsysr3ll/feat/override-user-request-limit
Open

feat(requests): allow admins to bypass user quota limits#2026
0xSysR3ll wants to merge 6 commits intodevelopfrom
0xsysr3ll/feat/override-user-request-limit

Conversation

@0xSysR3ll
Copy link
Copy Markdown
Contributor

@0xSysR3ll 0xSysR3ll commented Oct 9, 2025

Description

Note

Ported from sct/overseerr#4173 and slightly modified. CC @OwsleyJr

This PR adds the ability for users with MANAGE_REQUESTS permission to bypass quota restrictions when making requests on behalf of other users.

The request will not count against the user's quota limits, allowing admins to make requests on behalf of users who may have exceeded their quota or for special circumstances.

How Has This Been Tested?

Screenshots / Logs (if applicable)

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 "Ignore Quota" override in request modals (visible to users with request-management permission when limits apply) and included the flag in request payloads so bypasses are honored server-side.
  • Bug Fixes
    • Quota calculations now exclude requests created with the ignore-quota override.
  • Documentation
    • Added localized UI text for the new override.
  • Chores
    • Database migrations added to persist the new flag.

@0xSysR3ll 0xSysR3ll requested a review from a team as a code owner October 9, 2025 17:43
@github-actions github-actions Bot added the merge conflict Cannot merge due to merge conflicts label Jan 29, 2026
@github-actions
Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@M0NsTeRRR
Copy link
Copy Markdown
Member

When you have time @0xSysR3ll can you rebase so we can review it ?

@github-actions github-actions Bot removed the merge conflict Cannot merge due to merge conflicts label Apr 19, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 19, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an ignoreQuota boolean across API schema, DB, backend logic, and frontend to allow requests to bypass quota when the requester has MANAGE_REQUESTS; quota calculations now exclude requests with ignoreQuota = true.

Changes

Cohort / File(s) Summary
API Schema
seerr-api.yml
Added ignoreQuota boolean to components.schemas.MediaRequest and POST /request request body with description requiring MANAGE_REQUESTS.
Database Migrations
server/migration/postgres/1777103595541-AddIgnoreQuotaToMediaRequest.ts, server/migration/sqlite/1777103565110-AddIgnoreQuotaToMediaRequest.ts
Postgres migration adds ignoreQuota NOT NULL DEFAULT false. SQLite migration rebuilds media_request to include ignoreQuota, with copy/rename/index rebuild and rollback logic.
Backend Entity & Logic
server/entity/MediaRequest.ts, server/entity/User.ts
MediaRequest gains ignoreQuota column; request-creation logic validates requestBody.ignoreQuota against Permission.MANAGE_REQUESTS, persists only when allowed, and skips quota throws when bypassed. User.getQuota() excludes requests where ignoreQuota = true.
Backend Types
server/interfaces/api/requestInterfaces.ts
MediaRequestBody type now optionally includes ignoreQuota?: boolean.
Frontend Components
src/components/RequestModal/AdvancedRequester/index.tsx, src/components/RequestModal/MovieRequestModal.tsx, src/components/RequestModal/TvRequestModal.tsx, src/components/RequestModal/CollectionRequestModal.tsx
Added ignoreQuota to RequestOverrides; new checkbox visible only to MANAGE_REQUESTS where applicable; modals include ignoreQuota in POST payload and relax client-side quota gating when override set; quota fetch gating expanded to include MANAGE_REQUESTS.
Localization
src/i18n/locale/en.json
Added components.RequestModal.AdvancedRequester.ignoreQuotaTitle and ignoreQuotaDescription strings.

Sequence Diagram

sequenceDiagram
    participant User
    participant UI as AdvancedRequester
    participant Modal as RequestModal
    participant API as Backend API
    participant DB as Database
    participant Quota as Quota Calculator

    User->>UI: Toggle ignoreQuota (if visible)
    UI->>Modal: onChange(overrides with ignoreQuota)
    User->>Modal: Submit request
    Modal->>API: POST /api/v1/request (payload includes ignoreQuota)
    API->>API: Verify Permission.MANAGE_REQUESTS if ignoreQuota requested
    alt bypass allowed
        API->>DB: Save MediaRequest(ignoreQuota = true)
        API->>Modal: Respond 201 Created
    else bypass denied
        API-->>Modal: Respond 403 RequestPermissionError
    end
    Note over Quota,DB: Quota calculations query DB WHERE ignoreQuota = false
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • fallenbagel
  • gauthier-th

Poem

🐰 I nudged a flag beneath moonlit light,
For managers to grant a quota-free night,
A checkbox hop, permission checked true,
DB will remember the requests that flew,
Rabbits cheer — requests bounce through.

🚥 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 accurately describes the primary change: adding functionality for admins to bypass user quota limits when making requests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/components/RequestModal/AdvancedRequester/index.tsx (1)

308-319: ⚠️ Potential issue | 🟠 Major

Include quota bypass in the “has advanced options” render check.

If there is only one server/profile/folder and no alternate requester to show, this component returns null before rendering the new bypass toggle, leaving admins unable to enable the feature.

🐛 Proposed fix
+  const canRenderIgnoreQuota =
+    currentHasPermission([Permission.MANAGE_REQUESTS]) &&
+    !!quota &&
+    ((type === 'movie' && (quota.movie.limit ?? 0) > 0) ||
+      (type === 'tv' && (quota.tv.limit ?? 0) > 0));
+
   if (
     (!data ||
       selectedServer === null ||
       (data.filter((server) => server.is4k === is4k).length < 2 &&
         (!serverData ||
@@
             (serverData.languageProfiles ?? []).length < 2 &&
             !serverData.tags?.length)))) &&
-    (!selectedUser || (filteredUserData ?? []).length < 2)
+    (!selectedUser || (filteredUserData ?? []).length < 2) &&
+    !canRenderIgnoreQuota
   ) {
     return null;
   }
@@
-        {currentHasPermission([Permission.MANAGE_REQUESTS]) &&
-          quota &&
-          ((type === 'movie' && quota.movie.limit && quota.movie.limit > 0) ||
-            (type === 'tv' && quota.tv.limit && quota.tv.limit > 0)) && (
+        {canRenderIgnoreQuota && (
             <div className="mb-2">
               <label htmlFor="ignoreQuota">
                 {intl.formatMessage(messages.ignoreQuotaTitle)}
               </label>

Also applies to: 563-581

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/RequestModal/AdvancedRequester/index.tsx` around lines 308 -
319, The current complex render guard (the condition using data, selectedServer,
is4k, serverData, selectedUser, and filteredUserData) returns null when there
are no alternate servers/profiles/users and therefore prevents the new quota
bypass toggle from rendering; update that guard so it also permits rendering
when the quota bypass control should be shown — i.e., add a check for the quota
bypass state/permission (the component prop/state that governs the new "quota
bypass" toggle, e.g., bypassQuota / canBypassQuota / quotaBypassEnabled) so the
component does not return null when that toggle should be visible; apply the
same change to the corresponding guard around the other block (the one at the
563-581 region) so the bypass toggle is always reachable even if there is only
one server/profile/folder/user.
src/components/RequestModal/TvRequestModal.tsx (2)

289-320: ⚠️ Potential issue | 🟠 Major

Let quota bypass unlock TV season selection too.

With partial requests enabled and no quota remaining, toggleSeason / toggleAllSeasons still return early even after the admin enables bypass, so no seasons can be selected.

🐛 Proposed fix
     if (
       quota?.tv.limit &&
       currentlyRemaining <= 0 &&
+      !requestOverrides?.ignoreQuota &&
       !isSelectedSeason(seasonNumber)
     ) {
       return;
     }
@@
     if (
       quota?.tv.limit &&
       (quota?.tv.remaining ?? 0) < unrequestedSeasons.length &&
+      !requestOverrides?.ignoreQuota
     ) {
       return;
     }
@@
                           quota?.tv.remaining &&
                           quota.tv.limit &&
+                          !requestOverrides?.ignoreQuota &&
                           quota.tv.remaining < unrequestedSeasons.length
                             ? 'opacity-50'
                             : ''
@@
                                 mediaSeason ||
                                 (quota?.tv.limit &&
+                                  !requestOverrides?.ignoreQuota &&
                                   currentlyRemaining <= 0 &&
                                   !isSelectedSeason(season.seasonNumber)) ||

Also applies to: 555-561, 637-646

🤖 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 289 - 320, The
early-return quota checks in toggleSeason and toggleAllSeasons block selection
even when the admin bypass is enabled; update those conditions to skip the
return when the bypass flag is set (e.g. add
!settings.currentSettings.quotaBypassEnabled to the guard). Concretely, in
toggleSeason (the if with quota?.tv.limit && currentlyRemaining <= 0 &&
!isSelectedSeason(seasonNumber)) change it to also require the bypass is not
enabled before returning, and in toggleAllSeasons (the if with quota?.tv.limit
&& (quota?.tv.remaining ?? 0) < unrequestedSeasons.length) do the same; apply
the same pattern to the other analogous guards mentioned (around lines 555-561
and 637-646) so the admin quota bypass allows season selection.

443-460: ⚠️ Potential issue | 🔴 Critical

Fix the malformed okDisabled expression and compare against remaining quota.

Line 454 continues the boolean expression without an operator, which causes a parse failure. While fixing it, use quota.tv.remaining; comparing against limit lets over-quota full-series requests reach the server and fail there.

🐛 Proposed fix
       okDisabled={
         editRequest
           ? false
-          : !settings.currentSettings.partialRequestsEnabled &&
-            quota?.tv.limit &&
-            unrequestedSeasons.length > quota.tv.limit &&
-            !requestOverrides?.ignoreQuota
-          ? true
-          : getAllRequestedSeasons().length >= getAllSeasons().length ||
-            (settings.currentSettings.partialRequestsEnabled &&
-              selectedSeasons.length === 0)
-              quota?.tv.limit &&
-              unrequestedSeasons.length > quota.tv.limit
-            ? true
-            : getAllRequestedSeasons().length >= getAllSeasons().length ||
-              (settings.currentSettings.partialRequestsEnabled &&
-                selectedSeasons.length === 0)
+          : getAllRequestedSeasons().length >= getAllSeasons().length ||
+            (settings.currentSettings.partialRequestsEnabled &&
+              selectedSeasons.length === 0) ||
+            (!!quota?.tv.limit &&
+              !requestOverrides?.ignoreQuota &&
+              (settings.currentSettings.partialRequestsEnabled
+                ? selectedSeasons.length > (quota.tv.remaining ?? 0)
+                : unrequestedSeasons.length > (quota.tv.remaining ?? 0)))
       }
🤖 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 443 - 460, The
okDisabled expression in TvRequestModal (the okDisabled prop near editRequest /
partialRequestsEnabled) is malformed due to a missing operator and needs to be
simplified and corrected to compare against remaining quota; rewrite the boolean
so operators and parentheses are correct, replace any uses of quota?.tv.limit
with quota?.tv.remaining when checking unrequestedSeasons length, and preserve
existing short-circuits (editRequest => false, respect
requestOverrides?.ignoreQuota) while keeping the other checks: full-series
already requested (getAllRequestedSeasons().length >= getAllSeasons().length) or
(partialRequestsEnabled && selectedSeasons.length === 0) should still disable
OK.
server/entity/User.ts (1)

315-364: ⚠️ Potential issue | 🔴 Critical

Fix the duplicate TV quota query block.

The code contains a syntax error: two consecutive await statements without a connecting operator (lines 339–359). Remove the duplicate await requestRepository block and add the ignoreQuota predicate to tvQuotaUsedQuery while preserving the conditional date behavior (if (tvQuotaDays)).

Proposed fix
     const tvQuotaUsedQuery = requestRepository
       .createQueryBuilder('request')
       .leftJoin('request.requestedBy', 'requestedBy')
       .where('request.type = :requestType', {
         requestType: MediaType.TV,
       })
       .andWhere('requestedBy.id = :userId', {
         userId: this.id,
       })
       .andWhere('request.status != :declinedStatus', {
         declinedStatus: MediaRequestStatus.DECLINED,
+      })
+      .andWhere('request.ignoreQuota = :ignoreQuota', {
+        ignoreQuota: false,
       });

     if (tvQuotaDays) {
       tvQuotaUsedQuery.andWhere('request.createdAt > :date', {
         date: tvQuotaStartDate,
       });
     }

     const tvQuotaUsed = tvQuotaLimit
       ? (
-          await requestRepository
-            .createQueryBuilder('request')
-            .leftJoin('request.seasons', 'seasons')
-            .leftJoin('request.requestedBy', 'requestedBy')
-            .where('request.type = :requestType', {
-              requestType: MediaType.TV,
-            })
-            .andWhere('requestedBy.id = :userId', {
-              userId: this.id,
-            })
-            .andWhere('request.createdAt > :date', {
-              date: tvQuotaStartDate,
-            })
-            .andWhere('request.status != :declinedStatus', {
-              declinedStatus: MediaRequestStatus.DECLINED,
-            })
-            .andWhere('request.ignoreQuota = :ignoreQuota', {
-              ignoreQuota: false,
-            })
-          await tvQuotaUsedQuery
+          await tvQuotaUsedQuery
             .addSelect((subQuery) => {
               return subQuery
                 .select('COUNT(season.id)', 'seasonCount')
                 .from(SeasonRequest, 'season')
                 .leftJoin('season.request', 'parentRequest')
                 .where('parentRequest.id = request.id');
             }, 'seasonCount')
             .getMany()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/entity/User.ts` around lines 315 - 364, There is a duplicated/invalid
query block causing a syntax error; remove the extra awaited requestRepository
query and instead add the ignoreQuota predicate to the existing
tvQuotaUsedQuery, preserving the tvQuotaDays conditional date logic (use
tvQuotaStartDate when tvQuotaDays is set) and ensure tvQuotaUsed still computes
the sum of seasonCount from the select on tvQuotaUsedQuery (referencing
tvQuotaUsedQuery, requestRepository, tvQuotaDays, tvQuotaStartDate,
tvQuotaLimit, MediaRequest.seasonCount/seasonCount and the ignoreQuota = false
predicate).
🤖 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 116-130: The requestBody.ignoreQuota flag is trusted from the
client and must be sanitized: compute an effectiveIgnoreQuota boolean that is
true only if the user actually has the MANAGE_REQUESTS permission
(user.hasPermission([Permission.MANAGE_REQUESTS])) and requestBody.ignoreQuota
is true, otherwise set it to false; use this effectiveIgnoreQuota everywhere (in
the quota-enforcement branch that references canBypassQuota and in any
persistence code that stores ignoreQuota) so regular users cannot bypass quota
by sending ignoreQuota: true and managers cannot bypass when the toggle is off.

---

Outside diff comments:
In `@server/entity/User.ts`:
- Around line 315-364: There is a duplicated/invalid query block causing a
syntax error; remove the extra awaited requestRepository query and instead add
the ignoreQuota predicate to the existing tvQuotaUsedQuery, preserving the
tvQuotaDays conditional date logic (use tvQuotaStartDate when tvQuotaDays is
set) and ensure tvQuotaUsed still computes the sum of seasonCount from the
select on tvQuotaUsedQuery (referencing tvQuotaUsedQuery, requestRepository,
tvQuotaDays, tvQuotaStartDate, tvQuotaLimit,
MediaRequest.seasonCount/seasonCount and the ignoreQuota = false predicate).

In `@src/components/RequestModal/AdvancedRequester/index.tsx`:
- Around line 308-319: The current complex render guard (the condition using
data, selectedServer, is4k, serverData, selectedUser, and filteredUserData)
returns null when there are no alternate servers/profiles/users and therefore
prevents the new quota bypass toggle from rendering; update that guard so it
also permits rendering when the quota bypass control should be shown — i.e., add
a check for the quota bypass state/permission (the component prop/state that
governs the new "quota bypass" toggle, e.g., bypassQuota / canBypassQuota /
quotaBypassEnabled) so the component does not return null when that toggle
should be visible; apply the same change to the corresponding guard around the
other block (the one at the 563-581 region) so the bypass toggle is always
reachable even if there is only one server/profile/folder/user.

In `@src/components/RequestModal/TvRequestModal.tsx`:
- Around line 289-320: The early-return quota checks in toggleSeason and
toggleAllSeasons block selection even when the admin bypass is enabled; update
those conditions to skip the return when the bypass flag is set (e.g. add
!settings.currentSettings.quotaBypassEnabled to the guard). Concretely, in
toggleSeason (the if with quota?.tv.limit && currentlyRemaining <= 0 &&
!isSelectedSeason(seasonNumber)) change it to also require the bypass is not
enabled before returning, and in toggleAllSeasons (the if with quota?.tv.limit
&& (quota?.tv.remaining ?? 0) < unrequestedSeasons.length) do the same; apply
the same pattern to the other analogous guards mentioned (around lines 555-561
and 637-646) so the admin quota bypass allows season selection.
- Around line 443-460: The okDisabled expression in TvRequestModal (the
okDisabled prop near editRequest / partialRequestsEnabled) is malformed due to a
missing operator and needs to be simplified and corrected to compare against
remaining quota; rewrite the boolean so operators and parentheses are correct,
replace any uses of quota?.tv.limit with quota?.tv.remaining when checking
unrequestedSeasons length, and preserve existing short-circuits (editRequest =>
false, respect requestOverrides?.ignoreQuota) while keeping the other checks:
full-series already requested (getAllRequestedSeasons().length >=
getAllSeasons().length) or (partialRequestsEnabled && selectedSeasons.length ===
0) should still disable OK.
🪄 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: a5d158d0-dd1e-4f06-8ee6-696e4bcddcde

📥 Commits

Reviewing files that changed from the base of the PR and between 22d3b0f and b29889e.

📒 Files selected for processing (10)
  • seerr-api.yml
  • server/entity/MediaRequest.ts
  • server/entity/User.ts
  • server/interfaces/api/requestInterfaces.ts
  • server/migration/postgres/1760028688313-AddIgnoreQuotaToMediaRequest.ts
  • server/migration/sqlite/1760028688313-AddIgnoreQuotaToMediaRequest.ts
  • src/components/RequestModal/AdvancedRequester/index.tsx
  • src/components/RequestModal/MovieRequestModal.tsx
  • src/components/RequestModal/TvRequestModal.tsx
  • src/i18n/locale/en.json

Comment thread server/entity/MediaRequest.ts Outdated
Copy link
Copy Markdown
Member

@gauthier-th gauthier-th left a comment

Choose a reason for hiding this comment

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

LGTM, but generated migrations are quite old, they should be re-generated before we merge this.

@0xSysR3ll
Copy link
Copy Markdown
Contributor Author

LGTM, but generated migrations are quite old, they should be re-generated before we merge this.

Yep yep, will do. This was just a rebase attempt from GH's web UI :)

Signed-off-by: 0xsysr3ll <0xsysr3ll@pm.me>
Signed-off-by: 0xsysr3ll <0xsysr3ll@pm.me>
@0xSysR3ll 0xSysR3ll force-pushed the 0xsysr3ll/feat/override-user-request-limit branch from b29889e to cdb7b1b Compare April 25, 2026 07:54
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.

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 (2)
src/components/RequestModal/TvRequestModal.tsx (1)

443-454: ⚠️ Potential issue | 🟠 Major

Bypass still fails when partial requests are enabled.

Line 448 only relaxes quota gating in the non-partial branch. In partial mode, toggleSeason and toggleAllSeasons still hard-block selection at quota limits, so admins cannot actually bypass quotas there.

Suggested fix
+  const isIgnoringQuota = !!requestOverrides?.ignoreQuota;

   const toggleSeason = (seasonNumber: number): void => {
@@
-    if (
-      quota?.tv.limit &&
-      currentlyRemaining <= 0 &&
-      !isSelectedSeason(seasonNumber)
-    ) {
+    if (
+      quota?.tv.limit &&
+      currentlyRemaining <= 0 &&
+      !isSelectedSeason(seasonNumber) &&
+      !isIgnoringQuota
+    ) {
       return;
     }
@@
   const toggleAllSeasons = (): void => {
@@
-    if (
-      quota?.tv.limit &&
-      (quota?.tv.remaining ?? 0) < unrequestedSeasons.length
-    ) {
+    if (
+      quota?.tv.limit &&
+      (quota?.tv.remaining ?? 0) < unrequestedSeasons.length &&
+      !isIgnoringQuota
+    ) {
       return;
     }
🤖 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 443 - 454, The
partial-request flow still enforces quota checks in selection functions even
when a bypass is requested; update the quota checks to respect the bypass flag.
Specifically, in the toggleSeason and toggleAllSeasons handlers add a
short-circuit that skips the quota-limit blocking when
requestOverrides?.ignoreQuota (or whichever bypass flag is used) is true (and
keep existing editRequest behavior). Also adjust the okDisabled logic around
partialRequestsEnabled to treat requestOverrides?.ignoreQuota as allowing
selections beyond quota so the OK button reflects the bypass; reference
toggleSeason, toggleAllSeasons, okDisabled, getAllRequestedSeasons,
getAllSeasons and selectedSeasons when making these changes.
src/components/RequestModal/AdvancedRequester/index.tsx (1)

308-320: ⚠️ Potential issue | 🟡 Minor

Early return can hide the new "Bypass User Quota" toggle.

The bail-out at lines 308–320 only considers server/profile/folder/language/tags counts and the user-switcher list. It does not factor in the new ignoreQuota toggle, so an admin viewing a target with a single server, defaulted profiles/folders, and <2 filtered users will get a null advanced section even when quota.{movie|tv}.limit > 0 — meaning the bypass UI is unreachable in exactly the scenario it's most useful (admin requesting on behalf of a user who has hit their quota).

Consider adding the bypass-visibility predicate to this guard, e.g.:

♻️ Proposed adjustment
+  const canShowIgnoreQuota =
+    currentHasPermission([Permission.MANAGE_REQUESTS]) &&
+    !!quota &&
+    ((type === 'movie' && (quota.movie.limit ?? 0) > 0) ||
+      (type === 'tv' && (quota.tv.limit ?? 0) > 0));
+
   if (
     (!data ||
       selectedServer === null ||
       (data.filter((server) => server.is4k === is4k).length < 2 &&
         (!serverData ||
           (serverData.profiles.length < 2 &&
             serverData.rootFolders.length < 2 &&
             (serverData.languageProfiles ?? []).length < 2 &&
             !serverData.tags?.length)))) &&
-    (!selectedUser || (filteredUserData ?? []).length < 2)
+    (!selectedUser || (filteredUserData ?? []).length < 2) &&
+    !canShowIgnoreQuota
   ) {
     return null;
   }

The same canShowIgnoreQuota value can then be reused at line 563 instead of inlining the predicate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/RequestModal/AdvancedRequester/index.tsx` around lines 308 -
320, Compute a canShowIgnoreQuota boolean that checks whether the current target
has a non-zero quota (e.g., quota.movie.limit > 0 || quota.tv.limit > 0) and
whether the ignoreQuota toggle should be exposed (use existing ignoreQuota /
user/admin context as needed), then include canShowIgnoreQuota in the initial
bail-out condition so the advanced section is not returned null when the bypass
UI is needed; also replace the duplicated inline predicate at the later usage
(around where the bypass toggle is rendered) with the same canShowIgnoreQuota
variable so the visibility logic is consistent.
🧹 Nitpick comments (2)
src/components/RequestModal/AdvancedRequester/index.tsx (2)

250-276: ignoreQuota is not re-synced when defaultOverrides changes.

This effect propagates updates to defaultOverrides.{server,profile,folder,language,tags} into local state, but defaultOverrides.ignoreQuota is only consumed in the useState initializer at lines 107–109. If a parent recomputes defaultOverrides (e.g., after an "edit request" hydration), the toggle will be stuck at its first value. For consistency with the other fields:

♻️ Proposed adjustment
     if (defaultOverrides && defaultOverrides.tags != null) {
       setSelectedTags(defaultOverrides.tags);
     }
+
+    if (defaultOverrides && defaultOverrides.ignoreQuota != null) {
+      setIgnoreQuota(defaultOverrides.ignoreQuota);
+    }
   }, [
     defaultOverrides?.server,
     defaultOverrides?.folder,
     defaultOverrides?.profile,
     defaultOverrides?.language,
     defaultOverrides?.tags,
+    defaultOverrides?.ignoreQuota,
   ]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/RequestModal/AdvancedRequester/index.tsx` around lines 250 -
276, The effect that syncs defaultOverrides into local state is missing the
ignoreQuota field, so add logic to the useEffect to call
setIgnoreQuota(defaultOverrides.ignoreQuota) when defaultOverrides.ignoreQuota
is not null/undefined (mirroring the checks used for
setSelectedServer/setSelectedProfile/etc.), and include
defaultOverrides?.ignoreQuota in the effect dependency array so ignoreQuota is
re-synced whenever defaultOverrides changes; this touches the useEffect block
and the local state setter setIgnoreQuota (the current useState initializer for
ignoreQuota at lines ~107–109).

42-44: Nit: i18n key casing inconsistent with the rest of the file.

All sibling keys in this defineMessages block use lowercase (advancedoptions, destinationserver, qualityprofile, requestas, languageprofile, selecttags, notagoptions). The two new keys use camelCase (ignoreQuotaTitle, ignoreQuotaDescription). Worth aligning to ignorequotatitle / ignorequotadescription (or whatever convention the project standardizes on) so extracted message IDs stay uniform.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/RequestModal/AdvancedRequester/index.tsx` around lines 42 -
44, The new i18n keys in the defineMessages block use camelCase
(ignoreQuotaTitle, ignoreQuotaDescription) while the file's convention is
lowercase; rename these keys to match the existing pattern (e.g.,
ignorequotatitle and ignorequotadescription) in the defineMessages declaration
and update any usages of ignoreQuotaTitle/ignoreQuotaDescription to the new
lowercase keys so extracted message IDs remain consistent.
🤖 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/migration/sqlite/1777103565110-AddIgnoreQuotaToMediaRequest.ts`:
- Line 89: The down() migration in AddIgnoreQuotaToMediaRequest (method down)
recreates the media_request table without the ignoreQuota column, which will
silently drop ignoreQuota=true values on rollback; no code change is required,
but update the release notes/changelog to explicitly warn that downgrading after
admins use the quota bypass will lose the audit signal indicating which requests
bypassed quota so operators can make an informed decision before rolling back.
- Around line 7-60: This migration's up() and down() include duplicated rebuilds
of user_push_subscription (the DROP INDEX "IDX_03f7958328e311761b0de675fb" →
CREATE TABLE "temporary_user_push_subscription" → INSERT ... FROM
"user_push_subscription" → DROP TABLE "user_push_subscription" → ALTER TABLE ...
RENAME TO "user_push_subscription" → CREATE INDEX sequence) which are unrelated
to the intended change (adding ignoreQuota to media_request and the
temporary_media_request CREATE/INSERT/RENAME sequence); regenerate the migration
from a clean schema (matching develop) so that the up()/down() only modify
media_request (add ignoreQuota boolean and recreate its indexes) and remove all
duplicated temporary_user_push_subscription rebuild blocks, and also regenerate
the Postgres counterpart (the 1777103595541 migration) to confirm no similar
drift.

---

Outside diff comments:
In `@src/components/RequestModal/AdvancedRequester/index.tsx`:
- Around line 308-320: Compute a canShowIgnoreQuota boolean that checks whether
the current target has a non-zero quota (e.g., quota.movie.limit > 0 ||
quota.tv.limit > 0) and whether the ignoreQuota toggle should be exposed (use
existing ignoreQuota / user/admin context as needed), then include
canShowIgnoreQuota in the initial bail-out condition so the advanced section is
not returned null when the bypass UI is needed; also replace the duplicated
inline predicate at the later usage (around where the bypass toggle is rendered)
with the same canShowIgnoreQuota variable so the visibility logic is consistent.

In `@src/components/RequestModal/TvRequestModal.tsx`:
- Around line 443-454: The partial-request flow still enforces quota checks in
selection functions even when a bypass is requested; update the quota checks to
respect the bypass flag. Specifically, in the toggleSeason and toggleAllSeasons
handlers add a short-circuit that skips the quota-limit blocking when
requestOverrides?.ignoreQuota (or whichever bypass flag is used) is true (and
keep existing editRequest behavior). Also adjust the okDisabled logic around
partialRequestsEnabled to treat requestOverrides?.ignoreQuota as allowing
selections beyond quota so the OK button reflects the bypass; reference
toggleSeason, toggleAllSeasons, okDisabled, getAllRequestedSeasons,
getAllSeasons and selectedSeasons when making these changes.

---

Nitpick comments:
In `@src/components/RequestModal/AdvancedRequester/index.tsx`:
- Around line 250-276: The effect that syncs defaultOverrides into local state
is missing the ignoreQuota field, so add logic to the useEffect to call
setIgnoreQuota(defaultOverrides.ignoreQuota) when defaultOverrides.ignoreQuota
is not null/undefined (mirroring the checks used for
setSelectedServer/setSelectedProfile/etc.), and include
defaultOverrides?.ignoreQuota in the effect dependency array so ignoreQuota is
re-synced whenever defaultOverrides changes; this touches the useEffect block
and the local state setter setIgnoreQuota (the current useState initializer for
ignoreQuota at lines ~107–109).
- Around line 42-44: The new i18n keys in the defineMessages block use camelCase
(ignoreQuotaTitle, ignoreQuotaDescription) while the file's convention is
lowercase; rename these keys to match the existing pattern (e.g.,
ignorequotatitle and ignorequotadescription) in the defineMessages declaration
and update any usages of ignoreQuotaTitle/ignoreQuotaDescription to the new
lowercase keys so extracted message IDs remain consistent.
🪄 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: 4cf7fc58-9036-4ed4-b79d-cfe6bddad5db

📥 Commits

Reviewing files that changed from the base of the PR and between b29889e and cdb7b1b.

📒 Files selected for processing (10)
  • seerr-api.yml
  • server/entity/MediaRequest.ts
  • server/entity/User.ts
  • server/interfaces/api/requestInterfaces.ts
  • server/migration/postgres/1777103595541-AddIgnoreQuotaToMediaRequest.ts
  • server/migration/sqlite/1777103565110-AddIgnoreQuotaToMediaRequest.ts
  • src/components/RequestModal/AdvancedRequester/index.tsx
  • src/components/RequestModal/MovieRequestModal.tsx
  • src/components/RequestModal/TvRequestModal.tsx
  • src/i18n/locale/en.json
✅ Files skipped from review due to trivial changes (2)
  • server/interfaces/api/requestInterfaces.ts
  • src/i18n/locale/en.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/entity/MediaRequest.ts

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.

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)

91-96: ⚠️ Potential issue | 🟡 Minor

Quota fetch gate omits MANAGE_REQUESTS, preventing target-user quota visibility for MANAGE_REQUESTS-only admins.

The SWR fetch for the target user's quota only runs when hasPermission(Permission.MANAGE_USERS), but both the user selector and "Bypass User Quota" toggle in AdvancedRequester allow MANAGE_REQUESTS users to operate. A MANAGE_REQUESTS-only admin who picks a different target user will get quota === undefined, which:

  • Hides QuotaDisplay for that target.
  • Hides the "Bypass User Quota" toggle (even though they have permission to set it).

Same issue exists in MovieRequestModal.tsx and CollectionRequestModal.tsx.

Suggested adjustment
   const { data: quota } = useSWR<QuotaResponse>(
     user &&
-      (!requestOverrides?.user?.id || hasPermission(Permission.MANAGE_USERS))
+      (!requestOverrides?.user?.id ||
+        hasPermission([Permission.MANAGE_USERS, Permission.MANAGE_REQUESTS], {
+          type: 'or',
+        }))
       ? `/api/v1/user/${requestOverrides?.user?.id ?? user.id}/quota`
       : null
   );
🤖 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 91 - 96, The SWR
quota fetch gate currently only allows fetching the target user's quota when
hasPermission(Permission.MANAGE_USERS), which prevents MANAGE_REQUESTS-only
admins from seeing or bypassing target-user quotas; update the conditional used
in useSWR in TvRequestModal (and mirror the same change in MovieRequestModal and
CollectionRequestModal) to also allow hasPermission(Permission.MANAGE_REQUESTS)
when deciding whether to fetch `/api/v1/user/${requestOverrides?.user?.id ??
user.id}/quota`; this ensures QuotaDisplay and the "Bypass User Quota" toggle in
AdvancedRequester are shown for users with MANAGE_REQUESTS permission when a
different target user is selected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/components/RequestModal/TvRequestModal.tsx`:
- Around line 91-96: The SWR quota fetch gate currently only allows fetching the
target user's quota when hasPermission(Permission.MANAGE_USERS), which prevents
MANAGE_REQUESTS-only admins from seeing or bypassing target-user quotas; update
the conditional used in useSWR in TvRequestModal (and mirror the same change in
MovieRequestModal and CollectionRequestModal) to also allow
hasPermission(Permission.MANAGE_REQUESTS) when deciding whether to fetch
`/api/v1/user/${requestOverrides?.user?.id ?? user.id}/quota`; this ensures
QuotaDisplay and the "Bypass User Quota" toggle in AdvancedRequester are shown
for users with MANAGE_REQUESTS permission when a different target user is
selected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1e2dedf2-c00d-4451-afc8-d53dba4ed68a

📥 Commits

Reviewing files that changed from the base of the PR and between cdb7b1b and 89730bd.

📒 Files selected for processing (2)
  • server/entity/MediaRequest.ts
  • src/components/RequestModal/TvRequestModal.tsx

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/components/RequestModal/TvRequestModal.tsx (1)

286-323: ⚠️ Potential issue | 🟠 Major

ignoreQuota bypass is incomplete — season selection is still blocked by quota.

toggleSeason (Lines 293-299) and toggleAllSeasons (Lines 318-323) short-circuit when currentlyRemaining <= 0 or quota.tv.remaining < unrequestedSeasons.length, regardless of requestOverrides?.ignoreQuota. With partialRequestsEnabled, an admin who toggles "Bypass User Quota" on a user who is already over quota still cannot tick any additional seasons, so the bypass is effectively unreachable through the UI. Only the okDisabled clause at Line 451 was updated.

Consider gating these blocks on !requestOverrides?.ignoreQuota as well (and similarly for the visual opacity-50 checks at Lines 553-558 and 636-642 that signal "blocked").

🔧 Suggested fix
   const toggleSeason = (seasonNumber: number): void => {
     // If this season already has a pending request, don't allow it to be toggled
     if (getAllRequestedSeasons().includes(seasonNumber)) {
       return;
     }

     // If there are no more remaining requests available, block toggle
     if (
       quota?.tv.limit &&
       currentlyRemaining <= 0 &&
-      !isSelectedSeason(seasonNumber)
+      !isSelectedSeason(seasonNumber) &&
+      !requestOverrides?.ignoreQuota
     ) {
       return;
     }
@@
   const toggleAllSeasons = (): void => {
     // If the user has a quota and not enough requests for all seasons, block toggleAllSeasons
     if (
       quota?.tv.limit &&
-      (quota?.tv.remaining ?? 0) < unrequestedSeasons.length
+      (quota?.tv.remaining ?? 0) < unrequestedSeasons.length &&
+      !requestOverrides?.ignoreQuota
     ) {
       return;
     }
🤖 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 286 - 323,
toggleSeason and toggleAllSeasons are still blocked by quota checks even when
requestOverrides?.ignoreQuota is true; update the short-circuit conditions to
also allow toggling when requestOverrides?.ignoreQuota is set (i.e., only
enforce currentlyRemaining <= 0 or quota?.tv.remaining <
unrequestedSeasons.length when !requestOverrides?.ignoreQuota). Also update the
UI blocking/opacity logic that uses "opacity-50" so it reflects
requestOverrides?.ignoreQuota (remove or skip the faded/disabled styling when
ignoreQuota is true) so admins can actually interact with seasons when bypass is
enabled; reference toggleSeason, currentlyRemaining, quota?.tv.limit,
toggleAllSeasons, quota?.tv.remaining, unrequestedSeasons, and the opacity-50
visual checks.
src/components/RequestModal/CollectionRequestModal.tsx (1)

189-215: ⚠️ Potential issue | 🟠 Major

Add quota prop to AdvancedRequester and forward ignoreQuota in collection requests.

CollectionRequestModal does not pass quota to AdvancedRequester (line 525) and does not forward requestOverrides?.ignoreQuota in the POST body, unlike MovieRequestModal and TvRequestModal. This means the "Bypass User Quota" toggle will not appear for collection requests and admins cannot bypass quotas when requesting collections.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/RequestModal/CollectionRequestModal.tsx` around lines 189 -
215, CollectionRequestModal is not passing the quota prop to AdvancedRequester
and is not forwarding requestOverrides?.ignoreQuota in the request body; update
the AdvancedRequester usage in CollectionRequestModal to include the quota prop
(same prop name used by MovieRequestModal/TvRequestModal) and modify sendRequest
(overrideParams) to include ignoreQuota: requestOverrides.ignoreQuota so the
POST body sent by sendRequest includes ignoreQuota alongside
serverId/profileId/rootFolder/userId/tags; mirror the same shape and prop names
used in MovieRequestModal and TvRequestModal to ensure the "Bypass User Quota"
toggle appears and the flag is sent to the API.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/components/RequestModal/CollectionRequestModal.tsx`:
- Around line 189-215: CollectionRequestModal is not passing the quota prop to
AdvancedRequester and is not forwarding requestOverrides?.ignoreQuota in the
request body; update the AdvancedRequester usage in CollectionRequestModal to
include the quota prop (same prop name used by MovieRequestModal/TvRequestModal)
and modify sendRequest (overrideParams) to include ignoreQuota:
requestOverrides.ignoreQuota so the POST body sent by sendRequest includes
ignoreQuota alongside serverId/profileId/rootFolder/userId/tags; mirror the same
shape and prop names used in MovieRequestModal and TvRequestModal to ensure the
"Bypass User Quota" toggle appears and the flag is sent to the API.

In `@src/components/RequestModal/TvRequestModal.tsx`:
- Around line 286-323: toggleSeason and toggleAllSeasons are still blocked by
quota checks even when requestOverrides?.ignoreQuota is true; update the
short-circuit conditions to also allow toggling when
requestOverrides?.ignoreQuota is set (i.e., only enforce currentlyRemaining <= 0
or quota?.tv.remaining < unrequestedSeasons.length when
!requestOverrides?.ignoreQuota). Also update the UI blocking/opacity logic that
uses "opacity-50" so it reflects requestOverrides?.ignoreQuota (remove or skip
the faded/disabled styling when ignoreQuota is true) so admins can actually
interact with seasons when bypass is enabled; reference toggleSeason,
currentlyRemaining, quota?.tv.limit, toggleAllSeasons, quota?.tv.remaining,
unrequestedSeasons, and the opacity-50 visual checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 74ed28a5-5601-457a-ace8-584314a337c8

📥 Commits

Reviewing files that changed from the base of the PR and between 89730bd and 126ecb7.

📒 Files selected for processing (3)
  • src/components/RequestModal/CollectionRequestModal.tsx
  • src/components/RequestModal/MovieRequestModal.tsx
  • src/components/RequestModal/TvRequestModal.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/RequestModal/MovieRequestModal.tsx

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/components/RequestModal/AdvancedRequester/index.tsx (1)

42-44: Message key naming inconsistent with existing keys.

All other keys in this messages object use lowercase identifiers (advancedoptions, requestas, qualityprofile, …). The new keys are camelCase (ignoreQuotaTitle, ignoreQuotaDescription). Consider ignorequotatitle / ignorequotadescription (or bypassquota*) for consistency. Note this only affects the source key; translated strings are unaffected.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/RequestModal/AdvancedRequester/index.tsx` around lines 42 -
44, The new message keys in the messages object use camelCase (ignoreQuotaTitle,
ignoreQuotaDescription) which is inconsistent with existing lowercase keys;
rename these keys to match the convention (e.g., ignorequotatitle and
ignorequotadescription or bypassquota... as preferred) wherever they are defined
and referenced in AdvancedRequester (search for ignoreQuotaTitle /
ignoreQuotaDescription) so the messages object and all lookups use the new
lowercase keys consistently.
🤖 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/AdvancedRequester/index.tsx`:
- Around line 107-109: The ignoreQuota state can remain true when its toggle
becomes hidden; add a useEffect that watches the visibility predicate (the
permission check + per-type limit > 0) and selectedUser and calls
setIgnoreQuota(false) whenever that predicate becomes false or selectedUser
changes; update the component where ignoreQuota and setIgnoreQuota are declared
(and similarly the other occurrence around lines 271-273) so the toggle cannot
leave stale true values in the POST body by resetting ignoreQuota to false
whenever visibility is lost or the user selection changes.
- Around line 573-583: The label's htmlFor="ignoreQuota" isn't connected to a
real control because SlideCheckbox lacks an id and proper ARIA handling; update
the JSX to pass an id (e.g., id="ignoreQuota") and any ARIA attributes
(aria-labelledby, aria-label) into SlideCheckbox, and modify the SlideCheckbox
component to accept and forward an id and arbitrary ARIA props to the underlying
focusable element, use the checked prop to set aria-checked (do not hardcode
false), and ensure the toggle uses an accessible event (onClick/onChange) that
toggles via setIgnoreQuota so the label correctly toggles the control and screen
readers see the real state.

---

Nitpick comments:
In `@src/components/RequestModal/AdvancedRequester/index.tsx`:
- Around line 42-44: The new message keys in the messages object use camelCase
(ignoreQuotaTitle, ignoreQuotaDescription) which is inconsistent with existing
lowercase keys; rename these keys to match the convention (e.g.,
ignorequotatitle and ignorequotadescription or bypassquota... as preferred)
wherever they are defined and referenced in AdvancedRequester (search for
ignoreQuotaTitle / ignoreQuotaDescription) so the messages object and all
lookups use the new lowercase keys consistently.
🪄 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: e8eae48c-047d-40a6-851e-eaf3c86ed818

📥 Commits

Reviewing files that changed from the base of the PR and between 126ecb7 and 469f407.

📒 Files selected for processing (3)
  • src/components/RequestModal/AdvancedRequester/index.tsx
  • src/components/RequestModal/CollectionRequestModal.tsx
  • src/components/RequestModal/TvRequestModal.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/RequestModal/CollectionRequestModal.tsx
  • src/components/RequestModal/TvRequestModal.tsx

Comment on lines +107 to +109
const [ignoreQuota, setIgnoreQuota] = useState<boolean>(
defaultOverrides?.ignoreQuota ?? false
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Stale ignoreQuota state when the toggle becomes hidden.

If ignoreQuota was previously toggled on and the toggle then becomes hidden (e.g., admin switches “Request As” to a user where limit is 0/undefined, or the target loses MANAGE_REQUESTS gating), the state remains true and is silently included in the POST body. The server still enforces MANAGE_REQUESTS, so this isn’t a security risk, but it can produce surprising request payloads. Consider resetting ignoreQuota to false whenever the visibility predicate (permission + per-type limit > 0) becomes false, or whenever selectedUser changes.

Also applies to: 271-273

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/RequestModal/AdvancedRequester/index.tsx` around lines 107 -
109, The ignoreQuota state can remain true when its toggle becomes hidden; add a
useEffect that watches the visibility predicate (the permission check + per-type
limit > 0) and selectedUser and calls setIgnoreQuota(false) whenever that
predicate becomes false or selectedUser changes; update the component where
ignoreQuota and setIgnoreQuota are declared (and similarly the other occurrence
around lines 271-273) so the toggle cannot leave stale true values in the POST
body by resetting ignoreQuota to false whenever visibility is lost or the user
selection changes.

Comment thread src/components/RequestModal/AdvancedRequester/index.tsx
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.

3 participants