Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions platforms/file-manager/api/src/controllers/FileController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ import os from "os";
import { FileService } from "../services/FileService";

const upload = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

const uploadMultiple = multer({
limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit
storage: multer.memoryStorage(),
});

Expand Down Expand Up @@ -43,19 +41,19 @@ export class FileController {
.json({ error: "Authentication required" });
}

// Check file size limit (1GB)
const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes
if (req.file.size > MAX_FILE_SIZE) {
// Check user's storage quota
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

// Check individual file size against user's limit
if (req.file.size > limit) {
return res.status(413).json({
error: "File size exceeds 1GB limit",
maxSize: MAX_FILE_SIZE,
error: `File size exceeds ${Math.round(limit / (1024 * 1024 * 1024))}GB limit`,
maxSize: limit,
fileSize: req.file.size,
});
}

// Check user's storage quota (1GB total)
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);
if (used + req.file.size > limit) {
return res.status(413).json({
error: "Storage quota exceeded",
Expand Down Expand Up @@ -124,7 +122,6 @@ export class FileController {
.json({ error: "Authentication required" });
}

const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes
const { used, limit } =
await this.fileService.getUserStorageUsage(req.user.id);

Expand Down Expand Up @@ -169,10 +166,10 @@ export class FileController {
for (const file of files) {
try {
// Check file size limit
if (file.size > MAX_FILE_SIZE) {
if (file.size > limit) {
errors.push({
fileName: file.originalname,
error: "File size exceeds 1GB limit",
error: `File size exceeds ${Math.round(limit / (1024 * 1024 * 1024))}GB limit`,
fileSize: file.size,
});
continue;
Expand Down
3 changes: 3 additions & 0 deletions platforms/file-manager/api/src/database/entities/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,8 @@ export class User {

@Column({ default: false })
isArchived!: boolean;

@Column({ type: "int", default: 1 })
size!: number;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class AddUserSize1773609001333 implements MigrationInterface {
name = 'AddUserSize1773609001333'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users" ADD "size" integer NOT NULL DEFAULT 1`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "size"`);
}

}
10 changes: 9 additions & 1 deletion platforms/file-manager/api/src/services/FileService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Folder } from "../database/entities/Folder";
import { FileAccess } from "../database/entities/FileAccess";
import { FolderAccess } from "../database/entities/FolderAccess";
import { SignatureContainer } from "../database/entities/SignatureContainer";
import { User } from "../database/entities/User";
import { In, IsNull, Not } from "typeorm";
import crypto from "crypto";
import { Readable } from "stream";
Expand All @@ -16,6 +17,7 @@ export class FileService {
private fileAccessRepository = AppDataSource.getRepository(FileAccess);
private folderRepository = AppDataSource.getRepository(Folder);
private signatureRepository = AppDataSource.getRepository(SignatureContainer);
private userRepository = AppDataSource.getRepository(User);

async calculateMD5(buffer: Buffer): Promise<string> {
return crypto.createHash('md5').update(buffer).digest('hex');
Expand Down Expand Up @@ -355,7 +357,13 @@ export class FileService {
const folderSize = folderCount * FOLDER_SIZE;

const used = fileSize + folderSize;
const limit = 1073741824; // 1GB in bytes

const user = await this.userRepository.findOne({
where: { id: userId },
select: ["size"],
});
const sizeInGB = user?.size ?? 1;
const limit = sizeInGB * 1024 * 1024 * 1024;

return { used, limit, fileCount, folderCount };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,21 +230,7 @@
async function handleFileUpload(filesToUpload: globalThis.File[]) {
if (filesToUpload.length === 0) return;

// Client-side validation
const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB
const validFiles: globalThis.File[] = [];

for (const file of filesToUpload) {
if (file.size > MAX_FILE_SIZE) {
toast.error(
`File "${file.name}" exceeds 1GB limit. Your file is ${(file.size / 1024 / 1024).toFixed(2)}MB`,
);
} else {
validFiles.push(file);
}
}

if (validFiles.length === 0) return;
const validFiles = filesToUpload;

isUploading = true;
uploadProgress = {};
Expand Down Expand Up @@ -308,7 +294,7 @@
);
} else {
toast.error(
`File "${file.name}" size exceeds 1GB limit`,
`File "${file.name}" exceeds the size limit`,
);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@
<div class="flex-1">
<h4 class="text-sm font-semibold text-blue-900 mb-1">Storage Information</h4>
<ul class="text-sm text-blue-700 space-y-1">
<li>• Maximum file size: 5 MB per file</li>
<li>• Total storage quota: 1 GB</li>
<li>• Maximum file size: {formatBytes(limit)} per file</li>
<li>• Total storage quota: {formatBytes(limit)}</li>
<li>• Each folder counts as 4 KB</li>
<li>• Deleted files are permanently removed and cannot be recovered</li>
</ul>
Expand Down
Loading