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) {