From ef5349063deaf4497f0475dd1c50967a9d24796c Mon Sep 17 00:00:00 2001 From: Mathis Date: Mon, 7 Oct 2024 12:00:46 +0200 Subject: [PATCH] Enhance files service to save file data Implemented detailed logic to check machine and group existence before saving files. Added comprehensive error handling to provide clear feedback when database operations fail. Improved file saving functionality with associations between files and machines. --- apps/backend/src/app/files/files.service.ts | 116 ++++++++++++++++++-- 1 file changed, 105 insertions(+), 11 deletions(-) diff --git a/apps/backend/src/app/files/files.service.ts b/apps/backend/src/app/files/files.service.ts index 929c93f..c2c648d 100644 --- a/apps/backend/src/app/files/files.service.ts +++ b/apps/backend/src/app/files/files.service.ts @@ -1,9 +1,20 @@ -import { Injectable, NotFoundException, StreamableFile } from '@nestjs/common'; -import { DbService } from 'apps/backend/src/app/db/db.service'; -import { FilesTable } from 'apps/backend/src/app/db/schema'; -import { StorageService } from 'apps/backend/src/app/storage/storage.service'; -import { eq, ilike } from 'drizzle-orm'; - +import { + Injectable, + InternalServerErrorException, + NotFoundException, + StreamableFile, +} from "@nestjs/common"; +import { DbService } from "apps/backend/src/app/db/db.service"; +import { + FilesForMachinesTable, + FilesGroupTable, + FilesTable, + FilesTypeForMachine, + MachinesTable, +} from "apps/backend/src/app/db/schema"; +import { StorageService } from "apps/backend/src/app/storage/storage.service"; +import { data } from "autoprefixer"; +import { eq, ilike } from "drizzle-orm"; @Injectable() export class FilesService { @@ -12,7 +23,7 @@ export class FilesService { private readonly database: DbService, ) {} - /** + /** * Retrieves a file and its related information from the database and associated storage. * * @param fileId The unique identifier for the file to be retrieved. @@ -30,8 +41,8 @@ export class FilesService { if (foundFiles.length === 0) throw new NotFoundException("File not found", { - description: `Identifier : ${fileId}` - }); + description: `Identifier : ${fileId}`, + }); if (foundFiles.length > 1) console.log( @@ -51,7 +62,7 @@ export class FilesService { ); const fileNameWithoutSpaces = file.fileName.replace(/\s/g, "_"); return new StreamableFile(fileBuffer, { - disposition: `attachment; filename="${fileNameWithoutSpaces}.${fileInformation.fileType.ext.toLowerCase()}"` + disposition: `attachment; filename="${fileNameWithoutSpaces}.${fileInformation.fileType.ext.toLowerCase()}"`, }); } @@ -68,7 +79,90 @@ export class FilesService { } //TODO save a file - public async save() { + public async save(file: Buffer, data: Map) { + const _machineIds = Array.from(data.get("machineId") as string[]); + const machinesIds = new Set(); + console.log( + `Checking if machine with ID ${_machineIds} exist in the database...`, + ); + for (const machineId of _machineIds) { + const machineExists = await this.database + .use() + .select({ + uuid: MachinesTable.id, + }) + .from(MachinesTable) + .where(eq(MachinesTable.id, machineId)) + .prepare("checkMachineExists") + .execute(); + if (machineExists.length === 0) { + throw new NotFoundException(`Machine with ID "${machineId}" not found`); + } + + machinesIds.add(machineExists[0].uuid); + } + + const _group = data.get("groupId") as string; + // verify that the group exist in the database + const groupExists = await this.database + .use() + .select() + .from(FilesGroupTable) + .where(eq(FilesGroupTable.uuid, _group)) + .prepare("checkGroupExists") + .execute(); + + if (groupExists.length === 0) { + throw new NotFoundException(`Group with ID "${_group}" not found`); + } + + try { + const saveResult = await this.storage.new( + data.get("fileName") as string, + file, + _machineIds, + Boolean(data.get("isDocumentation")), + ); + const inserted = await this.database + .use() + .insert(FilesTable) + .values({ + fileName: data.get("fileName") as string, + checksum: saveResult.fileChecksum, + extension: saveResult.fileType.ext, + fileSize: saveResult.fileSize, + fileType: saveResult.fileType.mime, + isRestricted: Boolean(data.get("isRestricted")), + isDocumentation: Boolean(data.get("isDocumentation")), + uploadedBy: data.get("uploadedBy") as string, + }) + .returning(); + + for (const machineId of machinesIds) { + //TODO insert a link betwen fileId and MachineIds[] + const linkRow = await this.database + .use() + .insert(FilesForMachinesTable) + .values({ + fileId: inserted[0].uuid, + machineId: machineId, + }); + } + } catch (e) { + throw new InternalServerErrorException( + "It seems that the insertion in the database failed.", + { + cause: + process.env.NODE_ENV === "production" + ? "Internal server error" + : { + message: e.message, + stack: e.stack, + }, + description: `Nom de fichier : "${data.get("fileName")}" `, + }, + ); + } } }