From 6f9d25a58be3d099063db31f50c3838e9e763585 Mon Sep 17 00:00:00 2001 From: Mathis Date: Tue, 15 Oct 2024 16:50:33 +0200 Subject: [PATCH] Refactor and log changes in storage and file services Convert array of machine IDs to sets for uniqueness in methods. Add console logs for debugging and update error handling to improve clarity. Refactor the files controller for better readability. --- .../backend/src/app/files/files.controller.ts | 263 +++++++++--------- apps/backend/src/app/files/files.service.ts | 14 +- .../src/app/storage/storage.service.ts | 41 ++- 3 files changed, 169 insertions(+), 149 deletions(-) diff --git a/apps/backend/src/app/files/files.controller.ts b/apps/backend/src/app/files/files.controller.ts index 835dbd9..041b8c4 100644 --- a/apps/backend/src/app/files/files.controller.ts +++ b/apps/backend/src/app/files/files.controller.ts @@ -1,24 +1,24 @@ import { IncomingMessage } from "node:http"; import { - BadRequestException, - Body, - Controller, - DefaultValuePipe, - Delete, - Get, - HttpCode, - HttpStatus, - Param, - ParseIntPipe, - ParseUUIDPipe, - Post, - Query, - Req, - Request, - Res, - Response, - StreamableFile, - UseGuards, + BadRequestException, + Body, + Controller, + DefaultValuePipe, + Delete, + Get, + HttpCode, + HttpStatus, + Param, + ParseIntPipe, + ParseUUIDPipe, + Post, + Query, + Req, + Request, + Res, + Response, + StreamableFile, + UseGuards, } from "@nestjs/common"; import { CreateFileTypeDto } from "apps/backend/src/app/files/files.dto"; import { AdminGuard, InsertAdminState } from "../auth/auth.guard"; @@ -26,132 +26,133 @@ import { FilesService } from "./files.service"; @Controller("files") export class FilesController { - constructor(private readonly filesService: FilesService) { } + constructor(private readonly filesService: FilesService) {} - @HttpCode(HttpStatus.OK) - @UseGuards(InsertAdminState) - @Post("new") - async saveFile(@Req() req: IncomingMessage, @Res() res: Response) { - let fileBuffer: Buffer = Buffer.from([]); - req.on("data", (chunk: Buffer) => { - fileBuffer = Buffer.concat([fileBuffer, chunk]); - }); + @HttpCode(HttpStatus.OK) + @UseGuards(InsertAdminState) + @Post("new") + async saveFile(@Req() req: IncomingMessage, @Res() res: Response) { + let fileBuffer: Buffer = Buffer.from([]); + req.on("data", (chunk: Buffer) => { + fileBuffer = Buffer.concat([fileBuffer, chunk]); + }); - req.on("end", async () => { - try { - console.log(fileBuffer); - const _fileName = req.headers["file_name"] as string; - const _groupId = req.headers["group_id"] as string; - const _uploadedBy = req.headers["uploaded_by"] as string; - const _machineId = req.headers["machine_id"]; - const _isDocumentation = req.headers["is_documentation"] as string; - const _isRestricted = req.headers["is_restricted"] as string; - const _isAdmin = Boolean(req.headers["is_admin"] as string | boolean); - console.log( - _fileName, - _groupId, - _uploadedBy, - _machineId, - _isDocumentation, - _isRestricted, - _isAdmin, - ); + req.on("end", async () => { + try { + console.log(fileBuffer); + const _fileName = req.headers["file_name"] as string; + const _groupId = req.headers["group_id"] as string; + const _uploadedBy = req.headers["uploaded_by"] as string; + const _machineId = req.headers["machine_id"]; + const _isDocumentation = req.headers["is_documentation"] as string; + const _isRestricted = req.headers["is_restricted"] as string; + const _isAdmin = Boolean(req.headers["is_admin"] as string | boolean); + console.log( + _fileName, + _groupId, + _uploadedBy, + _machineId, + _isDocumentation, + _isRestricted, + _isAdmin, + ); - // Vérifier que les en-têtes nécessaires sont présents - if (!_fileName || !_machineId) { - throw new BadRequestException("Header(s) manquant(s)"); - } - console.log("Header found !"); - const machineId = Array(_machineId); + // Vérifier que les en-têtes nécessaires sont présents + if (!_fileName || !_machineId || !_uploadedBy) { + throw new BadRequestException("Header(s) manquant(s)"); + } + console.log("Header found !"); + const machineId = Array(_machineId); - const Params = new Map() - .set("fileName", _fileName.toString()) - .set("groupId", _groupId.toString() || null) - .set("uploadedBy", _uploadedBy.toString()) - .set("machineId", Array(JSON.parse(machineId.toString()))) - .set("isDocumentation", false) - .set("isRestricted", false); + const Params = new Map() + .set("groupId", null) + .set("fileName", _fileName.toString()) + .set("uploadedBy", String(_uploadedBy)) + .set("machineId", Array(machineId)) + .set("isDocumentation", false) + .set("isRestricted", false); - console.log("Current params :\n", Params); + if (_groupId) Params.set("groupId", String(_groupId)); - //TODO Integrate a verification if the source is an admin, if that the case then it can define isDocumentation and isRestricted else throw in case of presence of those parameters. - if (_isAdmin) { - Params.set("isDocumentation", Boolean(_isDocumentation)); - Params.set("isRestricted", Boolean(_isRestricted)); - } + console.log("Current params :\n", Params); - console.log("Executing save procedure..."); - return ( - res - // @ts-ignore - .status(HttpStatus.CREATED) - .send(await this.filesService.save(fileBuffer, Params)) - ); - } catch (err) { - console.error(err); - return ( - res - // @ts-ignore - .status(err.status || HttpStatus.INTERNAL_SERVER_ERROR) - .send(err) - ); - } - }); + //TODO Integrate a verification if the source is an admin, if that the case then it can define isDocumentation and isRestricted else throw in case of presence of those parameters. + if (_isAdmin) { + Params.set("isDocumentation", Boolean(_isDocumentation)); + Params.set("isRestricted", Boolean(_isRestricted)); + } - req.on("error", (err) => { - return ( - res - // @ts-ignore - .status(err.status || HttpStatus.INTERNAL_SERVER_ERROR) - .send(err) - ); - }); + console.log("Executing save procedure..."); + return ( + res + // @ts-ignore + .status(HttpStatus.CREATED) + .send(await this.filesService.save(fileBuffer, Params)) + ); + } catch (err) { + console.error(err); + return ( + res + // @ts-ignore + .status(err.status || HttpStatus.INTERNAL_SERVER_ERROR) + .send(err) + ); + } + }); - return; - } + req.on("error", (err) => { + return ( + res + // @ts-ignore + .status(err.status || HttpStatus.INTERNAL_SERVER_ERROR) + .send(err) + ); + }); - @HttpCode(HttpStatus.FOUND) - @Get("find") - async findMany( - @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, - @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, - @Query("search", new DefaultValuePipe("")) search: string, - ) { - return this.filesService.search(limit, offset, search); - } + return; + } - @HttpCode(HttpStatus.FOUND) - @Get("types") - async getTypes() { - console.log("Performing request") - return await this.filesService.getAllFilesTypes(); - } + @HttpCode(HttpStatus.FOUND) + @Get("find") + async findMany( + @Query("limit", new DefaultValuePipe(20), ParseIntPipe) limit: number, + @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, + @Query("search", new DefaultValuePipe("")) search: string, + ) { + return this.filesService.search(limit, offset, search); + } - @HttpCode(HttpStatus.CREATED) - @UseGuards(AdminGuard) - @Post("types/new") - async newType(@Body() body: CreateFileTypeDto) { - return await this.filesService.createFileType(body.name, body.mime); - } + @HttpCode(HttpStatus.FOUND) + @Get("types") + async getTypes() { + console.log("Performing request"); + return await this.filesService.getAllFilesTypes(); + } - @HttpCode(HttpStatus.ACCEPTED) - @UseGuards(AdminGuard) - @Delete("types/:typeId") - async delType(@Param(":typeId", ParseUUIDPipe) typeId: string) { - return await this.filesService.removeFileType(typeId) - } + @HttpCode(HttpStatus.CREATED) + @UseGuards(AdminGuard) + @Post("types/new") + async newType(@Body() body: CreateFileTypeDto) { + return await this.filesService.createFileType(body.name, body.mime); + } - @HttpCode(HttpStatus.FOUND) - @Get(":fileId") - async getFile(@Param("fileId") fileId: string) { - return await this.filesService.get(fileId); - } + @HttpCode(HttpStatus.ACCEPTED) + @UseGuards(AdminGuard) + @Delete("types/:typeId") + async delType(@Param(":typeId", ParseUUIDPipe) typeId: string) { + return await this.filesService.removeFileType(typeId); + } - @HttpCode(HttpStatus.OK) - @UseGuards(AdminGuard) - @Delete(":fileId") - async deleteFile(@Param("fileId", ParseUUIDPipe) fileId: string) { - return await this.filesService.deleteFile(fileId); - } + @HttpCode(HttpStatus.FOUND) + @Get(":fileId") + async getFile(@Param("fileId") fileId: string) { + return await this.filesService.get(fileId); + } + @HttpCode(HttpStatus.OK) + @UseGuards(AdminGuard) + @Delete(":fileId") + async deleteFile(@Param("fileId", ParseUUIDPipe) fileId: string) { + return await this.filesService.deleteFile(fileId); + } } diff --git a/apps/backend/src/app/files/files.service.ts b/apps/backend/src/app/files/files.service.ts index 89169c7..508d440 100644 --- a/apps/backend/src/app/files/files.service.ts +++ b/apps/backend/src/app/files/files.service.ts @@ -195,7 +195,7 @@ export class FilesService { .where(eq(FilesGroupTable.uuid, _group)) .prepare("checkGroupExists") .execute(); - + if (!_group) console.log("No group to link with the file."); if (_group && groupExists.length === 0) { throw new NotFoundException(`Group with ID "${_group}" not found`); } @@ -203,7 +203,7 @@ export class FilesService { const saveResult = await this.storage.new( data.get("fileName") as string, file, - _machineIds, + machinesIds, Boolean(data.get("isDocumentation")), ); console.log(saveResult); @@ -212,7 +212,7 @@ export class FilesService { .select() .from(FilesTypesTable) .where(eq(FilesTypesTable.mime, saveResult.fileType.mime)); - + console.log(mimeId); const inserted = await this.database .use() .insert(FilesTable) @@ -227,7 +227,9 @@ export class FilesService { uploadedBy: data.get("uploadedBy") as string, }) .returning(); - if (groupExists[0].uuid) { + console.log(inserted); + if (_group) { + console.log("Adding group ip to file.."); await this.database .use() .update(FilesTable) @@ -238,7 +240,7 @@ export class FilesService { .execute(); } - console.log(inserted); + console.log("File insertion done"); for (const machineId of machinesIds) { console.log( @@ -299,7 +301,7 @@ export class FilesService { .from(FilesTypesTable) .prepare("getAllFilesTypes") .execute(); - console.log(result) + console.log(result); return result; } diff --git a/apps/backend/src/app/storage/storage.service.ts b/apps/backend/src/app/storage/storage.service.ts index 66f3f2d..6ec8475 100644 --- a/apps/backend/src/app/storage/storage.service.ts +++ b/apps/backend/src/app/storage/storage.service.ts @@ -1,4 +1,3 @@ -import * as console from "node:console"; import * as crypto from "node:crypto"; import { readFile, rm, writeFile } from "node:fs/promises"; import { join } from "node:path"; @@ -43,13 +42,15 @@ export class StorageService { } /** - * Checks if the current MIME type and file size meet the specified conditions. - * @param {Array} machineIds - The IDs of the associated machines. - * @param {Buffer} file - The file to check. - * @return {Promise} - A Promise that resolves to true if the conditions are met, false otherwise. + * Checks the conditions for the provided file and machine IDs. + * + * @param {Set} machinesIds - A set containing machine identifiers. + * @param {Buffer} file - The file buffer that needs to be checked. + * @return {Promise} Returns a promise that resolves to true if the conditions are met, otherwise it throws an exception. + * @throws {BadRequestException} If the file size exceeds the allowed maximum size or the file MIME type is not allowed. */ private async checkConditions( - machineIds: Array, + machinesIds: Set, file: Buffer, ): Promise { /** @@ -65,6 +66,7 @@ export class StorageService { ): boolean { let notFoundCount = 0; for (const mimesForMachine of mimesForMachines) { + console.log(mimesForMachine); const [key, set] = mimesForMachine; if (!set.has(currentMime)) { notFoundCount++; @@ -82,10 +84,12 @@ export class StorageService { string, Set >(); + const mimeSet = new Set(_mimes); // Fetching MIMEs for the associated machines - for (const machineId of machineIds) { + for (const machineId of machinesIds) { console.debug(`Fetching mimeTypes for machine : ${machineId}`); // Get MIMEs associated to a machine + /* const allowedMimeId = this.dbService .use() .select() @@ -102,18 +106,31 @@ export class StorageService { .leftJoin( allowedMimeId, eq(FilesTypesTable.id, allowedMimeId.fileTypeId), + );*/ + + const _allowedMime = await this.dbService + .use() + .select() + .from(FilesTypeForMachine) + .where(eq(FilesTypeForMachine.machineId, machineId)) + .leftJoin( + FilesTypesTable, + eq(FilesTypesTable.id, FilesTypeForMachine.fileTypeId), ); + console.log(_allowedMime); console.debug(`Total : ${_allowedMime.length}`); // Append each MIME of a machine const tempSet = new Set(); for (const allowedMimeElement of _allowedMime) { - tempSet.add(allowedMimeElement.slug); + console.debug( + `Adding ${allowedMimeElement.f_types.mime} for verification..`, + ); + tempSet.add(allowedMimeElement.f_types.mime); + mimeSet.add(allowedMimeElement.f_types.mime); } machinesMap.set(machineId, tempSet); - tempSet.clear(); } //Store the MIMEs without duplicate - const mimeSet = new Set(_mimes); console.debug(`Indexed ${mimeSet.size} unique mimeTypes`); //check file size is less than 2mb @@ -236,7 +253,7 @@ export class StorageService { public async new( fileDisplayName: string, file: Buffer, - machinesId: Array, + machinesId: Set, isDocumentation?: boolean, ): Promise { try { @@ -246,7 +263,7 @@ export class StorageService { isDocumentation, ); console.log( - `Trying to append a new file : "${info.fileDisplayName}"...\n > Checksum SHA-256 : ${info.fileChecksum}\n > Size : ${info.fileSize / (1024 * 1024)}Mio\n > File format : ${info.fileType.mime}\n`, + `Trying to append a new file : "${info.fileDisplayName}"...\n > Checksum SHA-256 : ${info.fileChecksum}\n > Size : ${(info.fileSize / (1024 * 1024)).toFixed(6)} Mio\n > File format : ${info.fileType.mime}\n`, ); const condition = await this.checkConditions(machinesId, file); if (!condition) {