Skip to content
This repository was archived by the owner on Feb 27, 2026. It is now read-only.

Commit 37a30f1

Browse files
v2.0.0-beta.2 (#28)
2 parents a8c53af + d7bdffe commit 37a30f1

24 files changed

Lines changed: 357 additions & 35 deletions

File tree

apps/server/src/modules/file/controller.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { prisma } from "../../shared/prisma";
22
import { ConfigService } from "../config/service";
3-
import { RegisterFileSchema, RegisterFileInput, UpdateFileSchema } from "./dto";
3+
import { RegisterFileSchema, RegisterFileInput, UpdateFileSchema, CheckFileInput, CheckFileSchema } from "./dto";
44
import { FileService } from "./service";
55
import { FastifyReply, FastifyRequest } from "fastify";
66

@@ -103,6 +103,56 @@ export class FileController {
103103
}
104104
}
105105

106+
async checkFile(request: FastifyRequest, reply: FastifyReply) {
107+
try {
108+
await request.jwtVerify();
109+
const userId = (request as any).user?.userId;
110+
if (!userId) {
111+
return reply.status(401).send({
112+
error: "Unauthorized: a valid token is required to access this resource.",
113+
code: "unauthorized"
114+
});
115+
}
116+
117+
const input: CheckFileInput = CheckFileSchema.parse(request.body);
118+
119+
const maxFileSize = BigInt(await this.configService.getValue("maxFileSize"));
120+
if (BigInt(input.size) > maxFileSize) {
121+
const maxSizeMB = Number(maxFileSize) / (1024 * 1024);
122+
return reply.status(400).send({
123+
code: "fileSizeExceeded",
124+
error: `File size exceeds the maximum allowed size of ${maxSizeMB}MB`,
125+
details: maxSizeMB.toString(),
126+
});
127+
}
128+
129+
const maxTotalStorage = BigInt(await this.configService.getValue("maxTotalStoragePerUser"));
130+
131+
const userFiles = await prisma.file.findMany({
132+
where: { userId },
133+
select: { size: true },
134+
});
135+
136+
const currentStorage = userFiles.reduce((acc, file) => acc + file.size, BigInt(0));
137+
138+
if (currentStorage + BigInt(input.size) > maxTotalStorage) {
139+
const availableSpace = Number(maxTotalStorage - currentStorage) / (1024 * 1024);
140+
return reply.status(400).send({
141+
error: `Insufficient storage space. You have ${availableSpace.toFixed(2)}MB available`,
142+
code: "insufficientStorage",
143+
details: availableSpace.toFixed(2),
144+
});
145+
}
146+
147+
return reply.status(201).send({
148+
message: "File checks succeeded.",
149+
});
150+
} catch (error: any) {
151+
console.error("Error in checkFile:", error);
152+
return reply.status(400).send({ error: error.message });
153+
}
154+
}
155+
106156
async getDownloadUrl(request: FastifyRequest, reply: FastifyReply) {
107157
try {
108158
const { objectName: encodedObjectName } = request.params as {

apps/server/src/modules/file/dto.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,19 @@ export const RegisterFileSchema = z.object({
1111
objectName: z.string().min(1, "O objectName é obrigatório"),
1212
});
1313

14+
export const CheckFileSchema = z.object({
15+
name: z.string().min(1, "O nome do arquivo é obrigatório"),
16+
description: z.string().optional(),
17+
extension: z.string().min(1, "A extensão é obrigatória"),
18+
size: z.number({
19+
required_error: "O tamanho é obrigatório",
20+
invalid_type_error: "O tamanho deve ser um número",
21+
}),
22+
objectName: z.string().min(1, "O objectName é obrigatório"),
23+
});
24+
1425
export type RegisterFileInput = z.infer<typeof RegisterFileSchema>;
26+
export type CheckFileInput = z.infer<typeof CheckFileSchema>;
1527

1628
export const UpdateFileSchema = z.object({
1729
name: z.string().optional().describe("The file name"),

apps/server/src/modules/file/routes.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FileController } from "./controller";
2-
import { RegisterFileSchema, UpdateFileSchema } from "./dto";
2+
import { CheckFileSchema, RegisterFileSchema, UpdateFileSchema } from "./dto";
33
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
44
import { z } from "zod";
55

@@ -73,6 +73,33 @@ export async function fileRoutes(app: FastifyInstance) {
7373
},
7474
fileController.registerFile.bind(fileController)
7575
);
76+
app.post(
77+
"/files/check",
78+
{
79+
schema: {
80+
tags: ["File"],
81+
operationId: "checkFile",
82+
summary: "Check File validity",
83+
description: "Checks if the file meets all requirements",
84+
body: CheckFileSchema,
85+
response: {
86+
201: z.object({
87+
message: z.string().describe("The file check success message"),
88+
}),
89+
400: z.object({
90+
error: z.string().describe("Error message"),
91+
code: z.string().optional().describe("Error code"),
92+
details: z.string().optional().describe("Error details"),
93+
}),
94+
401: z.object({
95+
error: z.string().describe("Error message"),
96+
code: z.string().optional().describe("Error code"),
97+
}),
98+
},
99+
},
100+
},
101+
fileController.checkFile.bind(fileController)
102+
);
76103

77104
app.get(
78105
"/files/:objectName/download",

apps/web/messages/ar-SA.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@
266266
"lastNameRequired": "اسم العائلة مطلوب",
267267
"usernameMinLength": "يجب أن يحتوي اسم المستخدم على 3 أحرف على الأقل",
268268
"invalidEmail": "البريد الإلكتروني غير صالح",
269-
"passwordMinLength": "يجب أن تحتوي كلمة المرور على 6 أحرف على الأقل"
269+
"passwordMinLength": "يجب أن تحتوي كلمة المرور على 8 أحرف على الأقل",
270+
"success": "تم إنشاء مستخدم المسؤول بنجاح!",
271+
"error": "خطأ في إنشاء مستخدم المسؤول"
270272
},
271273
"labels": {
272274
"firstName": "الاسم الأول",
@@ -578,7 +580,10 @@
578580
"uploadProgress": "تقدم الرفع",
579581
"upload": "رفع",
580582
"success": "تم رفع الملف بنجاح",
581-
"error": "فشل في رفع الملف"
583+
"error": "فشل في رفع الملف",
584+
"fileSizeExceeded": "حجم الملف يتجاوز الحد المسموح به وهو {{maxsizemb}} ميجابايت.",
585+
"insufficientStorage": "مساحة التخزين غير كافية. لديك {{availablespace}} ميجابايت متاحة.",
586+
"unauthorized": "غير مصرح به: مطلوب رمز مميز صالح للوصول إلى هذا المورد."
582587
},
583588
"users": {
584589
"modes": {

apps/web/messages/de-DE.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@
266266
"lastNameRequired": "Nachname ist erforderlich",
267267
"usernameMinLength": "Benutzername muss mindestens 3 Zeichen lang sein",
268268
"invalidEmail": "Ungültige E-Mail-Adresse",
269-
"passwordMinLength": "Passwort muss mindestens 6 Zeichen lang sein"
269+
"passwordMinLength": "Passwort muss mindestens 8 Zeichen lang sein",
270+
"success": "Administratorbenutzer erfolgreich erstellt!",
271+
"error": "Fehler beim Erstellen von Administratorbenutzer"
270272
},
271273
"labels": {
272274
"firstName": "Vorname",
@@ -578,7 +580,10 @@
578580
"uploadProgress": "Upload-Fortschritt",
579581
"upload": "Hochladen",
580582
"success": "Datei erfolgreich hochgeladen",
581-
"error": "Fehler beim Hochladen der Datei"
583+
"error": "Fehler beim Hochladen der Datei",
584+
"fileSizeExceeded": "Dateigröße überschreitet das limit von {maxsizemb}MB.",
585+
"insufficientStorage": "Nicht genügend Speicherplatz. Es sind {availablespace}MB verfügbar.",
586+
"unauthorized": "Nicht autorisiert: Ein gültiger Token ist erforderlich, um auf diese Ressource zuzugreifen."
582587
},
583588
"users": {
584589
"modes": {

apps/web/messages/en-US.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@
266266
"lastNameRequired": "Last name is required",
267267
"usernameMinLength": "Username must be at least 3 characters",
268268
"invalidEmail": "Invalid email",
269-
"passwordMinLength": "Password must be at least 6 characters"
269+
"passwordMinLength": "Password must be at least 8 characters",
270+
"success": "Administrator user created successfully!",
271+
"error": "Error creating administrator user"
270272
},
271273
"labels": {
272274
"firstName": "First Name",
@@ -578,7 +580,10 @@
578580
"uploadProgress": "Upload progress",
579581
"upload": "Upload",
580582
"success": "File uploaded successfully",
581-
"error": "Failed to upload file"
583+
"error": "Failed to upload file",
584+
"fileSizeExceeded": "File size exceeds the limit of {maxsizemb}MB.",
585+
"insufficientStorage": "Insufficient storage space. You have {availablespace}MB available.",
586+
"unauthorized": "Unauthorized: a valid token is required to access this resource."
582587
},
583588
"users": {
584589
"modes": {
@@ -660,4 +665,4 @@
660665
"emailRequired": "Email is required",
661666
"passwordRequired": "Password is required"
662667
}
663-
}
668+
}

apps/web/messages/es-ES.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@
266266
"lastNameRequired": "El apellido es obligatorio",
267267
"usernameMinLength": "El nombre de usuario debe tener al menos 3 caracteres",
268268
"invalidEmail": "Correo electrónico inválido",
269-
"passwordMinLength": "La contraseña debe tener al menos 6 caracteres"
269+
"passwordMinLength": "La contraseña debe tener al menos 8 caracteres",
270+
"success": "¡El usuario del administrador creado con éxito!",
271+
"error": "Error a crear usuario administrador"
270272
},
271273
"labels": {
272274
"firstName": "Nombre",
@@ -578,7 +580,10 @@
578580
"uploadProgress": "Progreso de la subida",
579581
"upload": "Subir",
580582
"success": "Archivo subido exitosamente",
581-
"error": "Error al subir el archivo"
583+
"error": "Error al subir el archivo",
584+
"fileSizeExceeded": "El tamaño del archivo excede el límite de {{maxsizemb}}MB.",
585+
"insufficientStorage": "Espacio de almacenamiento insuficiente. Tiene {{availablespace}}MB disponibles.",
586+
"unauthorized": "No autorizado: se requiere un token válido para acceder a este recurso."
582587
},
583588
"users": {
584589
"modes": {

apps/web/messages/fr-FR.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@
266266
"lastNameRequired": "Le nom est requis",
267267
"usernameMinLength": "Le nom d'utilisateur doit contenir au moins 3 caractères",
268268
"invalidEmail": "Email invalide",
269-
"passwordMinLength": "Le mot de passe doit contenir au moins 6 caractères"
269+
"passwordMinLength": "Le mot de passe doit contenir au moins 8 caractères",
270+
"success": "L'utilisateur de l'administrateur a créé avec succès!",
271+
"error": "Erreur créant l'utilisateur de l'administrateur"
270272
},
271273
"labels": {
272274
"firstName": "Prénom",
@@ -577,7 +579,10 @@
577579
"uploadProgress": "Progression de l'envoi",
578580
"upload": "Envoyer",
579581
"success": "Fichier envoyé avec succès",
580-
"error": "Échec de l'envoi du fichier"
582+
"error": "Échec de l'envoi du fichier",
583+
"fileSizeExceeded": "La taille du fichier dépasse la limite de {{maxsizemb}} Mo.",
584+
"insufficientStorage": "Espace de stockage insuffisant. Vous disposez de {{availablespace}} Mo.",
585+
"unauthorized": "Non autorisé : un jeton valide est requis pour accéder à cette ressource."
581586
},
582587
"users": {
583588
"modes": {

apps/web/messages/hi-IN.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@
266266
"lastNameRequired": "अंतिम नाम आवश्यक है",
267267
"usernameMinLength": "उपयोगकर्ता नाम कम से कम 3 अक्षर का होना चाहिए",
268268
"invalidEmail": "अमान्य ईमेल",
269-
"passwordMinLength": "पासवर्ड कम से कम 6 अक्षर का होना चाहिए"
269+
"passwordMinLength": "पासवर्ड कम से कम 8 अक्षर का होना चाहिए",
270+
"success": "व्यवस्थापक उपयोगकर्ता ने सफलतापूर्वक बनाया!",
271+
"error": "व्यवस्थापक उपयोगकर्ता बनाने में त्रुटि"
270272
},
271273
"labels": {
272274
"firstName": "पहला नाम",
@@ -578,7 +580,10 @@
578580
"uploadProgress": "अपलोड प्रगति",
579581
"upload": "अपलोड करें",
580582
"success": "फाइल सफलतापूर्वक अपलोड हुई",
581-
"error": "फाइल अपलोड करने में विफल"
583+
"error": "फाइल अपलोड करने में विफल",
584+
"fileSizeExceeded": "फ़ाइल का आकार {{maxsizemb}}MB की सीमा से अधिक है।",
585+
"insufficientStorage": "अपर्याप्त संग्रहण स्थान। आपके पास {{availablespace}}MB उपलब्ध है।",
586+
"unauthorized": "अनधिकृत: इस संसाधन तक पहुँचने के लिए एक मान्य टोकन आवश्यक है।"
582587
},
583588
"users": {
584589
"modes": {

apps/web/messages/ja-JP.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@
266266
"lastNameRequired": "姓は必須です",
267267
"usernameMinLength": "ユーザー名は3文字以上である必要があります",
268268
"invalidEmail": "無効なメールアドレスです",
269-
"passwordMinLength": "パスワードは6文字以上である必要があります"
269+
"passwordMinLength": "パスワードは8文字以上である必要があります",
270+
"success": "管理者ユーザーは正常に作成されました!",
271+
"error": "管理者ユーザーの作成エラー"
270272
},
271273
"labels": {
272274
"firstName": "",
@@ -578,7 +580,10 @@
578580
"uploadProgress": "アップロードの進行状況",
579581
"upload": "アップロード",
580582
"success": "ファイルが正常にアップロードされました",
581-
"error": "ファイルのアップロードに失敗しました"
583+
"error": "ファイルのアップロードに失敗しました",
584+
"fileSizeExceeded": "ファイルサイズが制限値 {{maxsizemb}}MB を超えています。",
585+
"insufficientStorage": "ストレージ容量が不足しています。利用可能な容量は {{availablespace}}MB です。",
586+
"unauthorized": "権限がありません: このリソースにアクセスするには有効なトークンが必要です。"
582587
},
583588
"users": {
584589
"modes": {

0 commit comments

Comments
 (0)