Update file handling and error reporting in storage service

Changed the file saving path from "files/" to "assets/" to unify storage structure. Improved error handling and logging in the file operations to aid in debugging. Additionally, streamlined database insertion and validation logic in the files service for better efficiency and readability.
This commit is contained in:
Mathis H (Avnyr) 2024-10-08 11:30:26 +02:00
parent 9d28d4f82a
commit b182d740bd
Signed by: Mathis
GPG Key ID: DD9E0666A747D126
4 changed files with 98 additions and 86 deletions

View File

@ -34,42 +34,52 @@ export class FilesController {
}); });
req.on("end", async () => { req.on("end", async () => {
const _fileName = req.headers["file_name"] as string; try {
const _groupId = req.headers["group_id"] as string; console.log(fileBuffer);
const _uploadedBy = req.headers["uploaded_by"] as string; const _fileName = req.headers["file_name"] as string;
const _machineId = req.headers["machine_id"]; const _groupId = req.headers["group_id"] as string;
const _isDocumentation = req.headers["is_documentation"] as string; const _uploadedBy = req.headers["uploaded_by"] as string;
const _isRestricted = req.headers["is_restricted"] as string; const _machineId = req.headers["machine_id"];
const _isAdmin = Boolean(req.headers["is_admin"] as string | boolean); 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 // Vérifier que les en-têtes nécessaires sont présents
if (!_fileName || !_groupId || !_machineId) { if (!_fileName || !_groupId || !_machineId) {
throw new BadRequestException("Header(s) manquant(s)"); throw new BadRequestException("Header(s) manquant(s)");
}
const machineId = Array(_machineId);
const Params = new Map()
.set("fileName", _fileName.toString())
.set("groupId", Array(JSON.parse(_groupId.toString())))
.set("uploadedBy", _uploadedBy.toString())
.set("machineId", Array(JSON.parse(machineId.toString())))
.set("isDocumentation", false)
.set("isRestricted", false);
console.log(Params);
//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));
}
return await this.filesService.save(fileBuffer, Params);
} catch (err) {
// @ts-ignore
return res.status(err.status || HttpStatus.INTERNAL_SERVER_ERROR).send(err)
} }
const machineId = Array(..._machineId);
const Params = new Map()
.set("fileName", _fileName.toString())
.set("groupId", _groupId.toString())
.set("uploadedBy", _uploadedBy.toString())
.set("machineId", Array(..._machineId))
.set("isDocumentation", false)
.set("isRestricted", false);
//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));
}
await this.filesService.save(fileBuffer, Params);
return { message: "Fichier sauvegardé avec succès" };
}); });
req.on("error", (err) => { req.on("error", (err) => {
throw new BadRequestException(err.message); // @ts-ignore
return res.status(err.status || HttpStatus.INTERNAL_SERVER_ERROR).send(err)
}); });
return;
} }
@Get("find") @Get("find")

View File

@ -9,9 +9,9 @@ import {
FilesForMachinesTable, FilesForMachinesTable,
FilesGroupTable, FilesGroupTable,
FilesTable, FilesTable,
FilesTypeForMachine, FilesTypeForMachine, FilesTypesTable,
MachinesTable, MachinesTable
} from "apps/backend/src/app/db/schema"; } from 'apps/backend/src/app/db/schema';
import { StorageService } from "apps/backend/src/app/storage/storage.service"; import { StorageService } from "apps/backend/src/app/storage/storage.service";
import { data } from "autoprefixer"; import { data } from "autoprefixer";
import { eq, ilike } from "drizzle-orm"; import { eq, ilike } from "drizzle-orm";
@ -49,6 +49,7 @@ export class FilesService {
"Multiples entries found in the database.\nInformation from the first row will be used.", "Multiples entries found in the database.\nInformation from the first row will be used.",
); );
const file = foundFiles[0]; const file = foundFiles[0];
console.log(file);
const fileBuffer = await this.storage.read( const fileBuffer = await this.storage.read(
file.checksum, file.checksum,
@ -62,7 +63,7 @@ export class FilesService {
); );
const fileNameWithoutSpaces = file.fileName.replace(/\s/g, "_"); const fileNameWithoutSpaces = file.fileName.replace(/\s/g, "_");
return new StreamableFile(fileBuffer, { return new StreamableFile(fileBuffer, {
disposition: `attachment; filename="${fileNameWithoutSpaces}.${fileInformation.fileType[0].extension.toLowerCase()}"`, disposition: `attachment; filename="${fileNameWithoutSpaces}.${fileInformation.fileType.extension.toLowerCase()}"`,
}); });
} }
@ -80,64 +81,73 @@ export class FilesService {
//TODO save a file //TODO save a file
public async save(file: Buffer, data: Map<string, unknown>) { public async save(file: Buffer, data: Map<string, unknown>) {
const _machineIds = Array.from(data.get("machineId") as string[]); try {
const machinesIds = new Set<string>(); const _machineIds = data.get("machineId").toString().split(",");
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) { const machinesIds = new Set<string>();
throw new NotFoundException(`Machine with ID "${machineId}" not found`); for (const machineId of _machineIds) {
console.log(
`Checking if machine with ID ${machineId} exist in the database...`,
);
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);
} }
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();
const _group = data.get("groupId") as string; if (groupExists.length === 0) {
// verify that the group exist in the database throw new NotFoundException(`Group with ID "${_group}" not found`);
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( const saveResult = await this.storage.new(
data.get("fileName") as string, data.get("fileName") as string,
file, file,
_machineIds, _machineIds,
Boolean(data.get("isDocumentation")), Boolean(data.get("isDocumentation")),
); );
console.log(saveResult);
const mimeId = await this.database.use()
.select()
.from(FilesTypesTable)
.where(eq(FilesTypesTable.mime, saveResult.fileType.mime))
const inserted = await this.database const inserted = await this.database
.use() .use()
.insert(FilesTable) .insert(FilesTable)
.values({ .values({
fileName: data.get("fileName") as string, fileName: data.get("fileName") as string,
checksum: saveResult.fileChecksum, checksum: saveResult.fileChecksum,
extension: saveResult.fileType[0].extension, extension: saveResult.fileType.extension,
fileSize: saveResult.fileSize, fileSize: saveResult.fileSize,
fileType: saveResult.fileType.mime, fileType: mimeId[0].id,
isRestricted: Boolean(data.get("isRestricted")), isRestricted: Boolean(data.get("isRestricted")),
isDocumentation: Boolean(data.get("isDocumentation")), isDocumentation: Boolean(data.get("isDocumentation")),
uploadedBy: data.get("uploadedBy") as string, uploadedBy: data.get("uploadedBy") as string,
}) })
.returning(); .returning();
console.log(inserted);
for (const machineId of machinesIds) { for (const machineId of machinesIds) {
//TODO insert a link betwen fileId and MachineIds[] //TODO insert a link betwen fileId and MachineIds[]
@ -149,20 +159,10 @@ export class FilesService {
machineId: machineId, machineId: machineId,
}); });
} }
} catch (e) {
throw new InternalServerErrorException( return inserted[0];
"It seems that the insertion in the database failed.", } catch (err) {
{ throw err;
cause:
process.env.NODE_ENV === "production"
? "Internal server error"
: {
message: e.message,
stack: e.stack,
},
description: `Nom de fichier : "${data.get("fileName")}" `,
},
);
} }
} }
} }

View File

@ -34,7 +34,7 @@ export class StorageService {
*/ */
private async saveFile(fileName: string, file: Buffer): Promise<void> { private async saveFile(fileName: string, file: Buffer): Promise<void> {
try { try {
await writeFile(join(process.cwd(), "files/", fileName), file, "utf8"); await writeFile(join(process.cwd(), "assets/", fileName), file, "utf8");
} catch (err) { } catch (err) {
console.error(err); console.error(err);
throw new InternalServerErrorException("File save failed !"); throw new InternalServerErrorException("File save failed !");
@ -123,7 +123,7 @@ export class StorageService {
*/ */
private async getFile(fileName: string): Promise<Buffer> { private async getFile(fileName: string): Promise<Buffer> {
try { try {
return await readFile(join(process.cwd(), "files/", fileName)); return await readFile(join(process.cwd(), "assets/", fileName));
} catch (err) { } catch (err) {
throw new NotFoundException("File not found"); throw new NotFoundException("File not found");
} }
@ -245,9 +245,11 @@ export class StorageService {
await this.saveFile(info.fileName, file); await this.saveFile(info.fileName, file);
// All good we return data about the file to append it to the db. // All good we return data about the file to append it to the db.
console.log(`File "${info.fileName}" saved successfully.`);
return info; return info;
} catch (err) { } catch (err) {
throw new BadRequestException(err); console.error(err);
throw err;
} }
} }
} }

0
assets/.gitkeep Normal file
View File