diff --git a/.env b/.env index c312658..9f21caf 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ # NextJS parameters NEXT_PUBLIC_ENV=development NEXT_PUBLIC_TIMEZONE=Europe/Paris -NEXT_PUBLIC_MAX_FILE_SIZE=104857600 # 1024 * 1024 * 100 = 100MB (bytes) +NEXT_PUBLIC_MAX_QUOTA=104857600 # 1024 * 1024 * 100 = 100MB (bytes) NEXT_PUBLIC_MAX_AVATAR_SIZE=5242880 # 1024 * 1024 * 5 = 5MB (bytes) NEXT_PUBLIC_ACCEPTED_FILE_TYPES=image/*, video/*, audio/* # https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept NEXT_PUBLIC_ACCEPTED_AVATAR_TYPES=image/jpeg, image/jpg, image/png, image/webp diff --git a/app/[locale]/dashboard/actions.ts b/app/[locale]/dashboard/actions.ts index 5949413..48e1bac 100644 --- a/app/[locale]/dashboard/actions.ts +++ b/app/[locale]/dashboard/actions.ts @@ -131,9 +131,23 @@ export async function uploadFiles( await mkdir( userFolder, { recursive: true } ); - // On sort après chaque fichier téléversé de la mémoire. - result.data.upload.forEach( async ( file: File ) => + // On récupère après le quota actuel et maximal de l'utilisateur. + const maxQuota = Number( process.env.NEXT_PUBLIC_MAX_QUOTA ); + let currentQuota = ( await getUserQuota() ).value; + + // On vérifie si le quota de l'utilisateur n'est pas dépassé pour + // chaque fichier à téléverser. + result.data.upload.every( async ( file ) => { + // Si le quota de l'utilisateur est dépassé, on indique + // que le téléversement a été interrompu. + currentQuota += file.size; + + if ( currentQuota > maxQuota ) + { + return false; + } + // On insère le nom du fichier et son statut dans la base de // données afin de générer un identifiant unique. const identifier = ( @@ -155,7 +169,21 @@ export async function uploadFiles( ), new Uint8Array( await file.arrayBuffer() ) ); + + // On indique par ailleurs que le téléversement s'est bien + // passé. + return true; } ); + + if ( currentQuota > maxQuota ) + { + // Si un dépassement de quota a été détecté, on affiche un + // message d'erreur dans le formulaire. + return { + success: false, + reason: "form.errors.quota_exceeded" + }; + } } catch ( error ) { diff --git a/app/[locale]/settings/components/profile.tsx b/app/[locale]/settings/components/profile.tsx index 72c3c98..f6edaca 100644 --- a/app/[locale]/settings/components/profile.tsx +++ b/app/[locale]/settings/components/profile.tsx @@ -16,6 +16,7 @@ import { useFormState } from "react-dom"; import type { Session } from "next-auth"; import { useState, useEffect } from "react"; +import { formatSize } from "@/utilities/react-table"; import { Input } from "../../components/ui/input"; import { Button } from "../../components/ui/button"; import { useToast } from "../../components/ui/use-toast"; @@ -31,6 +32,7 @@ import { updateProfile } from "../profile/actions"; export default function Profile( { session }: { session: Session } ) { // Déclaration des constantes. + const maxAvatarSize = Number( process.env.NEXT_PUBLIC_MAX_AVATAR_SIZE ?? 0 ); const { toast } = useToast(); const formState = { success: true, @@ -209,8 +211,9 @@ export default function Profile( { session }: { session: Session } ) Vous pouvez mettre à jour l‘avatar utilisé pour votre compte utilisateur.{" "} - Les avatars ne doivent pas dépasser 5 Mo et - doivent être au format PNG, JPEG ou WEBP. + Les avatars ne doivent pas dépasser{" "} + {formatSize( maxAvatarSize )} et doivent être + au format PNG, JPEG ou WEBP. diff --git a/schemas/file-upload.ts b/schemas/file-upload.ts index 73a5c02..a8cfd40 100644 --- a/schemas/file-upload.ts +++ b/schemas/file-upload.ts @@ -4,7 +4,7 @@ import { z } from "zod"; // Taille maximale d'un fichier. -const MAX_FILE_SIZE = Number( process.env.NEXT_PUBLIC_MAX_FILE_SIZE ?? "0" ); +const MAX_FILE_SIZE = Number( process.env.NEXT_PUBLIC_MAX_QUOTA ?? "0" ); // Types de fichiers acceptés. const ACCEPTED_FILE_TYPES =