fix: file manager limits - #663

Merged
coodos merged 1 commit into
mainfrom
fix/file-manager-limits
Jan 11, 2026
Merged

fix: file manager limits#663
coodos merged 1 commit into
mainfrom
fix/file-manager-limits

Conversation

@sosweetham

@sosweethamsosweetham commented Jan 9, 2026

Copy link
Copy Markdown
Member

Description of change

Issue Number

Type of change

  • Breaking (any change that would cause existing functionality to not work as expected)
  • New (a change which implements a new feature)
  • Update (a change which updates existing functionality)
  • Fix (a change which fixes an issue)
  • Docs (changes to the documentation)
  • Chore (refactoring, build scripts or anything else that isn't user-facing)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Batch file upload: Upload multiple files simultaneously with per-file validation, quota enforcement, and comprehensive error reporting.
  • Bug Fixes & Improvements

    • Enhanced file validation with consistent size limits (1GB per file) and quota checks.
    • Refined error messaging for improved clarity.
    • Standardized API response structures and authentication handling across file operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitaiBot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added batch file upload handler supporting up to 50 files with per-file validation and error aggregation. Enhanced folderId normalization, standardized response shapes across endpoints to include owner/signatures/canPreview fields, exposed getFileSignatures endpoint, and refined error handling consistency.

Changes

Cohort / File(s)Summary
Batch Upload Handler
platforms/file-manager-api/src/controllers/FileController.ts
New uploadFiles method supporting array upload (max 50 files) with per-file validation (1GB limit, quota enforcement), service-level file creation, and aggregated response with per-file error tracking
Single Upload & Existing Flow
platforms/file-manager-api/src/controllers/FileController.ts
Updated existing single-file upload with refined max file size messaging and consistent folderId normalization; authentication and quota error handling paths preserved
Endpoint Normalization & Consistency
platforms/file-manager-api/src/controllers/FileController.ts
FolderId normalization across multiple endpoints treating "null" and empty strings as null; standardized content-type and disposition headers in download/preview responses; refactored response shapes for consistent owner, signatures, and canPreview field inclusion
Public API & Error Handling
platforms/file-manager-api/src/controllers/FileController.ts
Exposed getFileSignatures endpoint with nested user details mapping; updated error paths for consistent 401 and 404 responses; import type annotations for Request/Response; formatting and string literal adjustments

Sequence Diagram

sequenceDiagram
actor Client
participant FileController
participant FileService
participant StorageSystem
participant QuotaManager
Client->>FileController: POST /uploadFiles (50 files)
FileController->>FileController: Parse & validate array
loop For each file
FileController->>FileController: Validate file size (≤1GB)
FileController->>QuotaManager: Check user quota
alt Quota exceeded
FileController-->>FileController: Add per-file error
else Quota available
FileController->>FileService: Create file record
FileService->>StorageSystem: Store file
StorageSystem-->>FileService: Return file metadata
FileService-->>FileController: File created
FileController-->>FileController: Add to success results
end
end
FileController-->>Client: Return aggregated response (successes + errors)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop, hop, uploading in a batch today,
Fifty files can have their say,
Signatures aligned, responses gleam,
Validation flows like a coding dream! ✨📁

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check nameStatusExplanationResolution
Description check⚠️ WarningThe PR description is incomplete with all template sections left blank or unchecked, including Issue Number, Type of change selection, testing details, and all checklist items.Complete the PR description by filling in the Issue Number, selecting the applicable Type of change, documenting how changes were tested, and checking off completed checklist items.
Title check❓ InconclusiveThe title 'fix: file manager limits' is vague and does not clearly describe the main changes, which include batch file upload support, normalization improvements, and multiple API enhancements.Consider using a more specific title that reflects the primary change, such as 'feat: add batch file upload support and storage limits validation' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @platforms/file-manager-api/src/controllers/FileController.ts:
- Around line 10-13: The uploadMultiple middleware uses multer.memoryStorage
which can OOM for large batches (e.g., 50×1GB); replace multer.memoryStorage()
with multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.
- Around line 153-157: Remove the unreachable duplicate authentication guard
that checks if (!req.user) and returns res.status(401).json({ error:
"Authentication required" }) inside the same request handler; keep the original
early-return check (the one at the top of the handler) and delete the later
redundant block so authentication is only validated once per request in this
controller method.
🧹 Nitpick comments (5)
platforms/file-manager-api/src/controllers/FileController.ts (5)

5-13: Consolidate duplicate multer configurations.

Both upload and uploadMultiple have identical configuration (1GB limit, memoryStorage). A single multer instance can handle both single and multiple file uploads.

♻️ Proposed consolidation
-const upload = multer({- limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit- storage: multer.memoryStorage(),-});--const uploadMultiple = multer({+const upload = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Then use upload.single("file") and upload.array("files", 50) throughout.


36-44: Remove redundant file size check.

Multer already enforces the 1GB limit at configuration (line 6), so this manual check is unreachable. If a file exceeds 1GB, multer will reject it before reaching this code.

♻️ Proposed fix
- // Check file size limit (1GB)- const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes- if (req.file.size > MAX_FILE_SIZE) {- return res.status(413).json({- error: "File size exceeds 1GB limit",- maxSize: MAX_FILE_SIZE,- fileSize: req.file.size,- });- }-

62-68: Extract folderId normalization to a helper method.

This normalization logic is duplicated across at least 5 handlers (uploadFile, uploadFiles, updateFile, getFiles, moveFile). Extract it to reduce duplication and ensure consistency.

♻️ Proposed helper method

Add this private helper to the FileController class:

privatenormalizeFolderId(folderId: any): string|null{returnfolderId==="null"||folderId===""||folderId===null||folderId===undefined
? null
: folderId;}

Then replace all occurrences with:

- const normalizedFolderId =- folderId === "null" ||- folderId === "" ||- folderId === null ||- folderId === undefined- ? null- : folderId;+ const normalizedFolderId = this.normalizeFolderId(folderId);

251-273: Consider extracting signature mapping to reduce duplication.

The signature mapping logic (including user details) is duplicated in getFile (lines 315-331) and getFileSignatures (lines 500-517). Consider extracting to a private helper method.

♻️ Example helper method
privatemapSignature(sig: any){return{id: sig.id,userId: sig.userId,user: sig.user
? {id: sig.user.id,name: sig.user.name,ename: sig.user.ename,avatarUrl: sig.user.avatarUrl,}
: null,md5Hash: sig.md5Hash,signature: sig.signature,publicKey: sig.publicKey,message: sig.message,createdAt: sig.createdAt,};}

81-91: Response shape inconsistency across endpoints.

The uploadFile response doesn't include owner or canPreview fields that are returned by getFiles (lines 261-271) and getFile (lines 302-332). Consider standardizing response shapes for consistency, unless this omission is intentional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0144c4d and 3a079ff.

⛔ Files ignored due to path filters (4)
  • platforms/esigner/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/esigner/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
📒 Files selected for processing (2)
  • platforms/file-manager-api/src/controllers/FileController.ts
  • platforms/file-manager/src/routes/(protected)/files/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
platforms/file-manager-api/src/controllers/FileController.ts (4)

181-190: Batch upload doesn't support per-file displayName and description.

Unlike uploadFile (line 59), the batch upload handler hardcodes displayName and description as undefined. This means all uploaded files will have null metadata. Consider whether this is intentional or if you want to support per-file metadata via a different mechanism (e.g., parallel JSON array in the request body).


159-217: Verify partial upload behavior is intentional.

The batch upload processes files sequentially and returns both successful uploads and errors. If some files fail, the successfully uploaded files remain in storage (no rollback). Verify this partial-success pattern aligns with your requirements, as users may expect an all-or-nothing transaction.


412-418: LGTM: Proper Content-Disposition headers for download vs preview.

The distinction between attachment for downloads and inline for previews is correct and follows HTTP best practices.

Also applies to: 446-451


483-523: LGTM: File signatures endpoint properly secured.

The new getFileSignatures endpoint includes proper authentication checks and verifies file access before returning signature data. The response mapping includes user details consistently with other endpoints.

Comment on lines +10 to 13
const uploadMultiple = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory storage risk with large batch uploads.

Using memoryStorage with 50 files × 1GB max = potential 50GB memory consumption. This can crash the Node.js process with out-of-memory errors. Consider using diskStorage for temporary file storage or streaming directly to your storage backend.

Also applies to: 103-103

🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines 10
- 13, The uploadMultiple middleware uses multer.memoryStorage which can OOM for
large batches (e.g., 50×1GB); replace multer.memoryStorage() with
multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.

Comment on lines +118 to +119
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential storage quota race condition with concurrent uploads.

The storage quota is fetched once at the beginning (line 118-119), and while currentUsed is tracked locally within the batch (line 192), there's no protection against concurrent upload requests from the same user. If multiple batches are uploaded simultaneously, each will check against the same initial quota, potentially exceeding the limit.

Consider implementing database-level constraints or locks to ensure quota enforcement across concurrent requests.

Also applies to: 172-179

Comment on lines +153 to +157
if (!req.user) {
return res
.status(401)
.json({ error: "Authentication required" });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate authentication check.

This authentication check is unreachable dead code. The same check already exists at lines 111-115 and would have returned early if req.user is not present.

🔧 Proposed fix
 const results: UploadResult[] = [];
const errors: UploadError[] = [];
let currentUsed = used;
- if (!req.user) {- return res- .status(401)- .json({ error: "Authentication required" });- }-
for (const file of files) {
📝 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.

Suggested change
if(!req.user){
returnres
.status(401)
.json({error: "Authentication required"});
}
constresults: UploadResult[]=[];
consterrors: UploadError[]=[];
letcurrentUsed=used;
for(constfileoffiles){
🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines
153 - 157, Remove the unreachable duplicate authentication guard that checks if
(!req.user) and returns res.status(401).json({ error: "Authentication required"
}) inside the same request handler; keep the original early-return check (the
one at the top of the handler) and delete the later redundant block so
authentication is only validated once per request in this controller method.

@coodos
coodos merged commit 84abd62 into mainJan 11, 2026
4 checks passed
This was referenced Mar 15, 2026
Sign up for freeto 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.

2 participants

@sosweetham@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix: file manager limits - #663

Merged
coodos merged 1 commit into
mainfrom
fix/file-manager-limits
Jan 11, 2026
Merged

fix: file manager limits#663
coodos merged 1 commit into
mainfrom
fix/file-manager-limits

Conversation

@sosweetham

@sosweethamsosweetham commented Jan 9, 2026

Copy link
Copy Markdown
Member

Description of change

Issue Number

Type of change

  • Breaking (any change that would cause existing functionality to not work as expected)
  • New (a change which implements a new feature)
  • Update (a change which updates existing functionality)
  • Fix (a change which fixes an issue)
  • Docs (changes to the documentation)
  • Chore (refactoring, build scripts or anything else that isn't user-facing)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Batch file upload: Upload multiple files simultaneously with per-file validation, quota enforcement, and comprehensive error reporting.
  • Bug Fixes & Improvements

    • Enhanced file validation with consistent size limits (1GB per file) and quota checks.
    • Refined error messaging for improved clarity.
    • Standardized API response structures and authentication handling across file operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitaiBot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added batch file upload handler supporting up to 50 files with per-file validation and error aggregation. Enhanced folderId normalization, standardized response shapes across endpoints to include owner/signatures/canPreview fields, exposed getFileSignatures endpoint, and refined error handling consistency.

Changes

Cohort / File(s)Summary
Batch Upload Handler
platforms/file-manager-api/src/controllers/FileController.ts
New uploadFiles method supporting array upload (max 50 files) with per-file validation (1GB limit, quota enforcement), service-level file creation, and aggregated response with per-file error tracking
Single Upload & Existing Flow
platforms/file-manager-api/src/controllers/FileController.ts
Updated existing single-file upload with refined max file size messaging and consistent folderId normalization; authentication and quota error handling paths preserved
Endpoint Normalization & Consistency
platforms/file-manager-api/src/controllers/FileController.ts
FolderId normalization across multiple endpoints treating "null" and empty strings as null; standardized content-type and disposition headers in download/preview responses; refactored response shapes for consistent owner, signatures, and canPreview field inclusion
Public API & Error Handling
platforms/file-manager-api/src/controllers/FileController.ts
Exposed getFileSignatures endpoint with nested user details mapping; updated error paths for consistent 401 and 404 responses; import type annotations for Request/Response; formatting and string literal adjustments

Sequence Diagram

sequenceDiagram
actor Client
participant FileController
participant FileService
participant StorageSystem
participant QuotaManager
Client->>FileController: POST /uploadFiles (50 files)
FileController->>FileController: Parse & validate array
loop For each file
FileController->>FileController: Validate file size (≤1GB)
FileController->>QuotaManager: Check user quota
alt Quota exceeded
FileController-->>FileController: Add per-file error
else Quota available
FileController->>FileService: Create file record
FileService->>StorageSystem: Store file
StorageSystem-->>FileService: Return file metadata
FileService-->>FileController: File created
FileController-->>FileController: Add to success results
end
end
FileController-->>Client: Return aggregated response (successes + errors)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop, hop, uploading in a batch today,
Fifty files can have their say,
Signatures aligned, responses gleam,
Validation flows like a coding dream! ✨📁

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check nameStatusExplanationResolution
Description check⚠️ WarningThe PR description is incomplete with all template sections left blank or unchecked, including Issue Number, Type of change selection, testing details, and all checklist items.Complete the PR description by filling in the Issue Number, selecting the applicable Type of change, documenting how changes were tested, and checking off completed checklist items.
Title check❓ InconclusiveThe title 'fix: file manager limits' is vague and does not clearly describe the main changes, which include batch file upload support, normalization improvements, and multiple API enhancements.Consider using a more specific title that reflects the primary change, such as 'feat: add batch file upload support and storage limits validation' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @platforms/file-manager-api/src/controllers/FileController.ts:
- Around line 10-13: The uploadMultiple middleware uses multer.memoryStorage
which can OOM for large batches (e.g., 50×1GB); replace multer.memoryStorage()
with multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.
- Around line 153-157: Remove the unreachable duplicate authentication guard
that checks if (!req.user) and returns res.status(401).json({ error:
"Authentication required" }) inside the same request handler; keep the original
early-return check (the one at the top of the handler) and delete the later
redundant block so authentication is only validated once per request in this
controller method.
🧹 Nitpick comments (5)
platforms/file-manager-api/src/controllers/FileController.ts (5)

5-13: Consolidate duplicate multer configurations.

Both upload and uploadMultiple have identical configuration (1GB limit, memoryStorage). A single multer instance can handle both single and multiple file uploads.

♻️ Proposed consolidation
-const upload = multer({- limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit- storage: multer.memoryStorage(),-});--const uploadMultiple = multer({+const upload = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Then use upload.single("file") and upload.array("files", 50) throughout.


36-44: Remove redundant file size check.

Multer already enforces the 1GB limit at configuration (line 6), so this manual check is unreachable. If a file exceeds 1GB, multer will reject it before reaching this code.

♻️ Proposed fix
- // Check file size limit (1GB)- const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes- if (req.file.size > MAX_FILE_SIZE) {- return res.status(413).json({- error: "File size exceeds 1GB limit",- maxSize: MAX_FILE_SIZE,- fileSize: req.file.size,- });- }-

62-68: Extract folderId normalization to a helper method.

This normalization logic is duplicated across at least 5 handlers (uploadFile, uploadFiles, updateFile, getFiles, moveFile). Extract it to reduce duplication and ensure consistency.

♻️ Proposed helper method

Add this private helper to the FileController class:

privatenormalizeFolderId(folderId: any): string|null{returnfolderId==="null"||folderId===""||folderId===null||folderId===undefined
? null
: folderId;}

Then replace all occurrences with:

- const normalizedFolderId =- folderId === "null" ||- folderId === "" ||- folderId === null ||- folderId === undefined- ? null- : folderId;+ const normalizedFolderId = this.normalizeFolderId(folderId);

251-273: Consider extracting signature mapping to reduce duplication.

The signature mapping logic (including user details) is duplicated in getFile (lines 315-331) and getFileSignatures (lines 500-517). Consider extracting to a private helper method.

♻️ Example helper method
privatemapSignature(sig: any){return{id: sig.id,userId: sig.userId,user: sig.user
? {id: sig.user.id,name: sig.user.name,ename: sig.user.ename,avatarUrl: sig.user.avatarUrl,}
: null,md5Hash: sig.md5Hash,signature: sig.signature,publicKey: sig.publicKey,message: sig.message,createdAt: sig.createdAt,};}

81-91: Response shape inconsistency across endpoints.

The uploadFile response doesn't include owner or canPreview fields that are returned by getFiles (lines 261-271) and getFile (lines 302-332). Consider standardizing response shapes for consistency, unless this omission is intentional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0144c4d and 3a079ff.

⛔ Files ignored due to path filters (4)
  • platforms/esigner/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/esigner/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
📒 Files selected for processing (2)
  • platforms/file-manager-api/src/controllers/FileController.ts
  • platforms/file-manager/src/routes/(protected)/files/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
platforms/file-manager-api/src/controllers/FileController.ts (4)

181-190: Batch upload doesn't support per-file displayName and description.

Unlike uploadFile (line 59), the batch upload handler hardcodes displayName and description as undefined. This means all uploaded files will have null metadata. Consider whether this is intentional or if you want to support per-file metadata via a different mechanism (e.g., parallel JSON array in the request body).


159-217: Verify partial upload behavior is intentional.

The batch upload processes files sequentially and returns both successful uploads and errors. If some files fail, the successfully uploaded files remain in storage (no rollback). Verify this partial-success pattern aligns with your requirements, as users may expect an all-or-nothing transaction.


412-418: LGTM: Proper Content-Disposition headers for download vs preview.

The distinction between attachment for downloads and inline for previews is correct and follows HTTP best practices.

Also applies to: 446-451


483-523: LGTM: File signatures endpoint properly secured.

The new getFileSignatures endpoint includes proper authentication checks and verifies file access before returning signature data. The response mapping includes user details consistently with other endpoints.

Comment on lines +10 to 13
const uploadMultiple = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory storage risk with large batch uploads.

Using memoryStorage with 50 files × 1GB max = potential 50GB memory consumption. This can crash the Node.js process with out-of-memory errors. Consider using diskStorage for temporary file storage or streaming directly to your storage backend.

Also applies to: 103-103

🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines 10
- 13, The uploadMultiple middleware uses multer.memoryStorage which can OOM for
large batches (e.g., 50×1GB); replace multer.memoryStorage() with
multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.

Comment on lines +118 to +119
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential storage quota race condition with concurrent uploads.

The storage quota is fetched once at the beginning (line 118-119), and while currentUsed is tracked locally within the batch (line 192), there's no protection against concurrent upload requests from the same user. If multiple batches are uploaded simultaneously, each will check against the same initial quota, potentially exceeding the limit.

Consider implementing database-level constraints or locks to ensure quota enforcement across concurrent requests.

Also applies to: 172-179

Comment on lines +153 to +157
if (!req.user) {
return res
.status(401)
.json({ error: "Authentication required" });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate authentication check.

This authentication check is unreachable dead code. The same check already exists at lines 111-115 and would have returned early if req.user is not present.

🔧 Proposed fix
 const results: UploadResult[] = [];
const errors: UploadError[] = [];
let currentUsed = used;
- if (!req.user) {- return res- .status(401)- .json({ error: "Authentication required" });- }-
for (const file of files) {
📝 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.

Suggested change
if(!req.user){
returnres
.status(401)
.json({error: "Authentication required"});
}
constresults: UploadResult[]=[];
consterrors: UploadError[]=[];
letcurrentUsed=used;
for(constfileoffiles){
🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines
153 - 157, Remove the unreachable duplicate authentication guard that checks if
(!req.user) and returns res.status(401).json({ error: "Authentication required"
}) inside the same request handler; keep the original early-return check (the
one at the top of the handler) and delete the later redundant block so
authentication is only validated once per request in this controller method.

@coodos
coodos merged commit 84abd62 into mainJan 11, 2026
4 checks passed
This was referenced Mar 15, 2026
Sign up for freeto 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.

2 participants

@sosweetham@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: file manager limits - #663

Merged
coodos merged 1 commit into
mainfrom
fix/file-manager-limits
Jan 11, 2026
Merged

fix: file manager limits#663
coodos merged 1 commit into
mainfrom
fix/file-manager-limits

Conversation

@sosweetham

@sosweethamsosweetham commented Jan 9, 2026

Copy link
Copy Markdown
Member

Description of change

Issue Number

Type of change

  • Breaking (any change that would cause existing functionality to not work as expected)
  • New (a change which implements a new feature)
  • Update (a change which updates existing functionality)
  • Fix (a change which fixes an issue)
  • Docs (changes to the documentation)
  • Chore (refactoring, build scripts or anything else that isn't user-facing)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Batch file upload: Upload multiple files simultaneously with per-file validation, quota enforcement, and comprehensive error reporting.
  • Bug Fixes & Improvements

    • Enhanced file validation with consistent size limits (1GB per file) and quota checks.
    • Refined error messaging for improved clarity.
    • Standardized API response structures and authentication handling across file operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitaiBot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added batch file upload handler supporting up to 50 files with per-file validation and error aggregation. Enhanced folderId normalization, standardized response shapes across endpoints to include owner/signatures/canPreview fields, exposed getFileSignatures endpoint, and refined error handling consistency.

Changes

Cohort / File(s)Summary
Batch Upload Handler
platforms/file-manager-api/src/controllers/FileController.ts
New uploadFiles method supporting array upload (max 50 files) with per-file validation (1GB limit, quota enforcement), service-level file creation, and aggregated response with per-file error tracking
Single Upload & Existing Flow
platforms/file-manager-api/src/controllers/FileController.ts
Updated existing single-file upload with refined max file size messaging and consistent folderId normalization; authentication and quota error handling paths preserved
Endpoint Normalization & Consistency
platforms/file-manager-api/src/controllers/FileController.ts
FolderId normalization across multiple endpoints treating "null" and empty strings as null; standardized content-type and disposition headers in download/preview responses; refactored response shapes for consistent owner, signatures, and canPreview field inclusion
Public API & Error Handling
platforms/file-manager-api/src/controllers/FileController.ts
Exposed getFileSignatures endpoint with nested user details mapping; updated error paths for consistent 401 and 404 responses; import type annotations for Request/Response; formatting and string literal adjustments

Sequence Diagram

sequenceDiagram
actor Client
participant FileController
participant FileService
participant StorageSystem
participant QuotaManager
Client->>FileController: POST /uploadFiles (50 files)
FileController->>FileController: Parse & validate array
loop For each file
FileController->>FileController: Validate file size (≤1GB)
FileController->>QuotaManager: Check user quota
alt Quota exceeded
FileController-->>FileController: Add per-file error
else Quota available
FileController->>FileService: Create file record
FileService->>StorageSystem: Store file
StorageSystem-->>FileService: Return file metadata
FileService-->>FileController: File created
FileController-->>FileController: Add to success results
end
end
FileController-->>Client: Return aggregated response (successes + errors)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop, hop, uploading in a batch today,
Fifty files can have their say,
Signatures aligned, responses gleam,
Validation flows like a coding dream! ✨📁

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check nameStatusExplanationResolution
Description check⚠️ WarningThe PR description is incomplete with all template sections left blank or unchecked, including Issue Number, Type of change selection, testing details, and all checklist items.Complete the PR description by filling in the Issue Number, selecting the applicable Type of change, documenting how changes were tested, and checking off completed checklist items.
Title check❓ InconclusiveThe title 'fix: file manager limits' is vague and does not clearly describe the main changes, which include batch file upload support, normalization improvements, and multiple API enhancements.Consider using a more specific title that reflects the primary change, such as 'feat: add batch file upload support and storage limits validation' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @platforms/file-manager-api/src/controllers/FileController.ts:
- Around line 10-13: The uploadMultiple middleware uses multer.memoryStorage
which can OOM for large batches (e.g., 50×1GB); replace multer.memoryStorage()
with multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.
- Around line 153-157: Remove the unreachable duplicate authentication guard
that checks if (!req.user) and returns res.status(401).json({ error:
"Authentication required" }) inside the same request handler; keep the original
early-return check (the one at the top of the handler) and delete the later
redundant block so authentication is only validated once per request in this
controller method.
🧹 Nitpick comments (5)
platforms/file-manager-api/src/controllers/FileController.ts (5)

5-13: Consolidate duplicate multer configurations.

Both upload and uploadMultiple have identical configuration (1GB limit, memoryStorage). A single multer instance can handle both single and multiple file uploads.

♻️ Proposed consolidation
-const upload = multer({- limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit- storage: multer.memoryStorage(),-});--const uploadMultiple = multer({+const upload = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Then use upload.single("file") and upload.array("files", 50) throughout.


36-44: Remove redundant file size check.

Multer already enforces the 1GB limit at configuration (line 6), so this manual check is unreachable. If a file exceeds 1GB, multer will reject it before reaching this code.

♻️ Proposed fix
- // Check file size limit (1GB)- const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes- if (req.file.size > MAX_FILE_SIZE) {- return res.status(413).json({- error: "File size exceeds 1GB limit",- maxSize: MAX_FILE_SIZE,- fileSize: req.file.size,- });- }-

62-68: Extract folderId normalization to a helper method.

This normalization logic is duplicated across at least 5 handlers (uploadFile, uploadFiles, updateFile, getFiles, moveFile). Extract it to reduce duplication and ensure consistency.

♻️ Proposed helper method

Add this private helper to the FileController class:

privatenormalizeFolderId(folderId: any): string|null{returnfolderId==="null"||folderId===""||folderId===null||folderId===undefined
? null
: folderId;}

Then replace all occurrences with:

- const normalizedFolderId =- folderId === "null" ||- folderId === "" ||- folderId === null ||- folderId === undefined- ? null- : folderId;+ const normalizedFolderId = this.normalizeFolderId(folderId);

251-273: Consider extracting signature mapping to reduce duplication.

The signature mapping logic (including user details) is duplicated in getFile (lines 315-331) and getFileSignatures (lines 500-517). Consider extracting to a private helper method.

♻️ Example helper method
privatemapSignature(sig: any){return{id: sig.id,userId: sig.userId,user: sig.user
? {id: sig.user.id,name: sig.user.name,ename: sig.user.ename,avatarUrl: sig.user.avatarUrl,}
: null,md5Hash: sig.md5Hash,signature: sig.signature,publicKey: sig.publicKey,message: sig.message,createdAt: sig.createdAt,};}

81-91: Response shape inconsistency across endpoints.

The uploadFile response doesn't include owner or canPreview fields that are returned by getFiles (lines 261-271) and getFile (lines 302-332). Consider standardizing response shapes for consistency, unless this omission is intentional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0144c4d and 3a079ff.

⛔ Files ignored due to path filters (4)
  • platforms/esigner/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/esigner/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
📒 Files selected for processing (2)
  • platforms/file-manager-api/src/controllers/FileController.ts
  • platforms/file-manager/src/routes/(protected)/files/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
platforms/file-manager-api/src/controllers/FileController.ts (4)

181-190: Batch upload doesn't support per-file displayName and description.

Unlike uploadFile (line 59), the batch upload handler hardcodes displayName and description as undefined. This means all uploaded files will have null metadata. Consider whether this is intentional or if you want to support per-file metadata via a different mechanism (e.g., parallel JSON array in the request body).


159-217: Verify partial upload behavior is intentional.

The batch upload processes files sequentially and returns both successful uploads and errors. If some files fail, the successfully uploaded files remain in storage (no rollback). Verify this partial-success pattern aligns with your requirements, as users may expect an all-or-nothing transaction.


412-418: LGTM: Proper Content-Disposition headers for download vs preview.

The distinction between attachment for downloads and inline for previews is correct and follows HTTP best practices.

Also applies to: 446-451


483-523: LGTM: File signatures endpoint properly secured.

The new getFileSignatures endpoint includes proper authentication checks and verifies file access before returning signature data. The response mapping includes user details consistently with other endpoints.

Comment on lines +10 to 13
const uploadMultiple = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory storage risk with large batch uploads.

Using memoryStorage with 50 files × 1GB max = potential 50GB memory consumption. This can crash the Node.js process with out-of-memory errors. Consider using diskStorage for temporary file storage or streaming directly to your storage backend.

Also applies to: 103-103

🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines 10
- 13, The uploadMultiple middleware uses multer.memoryStorage which can OOM for
large batches (e.g., 50×1GB); replace multer.memoryStorage() with
multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.

Comment on lines +118 to +119
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential storage quota race condition with concurrent uploads.

The storage quota is fetched once at the beginning (line 118-119), and while currentUsed is tracked locally within the batch (line 192), there's no protection against concurrent upload requests from the same user. If multiple batches are uploaded simultaneously, each will check against the same initial quota, potentially exceeding the limit.

Consider implementing database-level constraints or locks to ensure quota enforcement across concurrent requests.

Also applies to: 172-179

Comment on lines +153 to +157
if (!req.user) {
return res
.status(401)
.json({ error: "Authentication required" });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate authentication check.

This authentication check is unreachable dead code. The same check already exists at lines 111-115 and would have returned early if req.user is not present.

🔧 Proposed fix
 const results: UploadResult[] = [];
const errors: UploadError[] = [];
let currentUsed = used;
- if (!req.user) {- return res- .status(401)- .json({ error: "Authentication required" });- }-
for (const file of files) {
📝 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.

Suggested change
if(!req.user){
returnres
.status(401)
.json({error: "Authentication required"});
}
constresults: UploadResult[]=[];
consterrors: UploadError[]=[];
letcurrentUsed=used;
for(constfileoffiles){
🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines
153 - 157, Remove the unreachable duplicate authentication guard that checks if
(!req.user) and returns res.status(401).json({ error: "Authentication required"
}) inside the same request handler; keep the original early-return check (the
one at the top of the handler) and delete the later redundant block so
authentication is only validated once per request in this controller method.

@coodos
coodos merged commit 84abd62 into mainJan 11, 2026
4 checks passed
This was referenced Mar 15, 2026
Sign up for freeto 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.

2 participants

@sosweetham@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: file manager limits - #663

Merged
coodos merged 1 commit into
mainfrom
fix/file-manager-limits
Jan 11, 2026
Merged

fix: file manager limits#663
coodos merged 1 commit into
mainfrom
fix/file-manager-limits

Conversation

@sosweetham

@sosweethamsosweetham commented Jan 9, 2026

Copy link
Copy Markdown
Member

Description of change

Issue Number

Type of change

  • Breaking (any change that would cause existing functionality to not work as expected)
  • New (a change which implements a new feature)
  • Update (a change which updates existing functionality)
  • Fix (a change which fixes an issue)
  • Docs (changes to the documentation)
  • Chore (refactoring, build scripts or anything else that isn't user-facing)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Batch file upload: Upload multiple files simultaneously with per-file validation, quota enforcement, and comprehensive error reporting.
  • Bug Fixes & Improvements

    • Enhanced file validation with consistent size limits (1GB per file) and quota checks.
    • Refined error messaging for improved clarity.
    • Standardized API response structures and authentication handling across file operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitaiBot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added batch file upload handler supporting up to 50 files with per-file validation and error aggregation. Enhanced folderId normalization, standardized response shapes across endpoints to include owner/signatures/canPreview fields, exposed getFileSignatures endpoint, and refined error handling consistency.

Changes

Cohort / File(s)Summary
Batch Upload Handler
platforms/file-manager-api/src/controllers/FileController.ts
New uploadFiles method supporting array upload (max 50 files) with per-file validation (1GB limit, quota enforcement), service-level file creation, and aggregated response with per-file error tracking
Single Upload & Existing Flow
platforms/file-manager-api/src/controllers/FileController.ts
Updated existing single-file upload with refined max file size messaging and consistent folderId normalization; authentication and quota error handling paths preserved
Endpoint Normalization & Consistency
platforms/file-manager-api/src/controllers/FileController.ts
FolderId normalization across multiple endpoints treating "null" and empty strings as null; standardized content-type and disposition headers in download/preview responses; refactored response shapes for consistent owner, signatures, and canPreview field inclusion
Public API & Error Handling
platforms/file-manager-api/src/controllers/FileController.ts
Exposed getFileSignatures endpoint with nested user details mapping; updated error paths for consistent 401 and 404 responses; import type annotations for Request/Response; formatting and string literal adjustments

Sequence Diagram

sequenceDiagram
actor Client
participant FileController
participant FileService
participant StorageSystem
participant QuotaManager
Client->>FileController: POST /uploadFiles (50 files)
FileController->>FileController: Parse & validate array
loop For each file
FileController->>FileController: Validate file size (≤1GB)
FileController->>QuotaManager: Check user quota
alt Quota exceeded
FileController-->>FileController: Add per-file error
else Quota available
FileController->>FileService: Create file record
FileService->>StorageSystem: Store file
StorageSystem-->>FileService: Return file metadata
FileService-->>FileController: File created
FileController-->>FileController: Add to success results
end
end
FileController-->>Client: Return aggregated response (successes + errors)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop, hop, uploading in a batch today,
Fifty files can have their say,
Signatures aligned, responses gleam,
Validation flows like a coding dream! ✨📁

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check nameStatusExplanationResolution
Description check⚠️ WarningThe PR description is incomplete with all template sections left blank or unchecked, including Issue Number, Type of change selection, testing details, and all checklist items.Complete the PR description by filling in the Issue Number, selecting the applicable Type of change, documenting how changes were tested, and checking off completed checklist items.
Title check❓ InconclusiveThe title 'fix: file manager limits' is vague and does not clearly describe the main changes, which include batch file upload support, normalization improvements, and multiple API enhancements.Consider using a more specific title that reflects the primary change, such as 'feat: add batch file upload support and storage limits validation' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @platforms/file-manager-api/src/controllers/FileController.ts:
- Around line 10-13: The uploadMultiple middleware uses multer.memoryStorage
which can OOM for large batches (e.g., 50×1GB); replace multer.memoryStorage()
with multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.
- Around line 153-157: Remove the unreachable duplicate authentication guard
that checks if (!req.user) and returns res.status(401).json({ error:
"Authentication required" }) inside the same request handler; keep the original
early-return check (the one at the top of the handler) and delete the later
redundant block so authentication is only validated once per request in this
controller method.
🧹 Nitpick comments (5)
platforms/file-manager-api/src/controllers/FileController.ts (5)

5-13: Consolidate duplicate multer configurations.

Both upload and uploadMultiple have identical configuration (1GB limit, memoryStorage). A single multer instance can handle both single and multiple file uploads.

♻️ Proposed consolidation
-const upload = multer({- limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit- storage: multer.memoryStorage(),-});--const uploadMultiple = multer({+const upload = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Then use upload.single("file") and upload.array("files", 50) throughout.


36-44: Remove redundant file size check.

Multer already enforces the 1GB limit at configuration (line 6), so this manual check is unreachable. If a file exceeds 1GB, multer will reject it before reaching this code.

♻️ Proposed fix
- // Check file size limit (1GB)- const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes- if (req.file.size > MAX_FILE_SIZE) {- return res.status(413).json({- error: "File size exceeds 1GB limit",- maxSize: MAX_FILE_SIZE,- fileSize: req.file.size,- });- }-

62-68: Extract folderId normalization to a helper method.

This normalization logic is duplicated across at least 5 handlers (uploadFile, uploadFiles, updateFile, getFiles, moveFile). Extract it to reduce duplication and ensure consistency.

♻️ Proposed helper method

Add this private helper to the FileController class:

privatenormalizeFolderId(folderId: any): string|null{returnfolderId==="null"||folderId===""||folderId===null||folderId===undefined
? null
: folderId;}

Then replace all occurrences with:

- const normalizedFolderId =- folderId === "null" ||- folderId === "" ||- folderId === null ||- folderId === undefined- ? null- : folderId;+ const normalizedFolderId = this.normalizeFolderId(folderId);

251-273: Consider extracting signature mapping to reduce duplication.

The signature mapping logic (including user details) is duplicated in getFile (lines 315-331) and getFileSignatures (lines 500-517). Consider extracting to a private helper method.

♻️ Example helper method
privatemapSignature(sig: any){return{id: sig.id,userId: sig.userId,user: sig.user
? {id: sig.user.id,name: sig.user.name,ename: sig.user.ename,avatarUrl: sig.user.avatarUrl,}
: null,md5Hash: sig.md5Hash,signature: sig.signature,publicKey: sig.publicKey,message: sig.message,createdAt: sig.createdAt,};}

81-91: Response shape inconsistency across endpoints.

The uploadFile response doesn't include owner or canPreview fields that are returned by getFiles (lines 261-271) and getFile (lines 302-332). Consider standardizing response shapes for consistency, unless this omission is intentional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0144c4d and 3a079ff.

⛔ Files ignored due to path filters (4)
  • platforms/esigner/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/esigner/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
📒 Files selected for processing (2)
  • platforms/file-manager-api/src/controllers/FileController.ts
  • platforms/file-manager/src/routes/(protected)/files/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
platforms/file-manager-api/src/controllers/FileController.ts (4)

181-190: Batch upload doesn't support per-file displayName and description.

Unlike uploadFile (line 59), the batch upload handler hardcodes displayName and description as undefined. This means all uploaded files will have null metadata. Consider whether this is intentional or if you want to support per-file metadata via a different mechanism (e.g., parallel JSON array in the request body).


159-217: Verify partial upload behavior is intentional.

The batch upload processes files sequentially and returns both successful uploads and errors. If some files fail, the successfully uploaded files remain in storage (no rollback). Verify this partial-success pattern aligns with your requirements, as users may expect an all-or-nothing transaction.


412-418: LGTM: Proper Content-Disposition headers for download vs preview.

The distinction between attachment for downloads and inline for previews is correct and follows HTTP best practices.

Also applies to: 446-451


483-523: LGTM: File signatures endpoint properly secured.

The new getFileSignatures endpoint includes proper authentication checks and verifies file access before returning signature data. The response mapping includes user details consistently with other endpoints.

Comment on lines +10 to 13
const uploadMultiple = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory storage risk with large batch uploads.

Using memoryStorage with 50 files × 1GB max = potential 50GB memory consumption. This can crash the Node.js process with out-of-memory errors. Consider using diskStorage for temporary file storage or streaming directly to your storage backend.

Also applies to: 103-103

🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines 10
- 13, The uploadMultiple middleware uses multer.memoryStorage which can OOM for
large batches (e.g., 50×1GB); replace multer.memoryStorage() with
multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.

Comment on lines +118 to +119
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential storage quota race condition with concurrent uploads.

The storage quota is fetched once at the beginning (line 118-119), and while currentUsed is tracked locally within the batch (line 192), there's no protection against concurrent upload requests from the same user. If multiple batches are uploaded simultaneously, each will check against the same initial quota, potentially exceeding the limit.

Consider implementing database-level constraints or locks to ensure quota enforcement across concurrent requests.

Also applies to: 172-179

Comment on lines +153 to +157
if (!req.user) {
return res
.status(401)
.json({ error: "Authentication required" });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate authentication check.

This authentication check is unreachable dead code. The same check already exists at lines 111-115 and would have returned early if req.user is not present.

🔧 Proposed fix
 const results: UploadResult[] = [];
const errors: UploadError[] = [];
let currentUsed = used;
- if (!req.user) {- return res- .status(401)- .json({ error: "Authentication required" });- }-
for (const file of files) {
📝 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.

Suggested change
if(!req.user){
returnres
.status(401)
.json({error: "Authentication required"});
}
constresults: UploadResult[]=[];
consterrors: UploadError[]=[];
letcurrentUsed=used;
for(constfileoffiles){
🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines
153 - 157, Remove the unreachable duplicate authentication guard that checks if
(!req.user) and returns res.status(401).json({ error: "Authentication required"
}) inside the same request handler; keep the original early-return check (the
one at the top of the handler) and delete the later redundant block so
authentication is only validated once per request in this controller method.

@coodos
coodos merged commit 84abd62 into mainJan 11, 2026
4 checks passed
This was referenced Mar 15, 2026
Sign up for freeto 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.

2 participants

@sosweetham@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix: file manager limits - #663

Merged
coodos merged 1 commit into
mainfrom
fix/file-manager-limits
Jan 11, 2026
Merged

fix: file manager limits#663
coodos merged 1 commit into
mainfrom
fix/file-manager-limits

Conversation

@sosweetham

@sosweethamsosweetham commented Jan 9, 2026

Copy link
Copy Markdown
Member

Description of change

Issue Number

Type of change

  • Breaking (any change that would cause existing functionality to not work as expected)
  • New (a change which implements a new feature)
  • Update (a change which updates existing functionality)
  • Fix (a change which fixes an issue)
  • Docs (changes to the documentation)
  • Chore (refactoring, build scripts or anything else that isn't user-facing)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Batch file upload: Upload multiple files simultaneously with per-file validation, quota enforcement, and comprehensive error reporting.
  • Bug Fixes & Improvements

    • Enhanced file validation with consistent size limits (1GB per file) and quota checks.
    • Refined error messaging for improved clarity.
    • Standardized API response structures and authentication handling across file operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitaiBot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added batch file upload handler supporting up to 50 files with per-file validation and error aggregation. Enhanced folderId normalization, standardized response shapes across endpoints to include owner/signatures/canPreview fields, exposed getFileSignatures endpoint, and refined error handling consistency.

Changes

Cohort / File(s)Summary
Batch Upload Handler
platforms/file-manager-api/src/controllers/FileController.ts
New uploadFiles method supporting array upload (max 50 files) with per-file validation (1GB limit, quota enforcement), service-level file creation, and aggregated response with per-file error tracking
Single Upload & Existing Flow
platforms/file-manager-api/src/controllers/FileController.ts
Updated existing single-file upload with refined max file size messaging and consistent folderId normalization; authentication and quota error handling paths preserved
Endpoint Normalization & Consistency
platforms/file-manager-api/src/controllers/FileController.ts
FolderId normalization across multiple endpoints treating "null" and empty strings as null; standardized content-type and disposition headers in download/preview responses; refactored response shapes for consistent owner, signatures, and canPreview field inclusion
Public API & Error Handling
platforms/file-manager-api/src/controllers/FileController.ts
Exposed getFileSignatures endpoint with nested user details mapping; updated error paths for consistent 401 and 404 responses; import type annotations for Request/Response; formatting and string literal adjustments

Sequence Diagram

sequenceDiagram
actor Client
participant FileController
participant FileService
participant StorageSystem
participant QuotaManager
Client->>FileController: POST /uploadFiles (50 files)
FileController->>FileController: Parse & validate array
loop For each file
FileController->>FileController: Validate file size (≤1GB)
FileController->>QuotaManager: Check user quota
alt Quota exceeded
FileController-->>FileController: Add per-file error
else Quota available
FileController->>FileService: Create file record
FileService->>StorageSystem: Store file
StorageSystem-->>FileService: Return file metadata
FileService-->>FileController: File created
FileController-->>FileController: Add to success results
end
end
FileController-->>Client: Return aggregated response (successes + errors)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop, hop, uploading in a batch today,
Fifty files can have their say,
Signatures aligned, responses gleam,
Validation flows like a coding dream! ✨📁

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check nameStatusExplanationResolution
Description check⚠️ WarningThe PR description is incomplete with all template sections left blank or unchecked, including Issue Number, Type of change selection, testing details, and all checklist items.Complete the PR description by filling in the Issue Number, selecting the applicable Type of change, documenting how changes were tested, and checking off completed checklist items.
Title check❓ InconclusiveThe title 'fix: file manager limits' is vague and does not clearly describe the main changes, which include batch file upload support, normalization improvements, and multiple API enhancements.Consider using a more specific title that reflects the primary change, such as 'feat: add batch file upload support and storage limits validation' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @platforms/file-manager-api/src/controllers/FileController.ts:
- Around line 10-13: The uploadMultiple middleware uses multer.memoryStorage
which can OOM for large batches (e.g., 50×1GB); replace multer.memoryStorage()
with multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.
- Around line 153-157: Remove the unreachable duplicate authentication guard
that checks if (!req.user) and returns res.status(401).json({ error:
"Authentication required" }) inside the same request handler; keep the original
early-return check (the one at the top of the handler) and delete the later
redundant block so authentication is only validated once per request in this
controller method.
🧹 Nitpick comments (5)
platforms/file-manager-api/src/controllers/FileController.ts (5)

5-13: Consolidate duplicate multer configurations.

Both upload and uploadMultiple have identical configuration (1GB limit, memoryStorage). A single multer instance can handle both single and multiple file uploads.

♻️ Proposed consolidation
-const upload = multer({- limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit- storage: multer.memoryStorage(),-});--const uploadMultiple = multer({+const upload = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Then use upload.single("file") and upload.array("files", 50) throughout.


36-44: Remove redundant file size check.

Multer already enforces the 1GB limit at configuration (line 6), so this manual check is unreachable. If a file exceeds 1GB, multer will reject it before reaching this code.

♻️ Proposed fix
- // Check file size limit (1GB)- const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes- if (req.file.size > MAX_FILE_SIZE) {- return res.status(413).json({- error: "File size exceeds 1GB limit",- maxSize: MAX_FILE_SIZE,- fileSize: req.file.size,- });- }-

62-68: Extract folderId normalization to a helper method.

This normalization logic is duplicated across at least 5 handlers (uploadFile, uploadFiles, updateFile, getFiles, moveFile). Extract it to reduce duplication and ensure consistency.

♻️ Proposed helper method

Add this private helper to the FileController class:

privatenormalizeFolderId(folderId: any): string|null{returnfolderId==="null"||folderId===""||folderId===null||folderId===undefined
? null
: folderId;}

Then replace all occurrences with:

- const normalizedFolderId =- folderId === "null" ||- folderId === "" ||- folderId === null ||- folderId === undefined- ? null- : folderId;+ const normalizedFolderId = this.normalizeFolderId(folderId);

251-273: Consider extracting signature mapping to reduce duplication.

The signature mapping logic (including user details) is duplicated in getFile (lines 315-331) and getFileSignatures (lines 500-517). Consider extracting to a private helper method.

♻️ Example helper method
privatemapSignature(sig: any){return{id: sig.id,userId: sig.userId,user: sig.user
? {id: sig.user.id,name: sig.user.name,ename: sig.user.ename,avatarUrl: sig.user.avatarUrl,}
: null,md5Hash: sig.md5Hash,signature: sig.signature,publicKey: sig.publicKey,message: sig.message,createdAt: sig.createdAt,};}

81-91: Response shape inconsistency across endpoints.

The uploadFile response doesn't include owner or canPreview fields that are returned by getFiles (lines 261-271) and getFile (lines 302-332). Consider standardizing response shapes for consistency, unless this omission is intentional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0144c4d and 3a079ff.

⛔ Files ignored due to path filters (4)
  • platforms/esigner/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/esigner/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
📒 Files selected for processing (2)
  • platforms/file-manager-api/src/controllers/FileController.ts
  • platforms/file-manager/src/routes/(protected)/files/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
platforms/file-manager-api/src/controllers/FileController.ts (4)

181-190: Batch upload doesn't support per-file displayName and description.

Unlike uploadFile (line 59), the batch upload handler hardcodes displayName and description as undefined. This means all uploaded files will have null metadata. Consider whether this is intentional or if you want to support per-file metadata via a different mechanism (e.g., parallel JSON array in the request body).


159-217: Verify partial upload behavior is intentional.

The batch upload processes files sequentially and returns both successful uploads and errors. If some files fail, the successfully uploaded files remain in storage (no rollback). Verify this partial-success pattern aligns with your requirements, as users may expect an all-or-nothing transaction.


412-418: LGTM: Proper Content-Disposition headers for download vs preview.

The distinction between attachment for downloads and inline for previews is correct and follows HTTP best practices.

Also applies to: 446-451


483-523: LGTM: File signatures endpoint properly secured.

The new getFileSignatures endpoint includes proper authentication checks and verifies file access before returning signature data. The response mapping includes user details consistently with other endpoints.

Comment on lines +10 to 13
const uploadMultiple = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory storage risk with large batch uploads.

Using memoryStorage with 50 files × 1GB max = potential 50GB memory consumption. This can crash the Node.js process with out-of-memory errors. Consider using diskStorage for temporary file storage or streaming directly to your storage backend.

Also applies to: 103-103

🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines 10
- 13, The uploadMultiple middleware uses multer.memoryStorage which can OOM for
large batches (e.g., 50×1GB); replace multer.memoryStorage() with
multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.

Comment on lines +118 to +119
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential storage quota race condition with concurrent uploads.

The storage quota is fetched once at the beginning (line 118-119), and while currentUsed is tracked locally within the batch (line 192), there's no protection against concurrent upload requests from the same user. If multiple batches are uploaded simultaneously, each will check against the same initial quota, potentially exceeding the limit.

Consider implementing database-level constraints or locks to ensure quota enforcement across concurrent requests.

Also applies to: 172-179

Comment on lines +153 to +157
if (!req.user) {
return res
.status(401)
.json({ error: "Authentication required" });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate authentication check.

This authentication check is unreachable dead code. The same check already exists at lines 111-115 and would have returned early if req.user is not present.

🔧 Proposed fix
 const results: UploadResult[] = [];
const errors: UploadError[] = [];
let currentUsed = used;
- if (!req.user) {- return res- .status(401)- .json({ error: "Authentication required" });- }-
for (const file of files) {
📝 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.

Suggested change
if(!req.user){
returnres
.status(401)
.json({error: "Authentication required"});
}
constresults: UploadResult[]=[];
consterrors: UploadError[]=[];
letcurrentUsed=used;
for(constfileoffiles){
🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines
153 - 157, Remove the unreachable duplicate authentication guard that checks if
(!req.user) and returns res.status(401).json({ error: "Authentication required"
}) inside the same request handler; keep the original early-return check (the
one at the top of the handler) and delete the later redundant block so
authentication is only validated once per request in this controller method.

@coodos
coodos merged commit 84abd62 into mainJan 11, 2026
4 checks passed
This was referenced Mar 15, 2026
Sign up for freeto 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.

2 participants

@sosweetham@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: file manager limits - #663

Merged
coodos merged 1 commit into
mainfrom
fix/file-manager-limits
Jan 11, 2026
Merged

fix: file manager limits#663
coodos merged 1 commit into
mainfrom
fix/file-manager-limits

Conversation

@sosweetham

@sosweethamsosweetham commented Jan 9, 2026

Copy link
Copy Markdown
Member

Description of change

Issue Number

Type of change

  • Breaking (any change that would cause existing functionality to not work as expected)
  • New (a change which implements a new feature)
  • Update (a change which updates existing functionality)
  • Fix (a change which fixes an issue)
  • Docs (changes to the documentation)
  • Chore (refactoring, build scripts or anything else that isn't user-facing)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Batch file upload: Upload multiple files simultaneously with per-file validation, quota enforcement, and comprehensive error reporting.
  • Bug Fixes & Improvements

    • Enhanced file validation with consistent size limits (1GB per file) and quota checks.
    • Refined error messaging for improved clarity.
    • Standardized API response structures and authentication handling across file operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitaiBot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added batch file upload handler supporting up to 50 files with per-file validation and error aggregation. Enhanced folderId normalization, standardized response shapes across endpoints to include owner/signatures/canPreview fields, exposed getFileSignatures endpoint, and refined error handling consistency.

Changes

Cohort / File(s)Summary
Batch Upload Handler
platforms/file-manager-api/src/controllers/FileController.ts
New uploadFiles method supporting array upload (max 50 files) with per-file validation (1GB limit, quota enforcement), service-level file creation, and aggregated response with per-file error tracking
Single Upload & Existing Flow
platforms/file-manager-api/src/controllers/FileController.ts
Updated existing single-file upload with refined max file size messaging and consistent folderId normalization; authentication and quota error handling paths preserved
Endpoint Normalization & Consistency
platforms/file-manager-api/src/controllers/FileController.ts
FolderId normalization across multiple endpoints treating "null" and empty strings as null; standardized content-type and disposition headers in download/preview responses; refactored response shapes for consistent owner, signatures, and canPreview field inclusion
Public API & Error Handling
platforms/file-manager-api/src/controllers/FileController.ts
Exposed getFileSignatures endpoint with nested user details mapping; updated error paths for consistent 401 and 404 responses; import type annotations for Request/Response; formatting and string literal adjustments

Sequence Diagram

sequenceDiagram
actor Client
participant FileController
participant FileService
participant StorageSystem
participant QuotaManager
Client->>FileController: POST /uploadFiles (50 files)
FileController->>FileController: Parse & validate array
loop For each file
FileController->>FileController: Validate file size (≤1GB)
FileController->>QuotaManager: Check user quota
alt Quota exceeded
FileController-->>FileController: Add per-file error
else Quota available
FileController->>FileService: Create file record
FileService->>StorageSystem: Store file
StorageSystem-->>FileService: Return file metadata
FileService-->>FileController: File created
FileController-->>FileController: Add to success results
end
end
FileController-->>Client: Return aggregated response (successes + errors)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop, hop, uploading in a batch today,
Fifty files can have their say,
Signatures aligned, responses gleam,
Validation flows like a coding dream! ✨📁

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check nameStatusExplanationResolution
Description check⚠️ WarningThe PR description is incomplete with all template sections left blank or unchecked, including Issue Number, Type of change selection, testing details, and all checklist items.Complete the PR description by filling in the Issue Number, selecting the applicable Type of change, documenting how changes were tested, and checking off completed checklist items.
Title check❓ InconclusiveThe title 'fix: file manager limits' is vague and does not clearly describe the main changes, which include batch file upload support, normalization improvements, and multiple API enhancements.Consider using a more specific title that reflects the primary change, such as 'feat: add batch file upload support and storage limits validation' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @platforms/file-manager-api/src/controllers/FileController.ts:
- Around line 10-13: The uploadMultiple middleware uses multer.memoryStorage
which can OOM for large batches (e.g., 50×1GB); replace multer.memoryStorage()
with multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.
- Around line 153-157: Remove the unreachable duplicate authentication guard
that checks if (!req.user) and returns res.status(401).json({ error:
"Authentication required" }) inside the same request handler; keep the original
early-return check (the one at the top of the handler) and delete the later
redundant block so authentication is only validated once per request in this
controller method.
🧹 Nitpick comments (5)
platforms/file-manager-api/src/controllers/FileController.ts (5)

5-13: Consolidate duplicate multer configurations.

Both upload and uploadMultiple have identical configuration (1GB limit, memoryStorage). A single multer instance can handle both single and multiple file uploads.

♻️ Proposed consolidation
-const upload = multer({- limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit- storage: multer.memoryStorage(),-});--const uploadMultiple = multer({+const upload = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Then use upload.single("file") and upload.array("files", 50) throughout.


36-44: Remove redundant file size check.

Multer already enforces the 1GB limit at configuration (line 6), so this manual check is unreachable. If a file exceeds 1GB, multer will reject it before reaching this code.

♻️ Proposed fix
- // Check file size limit (1GB)- const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes- if (req.file.size > MAX_FILE_SIZE) {- return res.status(413).json({- error: "File size exceeds 1GB limit",- maxSize: MAX_FILE_SIZE,- fileSize: req.file.size,- });- }-

62-68: Extract folderId normalization to a helper method.

This normalization logic is duplicated across at least 5 handlers (uploadFile, uploadFiles, updateFile, getFiles, moveFile). Extract it to reduce duplication and ensure consistency.

♻️ Proposed helper method

Add this private helper to the FileController class:

privatenormalizeFolderId(folderId: any): string|null{returnfolderId==="null"||folderId===""||folderId===null||folderId===undefined
? null
: folderId;}

Then replace all occurrences with:

- const normalizedFolderId =- folderId === "null" ||- folderId === "" ||- folderId === null ||- folderId === undefined- ? null- : folderId;+ const normalizedFolderId = this.normalizeFolderId(folderId);

251-273: Consider extracting signature mapping to reduce duplication.

The signature mapping logic (including user details) is duplicated in getFile (lines 315-331) and getFileSignatures (lines 500-517). Consider extracting to a private helper method.

♻️ Example helper method
privatemapSignature(sig: any){return{id: sig.id,userId: sig.userId,user: sig.user
? {id: sig.user.id,name: sig.user.name,ename: sig.user.ename,avatarUrl: sig.user.avatarUrl,}
: null,md5Hash: sig.md5Hash,signature: sig.signature,publicKey: sig.publicKey,message: sig.message,createdAt: sig.createdAt,};}

81-91: Response shape inconsistency across endpoints.

The uploadFile response doesn't include owner or canPreview fields that are returned by getFiles (lines 261-271) and getFile (lines 302-332). Consider standardizing response shapes for consistency, unless this omission is intentional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0144c4d and 3a079ff.

⛔ Files ignored due to path filters (4)
  • platforms/esigner/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/esigner/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
📒 Files selected for processing (2)
  • platforms/file-manager-api/src/controllers/FileController.ts
  • platforms/file-manager/src/routes/(protected)/files/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
platforms/file-manager-api/src/controllers/FileController.ts (4)

181-190: Batch upload doesn't support per-file displayName and description.

Unlike uploadFile (line 59), the batch upload handler hardcodes displayName and description as undefined. This means all uploaded files will have null metadata. Consider whether this is intentional or if you want to support per-file metadata via a different mechanism (e.g., parallel JSON array in the request body).


159-217: Verify partial upload behavior is intentional.

The batch upload processes files sequentially and returns both successful uploads and errors. If some files fail, the successfully uploaded files remain in storage (no rollback). Verify this partial-success pattern aligns with your requirements, as users may expect an all-or-nothing transaction.


412-418: LGTM: Proper Content-Disposition headers for download vs preview.

The distinction between attachment for downloads and inline for previews is correct and follows HTTP best practices.

Also applies to: 446-451


483-523: LGTM: File signatures endpoint properly secured.

The new getFileSignatures endpoint includes proper authentication checks and verifies file access before returning signature data. The response mapping includes user details consistently with other endpoints.

Comment on lines +10 to 13
const uploadMultiple = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory storage risk with large batch uploads.

Using memoryStorage with 50 files × 1GB max = potential 50GB memory consumption. This can crash the Node.js process with out-of-memory errors. Consider using diskStorage for temporary file storage or streaming directly to your storage backend.

Also applies to: 103-103

🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines 10
- 13, The uploadMultiple middleware uses multer.memoryStorage which can OOM for
large batches (e.g., 50×1GB); replace multer.memoryStorage() with
multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.

Comment on lines +118 to +119
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential storage quota race condition with concurrent uploads.

The storage quota is fetched once at the beginning (line 118-119), and while currentUsed is tracked locally within the batch (line 192), there's no protection against concurrent upload requests from the same user. If multiple batches are uploaded simultaneously, each will check against the same initial quota, potentially exceeding the limit.

Consider implementing database-level constraints or locks to ensure quota enforcement across concurrent requests.

Also applies to: 172-179

Comment on lines +153 to +157
if (!req.user) {
return res
.status(401)
.json({ error: "Authentication required" });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate authentication check.

This authentication check is unreachable dead code. The same check already exists at lines 111-115 and would have returned early if req.user is not present.

🔧 Proposed fix
 const results: UploadResult[] = [];
const errors: UploadError[] = [];
let currentUsed = used;
- if (!req.user) {- return res- .status(401)- .json({ error: "Authentication required" });- }-
for (const file of files) {
📝 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.

Suggested change
if(!req.user){
returnres
.status(401)
.json({error: "Authentication required"});
}
constresults: UploadResult[]=[];
consterrors: UploadError[]=[];
letcurrentUsed=used;
for(constfileoffiles){
🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines
153 - 157, Remove the unreachable duplicate authentication guard that checks if
(!req.user) and returns res.status(401).json({ error: "Authentication required"
}) inside the same request handler; keep the original early-return check (the
one at the top of the handler) and delete the later redundant block so
authentication is only validated once per request in this controller method.

@coodos
coodos merged commit 84abd62 into mainJan 11, 2026
4 checks passed
This was referenced Mar 15, 2026
Sign up for freeto 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.

2 participants

@sosweetham@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: file manager limits - #663

Merged
coodos merged 1 commit into
mainfrom
fix/file-manager-limits
Jan 11, 2026
Merged

fix: file manager limits#663
coodos merged 1 commit into
mainfrom
fix/file-manager-limits

Conversation

@sosweetham

@sosweethamsosweetham commented Jan 9, 2026

Copy link
Copy Markdown
Member

Description of change

Issue Number

Type of change

  • Breaking (any change that would cause existing functionality to not work as expected)
  • New (a change which implements a new feature)
  • Update (a change which updates existing functionality)
  • Fix (a change which fixes an issue)
  • Docs (changes to the documentation)
  • Chore (refactoring, build scripts or anything else that isn't user-facing)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Batch file upload: Upload multiple files simultaneously with per-file validation, quota enforcement, and comprehensive error reporting.
  • Bug Fixes & Improvements

    • Enhanced file validation with consistent size limits (1GB per file) and quota checks.
    • Refined error messaging for improved clarity.
    • Standardized API response structures and authentication handling across file operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitaiBot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added batch file upload handler supporting up to 50 files with per-file validation and error aggregation. Enhanced folderId normalization, standardized response shapes across endpoints to include owner/signatures/canPreview fields, exposed getFileSignatures endpoint, and refined error handling consistency.

Changes

Cohort / File(s)Summary
Batch Upload Handler
platforms/file-manager-api/src/controllers/FileController.ts
New uploadFiles method supporting array upload (max 50 files) with per-file validation (1GB limit, quota enforcement), service-level file creation, and aggregated response with per-file error tracking
Single Upload & Existing Flow
platforms/file-manager-api/src/controllers/FileController.ts
Updated existing single-file upload with refined max file size messaging and consistent folderId normalization; authentication and quota error handling paths preserved
Endpoint Normalization & Consistency
platforms/file-manager-api/src/controllers/FileController.ts
FolderId normalization across multiple endpoints treating "null" and empty strings as null; standardized content-type and disposition headers in download/preview responses; refactored response shapes for consistent owner, signatures, and canPreview field inclusion
Public API & Error Handling
platforms/file-manager-api/src/controllers/FileController.ts
Exposed getFileSignatures endpoint with nested user details mapping; updated error paths for consistent 401 and 404 responses; import type annotations for Request/Response; formatting and string literal adjustments

Sequence Diagram

sequenceDiagram
actor Client
participant FileController
participant FileService
participant StorageSystem
participant QuotaManager
Client->>FileController: POST /uploadFiles (50 files)
FileController->>FileController: Parse & validate array
loop For each file
FileController->>FileController: Validate file size (≤1GB)
FileController->>QuotaManager: Check user quota
alt Quota exceeded
FileController-->>FileController: Add per-file error
else Quota available
FileController->>FileService: Create file record
FileService->>StorageSystem: Store file
StorageSystem-->>FileService: Return file metadata
FileService-->>FileController: File created
FileController-->>FileController: Add to success results
end
end
FileController-->>Client: Return aggregated response (successes + errors)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop, hop, uploading in a batch today,
Fifty files can have their say,
Signatures aligned, responses gleam,
Validation flows like a coding dream! ✨📁

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check nameStatusExplanationResolution
Description check⚠️ WarningThe PR description is incomplete with all template sections left blank or unchecked, including Issue Number, Type of change selection, testing details, and all checklist items.Complete the PR description by filling in the Issue Number, selecting the applicable Type of change, documenting how changes were tested, and checking off completed checklist items.
Title check❓ InconclusiveThe title 'fix: file manager limits' is vague and does not clearly describe the main changes, which include batch file upload support, normalization improvements, and multiple API enhancements.Consider using a more specific title that reflects the primary change, such as 'feat: add batch file upload support and storage limits validation' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @platforms/file-manager-api/src/controllers/FileController.ts:
- Around line 10-13: The uploadMultiple middleware uses multer.memoryStorage
which can OOM for large batches (e.g., 50×1GB); replace multer.memoryStorage()
with multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.
- Around line 153-157: Remove the unreachable duplicate authentication guard
that checks if (!req.user) and returns res.status(401).json({ error:
"Authentication required" }) inside the same request handler; keep the original
early-return check (the one at the top of the handler) and delete the later
redundant block so authentication is only validated once per request in this
controller method.
🧹 Nitpick comments (5)
platforms/file-manager-api/src/controllers/FileController.ts (5)

5-13: Consolidate duplicate multer configurations.

Both upload and uploadMultiple have identical configuration (1GB limit, memoryStorage). A single multer instance can handle both single and multiple file uploads.

♻️ Proposed consolidation
-const upload = multer({- limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit- storage: multer.memoryStorage(),-});--const uploadMultiple = multer({+const upload = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Then use upload.single("file") and upload.array("files", 50) throughout.


36-44: Remove redundant file size check.

Multer already enforces the 1GB limit at configuration (line 6), so this manual check is unreachable. If a file exceeds 1GB, multer will reject it before reaching this code.

♻️ Proposed fix
- // Check file size limit (1GB)- const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes- if (req.file.size > MAX_FILE_SIZE) {- return res.status(413).json({- error: "File size exceeds 1GB limit",- maxSize: MAX_FILE_SIZE,- fileSize: req.file.size,- });- }-

62-68: Extract folderId normalization to a helper method.

This normalization logic is duplicated across at least 5 handlers (uploadFile, uploadFiles, updateFile, getFiles, moveFile). Extract it to reduce duplication and ensure consistency.

♻️ Proposed helper method

Add this private helper to the FileController class:

privatenormalizeFolderId(folderId: any): string|null{returnfolderId==="null"||folderId===""||folderId===null||folderId===undefined
? null
: folderId;}

Then replace all occurrences with:

- const normalizedFolderId =- folderId === "null" ||- folderId === "" ||- folderId === null ||- folderId === undefined- ? null- : folderId;+ const normalizedFolderId = this.normalizeFolderId(folderId);

251-273: Consider extracting signature mapping to reduce duplication.

The signature mapping logic (including user details) is duplicated in getFile (lines 315-331) and getFileSignatures (lines 500-517). Consider extracting to a private helper method.

♻️ Example helper method
privatemapSignature(sig: any){return{id: sig.id,userId: sig.userId,user: sig.user
? {id: sig.user.id,name: sig.user.name,ename: sig.user.ename,avatarUrl: sig.user.avatarUrl,}
: null,md5Hash: sig.md5Hash,signature: sig.signature,publicKey: sig.publicKey,message: sig.message,createdAt: sig.createdAt,};}

81-91: Response shape inconsistency across endpoints.

The uploadFile response doesn't include owner or canPreview fields that are returned by getFiles (lines 261-271) and getFile (lines 302-332). Consider standardizing response shapes for consistency, unless this omission is intentional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0144c4d and 3a079ff.

⛔ Files ignored due to path filters (4)
  • platforms/esigner/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/esigner/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
📒 Files selected for processing (2)
  • platforms/file-manager-api/src/controllers/FileController.ts
  • platforms/file-manager/src/routes/(protected)/files/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
platforms/file-manager-api/src/controllers/FileController.ts (4)

181-190: Batch upload doesn't support per-file displayName and description.

Unlike uploadFile (line 59), the batch upload handler hardcodes displayName and description as undefined. This means all uploaded files will have null metadata. Consider whether this is intentional or if you want to support per-file metadata via a different mechanism (e.g., parallel JSON array in the request body).


159-217: Verify partial upload behavior is intentional.

The batch upload processes files sequentially and returns both successful uploads and errors. If some files fail, the successfully uploaded files remain in storage (no rollback). Verify this partial-success pattern aligns with your requirements, as users may expect an all-or-nothing transaction.


412-418: LGTM: Proper Content-Disposition headers for download vs preview.

The distinction between attachment for downloads and inline for previews is correct and follows HTTP best practices.

Also applies to: 446-451


483-523: LGTM: File signatures endpoint properly secured.

The new getFileSignatures endpoint includes proper authentication checks and verifies file access before returning signature data. The response mapping includes user details consistently with other endpoints.

Comment on lines +10 to 13
const uploadMultiple = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory storage risk with large batch uploads.

Using memoryStorage with 50 files × 1GB max = potential 50GB memory consumption. This can crash the Node.js process with out-of-memory errors. Consider using diskStorage for temporary file storage or streaming directly to your storage backend.

Also applies to: 103-103

🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines 10
- 13, The uploadMultiple middleware uses multer.memoryStorage which can OOM for
large batches (e.g., 50×1GB); replace multer.memoryStorage() with
multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.

Comment on lines +118 to +119
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential storage quota race condition with concurrent uploads.

The storage quota is fetched once at the beginning (line 118-119), and while currentUsed is tracked locally within the batch (line 192), there's no protection against concurrent upload requests from the same user. If multiple batches are uploaded simultaneously, each will check against the same initial quota, potentially exceeding the limit.

Consider implementing database-level constraints or locks to ensure quota enforcement across concurrent requests.

Also applies to: 172-179

Comment on lines +153 to +157
if (!req.user) {
return res
.status(401)
.json({ error: "Authentication required" });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate authentication check.

This authentication check is unreachable dead code. The same check already exists at lines 111-115 and would have returned early if req.user is not present.

🔧 Proposed fix
 const results: UploadResult[] = [];
const errors: UploadError[] = [];
let currentUsed = used;
- if (!req.user) {- return res- .status(401)- .json({ error: "Authentication required" });- }-
for (const file of files) {
📝 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.

Suggested change
if(!req.user){
returnres
.status(401)
.json({error: "Authentication required"});
}
constresults: UploadResult[]=[];
consterrors: UploadError[]=[];
letcurrentUsed=used;
for(constfileoffiles){
🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines
153 - 157, Remove the unreachable duplicate authentication guard that checks if
(!req.user) and returns res.status(401).json({ error: "Authentication required"
}) inside the same request handler; keep the original early-return check (the
one at the top of the handler) and delete the later redundant block so
authentication is only validated once per request in this controller method.

@coodos
coodos merged commit 84abd62 into mainJan 11, 2026
4 checks passed
This was referenced Mar 15, 2026
Sign up for freeto 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.

2 participants

@sosweetham@coodos
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix: file manager limits - #663

Merged
coodos merged 1 commit into
mainfrom
fix/file-manager-limits
Jan 11, 2026
Merged

fix: file manager limits#663
coodos merged 1 commit into
mainfrom
fix/file-manager-limits

Conversation

@sosweetham

@sosweethamsosweetham commented Jan 9, 2026

Copy link
Copy Markdown
Member

Description of change

Issue Number

Type of change

  • Breaking (any change that would cause existing functionality to not work as expected)
  • New (a change which implements a new feature)
  • Update (a change which updates existing functionality)
  • Fix (a change which fixes an issue)
  • Docs (changes to the documentation)
  • Chore (refactoring, build scripts or anything else that isn't user-facing)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Batch file upload: Upload multiple files simultaneously with per-file validation, quota enforcement, and comprehensive error reporting.
  • Bug Fixes & Improvements

    • Enhanced file validation with consistent size limits (1GB per file) and quota checks.
    • Refined error messaging for improved clarity.
    • Standardized API response structures and authentication handling across file operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitaiBot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added batch file upload handler supporting up to 50 files with per-file validation and error aggregation. Enhanced folderId normalization, standardized response shapes across endpoints to include owner/signatures/canPreview fields, exposed getFileSignatures endpoint, and refined error handling consistency.

Changes

Cohort / File(s)Summary
Batch Upload Handler
platforms/file-manager-api/src/controllers/FileController.ts
New uploadFiles method supporting array upload (max 50 files) with per-file validation (1GB limit, quota enforcement), service-level file creation, and aggregated response with per-file error tracking
Single Upload & Existing Flow
platforms/file-manager-api/src/controllers/FileController.ts
Updated existing single-file upload with refined max file size messaging and consistent folderId normalization; authentication and quota error handling paths preserved
Endpoint Normalization & Consistency
platforms/file-manager-api/src/controllers/FileController.ts
FolderId normalization across multiple endpoints treating "null" and empty strings as null; standardized content-type and disposition headers in download/preview responses; refactored response shapes for consistent owner, signatures, and canPreview field inclusion
Public API & Error Handling
platforms/file-manager-api/src/controllers/FileController.ts
Exposed getFileSignatures endpoint with nested user details mapping; updated error paths for consistent 401 and 404 responses; import type annotations for Request/Response; formatting and string literal adjustments

Sequence Diagram

sequenceDiagram
actor Client
participant FileController
participant FileService
participant StorageSystem
participant QuotaManager
Client->>FileController: POST /uploadFiles (50 files)
FileController->>FileController: Parse & validate array
loop For each file
FileController->>FileController: Validate file size (≤1GB)
FileController->>QuotaManager: Check user quota
alt Quota exceeded
FileController-->>FileController: Add per-file error
else Quota available
FileController->>FileService: Create file record
FileService->>StorageSystem: Store file
StorageSystem-->>FileService: Return file metadata
FileService-->>FileController: File created
FileController-->>FileController: Add to success results
end
end
FileController-->>Client: Return aggregated response (successes + errors)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop, hop, uploading in a batch today,
Fifty files can have their say,
Signatures aligned, responses gleam,
Validation flows like a coding dream! ✨📁

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check nameStatusExplanationResolution
Description check⚠️ WarningThe PR description is incomplete with all template sections left blank or unchecked, including Issue Number, Type of change selection, testing details, and all checklist items.Complete the PR description by filling in the Issue Number, selecting the applicable Type of change, documenting how changes were tested, and checking off completed checklist items.
Title check❓ InconclusiveThe title 'fix: file manager limits' is vague and does not clearly describe the main changes, which include batch file upload support, normalization improvements, and multiple API enhancements.Consider using a more specific title that reflects the primary change, such as 'feat: add batch file upload support and storage limits validation' to better convey the scope of changes.
✅ Passed checks (1 passed)
Check nameStatusExplanation
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @platforms/file-manager-api/src/controllers/FileController.ts:
- Around line 10-13: The uploadMultiple middleware uses multer.memoryStorage
which can OOM for large batches (e.g., 50×1GB); replace multer.memoryStorage()
with multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.
- Around line 153-157: Remove the unreachable duplicate authentication guard
that checks if (!req.user) and returns res.status(401).json({ error:
"Authentication required" }) inside the same request handler; keep the original
early-return check (the one at the top of the handler) and delete the later
redundant block so authentication is only validated once per request in this
controller method.
🧹 Nitpick comments (5)
platforms/file-manager-api/src/controllers/FileController.ts (5)

5-13: Consolidate duplicate multer configurations.

Both upload and uploadMultiple have identical configuration (1GB limit, memoryStorage). A single multer instance can handle both single and multiple file uploads.

♻️ Proposed consolidation
-const upload = multer({- limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit- storage: multer.memoryStorage(),-});--const uploadMultiple = multer({+const upload = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Then use upload.single("file") and upload.array("files", 50) throughout.


36-44: Remove redundant file size check.

Multer already enforces the 1GB limit at configuration (line 6), so this manual check is unreachable. If a file exceeds 1GB, multer will reject it before reaching this code.

♻️ Proposed fix
- // Check file size limit (1GB)- const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes- if (req.file.size > MAX_FILE_SIZE) {- return res.status(413).json({- error: "File size exceeds 1GB limit",- maxSize: MAX_FILE_SIZE,- fileSize: req.file.size,- });- }-

62-68: Extract folderId normalization to a helper method.

This normalization logic is duplicated across at least 5 handlers (uploadFile, uploadFiles, updateFile, getFiles, moveFile). Extract it to reduce duplication and ensure consistency.

♻️ Proposed helper method

Add this private helper to the FileController class:

privatenormalizeFolderId(folderId: any): string|null{returnfolderId==="null"||folderId===""||folderId===null||folderId===undefined
? null
: folderId;}

Then replace all occurrences with:

- const normalizedFolderId =- folderId === "null" ||- folderId === "" ||- folderId === null ||- folderId === undefined- ? null- : folderId;+ const normalizedFolderId = this.normalizeFolderId(folderId);

251-273: Consider extracting signature mapping to reduce duplication.

The signature mapping logic (including user details) is duplicated in getFile (lines 315-331) and getFileSignatures (lines 500-517). Consider extracting to a private helper method.

♻️ Example helper method
privatemapSignature(sig: any){return{id: sig.id,userId: sig.userId,user: sig.user
? {id: sig.user.id,name: sig.user.name,ename: sig.user.ename,avatarUrl: sig.user.avatarUrl,}
: null,md5Hash: sig.md5Hash,signature: sig.signature,publicKey: sig.publicKey,message: sig.message,createdAt: sig.createdAt,};}

81-91: Response shape inconsistency across endpoints.

The uploadFile response doesn't include owner or canPreview fields that are returned by getFiles (lines 261-271) and getFile (lines 302-332). Consider standardizing response shapes for consistency, unless this omission is intentional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0144c4d and 3a079ff.

⛔ Files ignored due to path filters (4)
  • platforms/esigner/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/esigner/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/ambient.d.ts is excluded by !**/.svelte-kit/**
  • platforms/file-manager/.svelte-kit/non-ambient.d.ts is excluded by !**/.svelte-kit/**
📒 Files selected for processing (2)
  • platforms/file-manager-api/src/controllers/FileController.ts
  • platforms/file-manager/src/routes/(protected)/files/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
platforms/file-manager-api/src/controllers/FileController.ts (4)

181-190: Batch upload doesn't support per-file displayName and description.

Unlike uploadFile (line 59), the batch upload handler hardcodes displayName and description as undefined. This means all uploaded files will have null metadata. Consider whether this is intentional or if you want to support per-file metadata via a different mechanism (e.g., parallel JSON array in the request body).


159-217: Verify partial upload behavior is intentional.

The batch upload processes files sequentially and returns both successful uploads and errors. If some files fail, the successfully uploaded files remain in storage (no rollback). Verify this partial-success pattern aligns with your requirements, as users may expect an all-or-nothing transaction.


412-418: LGTM: Proper Content-Disposition headers for download vs preview.

The distinction between attachment for downloads and inline for previews is correct and follows HTTP best practices.

Also applies to: 446-451


483-523: LGTM: File signatures endpoint properly secured.

The new getFileSignatures endpoint includes proper authentication checks and verifies file access before returning signature data. The response mapping includes user details consistently with other endpoints.

Comment on lines +10 to 13
const uploadMultiple = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Memory storage risk with large batch uploads.

Using memoryStorage with 50 files × 1GB max = potential 50GB memory consumption. This can crash the Node.js process with out-of-memory errors. Consider using diskStorage for temporary file storage or streaming directly to your storage backend.

Also applies to: 103-103

🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines 10
- 13, The uploadMultiple middleware uses multer.memoryStorage which can OOM for
large batches (e.g., 50×1GB); replace multer.memoryStorage() with
multer.diskStorage configured to write to a temporary directory (e.g.,
os.tmpdir()) or change to a streaming approach that pipes uploads directly to
your storage backend, and add stricter multer limits (limits: { files:
<reasonable_max>, fileSize: <per_file_limit> }) and ensure uploaded temp files
are cleaned up after processing; update the same upload middleware usage
elsewhere (uploadMultiple) to match.

Comment on lines +118 to +119
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential storage quota race condition with concurrent uploads.

The storage quota is fetched once at the beginning (line 118-119), and while currentUsed is tracked locally within the batch (line 192), there's no protection against concurrent upload requests from the same user. If multiple batches are uploaded simultaneously, each will check against the same initial quota, potentially exceeding the limit.

Consider implementing database-level constraints or locks to ensure quota enforcement across concurrent requests.

Also applies to: 172-179

Comment on lines +153 to +157
if (!req.user) {
return res
.status(401)
.json({ error: "Authentication required" });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate authentication check.

This authentication check is unreachable dead code. The same check already exists at lines 111-115 and would have returned early if req.user is not present.

🔧 Proposed fix
 const results: UploadResult[] = [];
const errors: UploadError[] = [];
let currentUsed = used;
- if (!req.user) {- return res- .status(401)- .json({ error: "Authentication required" });- }-
for (const file of files) {
📝 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.

Suggested change
if(!req.user){
returnres
.status(401)
.json({error: "Authentication required"});
}
constresults: UploadResult[]=[];
consterrors: UploadError[]=[];
letcurrentUsed=used;
for(constfileoffiles){
🤖 Prompt for AI Agents
In @platforms/file-manager-api/src/controllers/FileController.ts around lines
153 - 157, Remove the unreachable duplicate authentication guard that checks if
(!req.user) and returns res.status(401).json({ error: "Authentication required"
}) inside the same request handler; keep the original early-return check (the
one at the top of the handler) and delete the later redundant block so
authentication is only validated once per request in this controller method.

@coodos
coodos merged commit 84abd62 into mainJan 11, 2026
4 checks passed
This was referenced Mar 15, 2026
Sign up for freeto 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.

2 participants

@sosweetham@coodos