diff --git a/src/app/api/super-admin/FilesController.ts b/src/app/api/super-admin/FilesController.ts index 68c2dfd1..b3be77f3 100644 --- a/src/app/api/super-admin/FilesController.ts +++ b/src/app/api/super-admin/FilesController.ts @@ -42,19 +42,28 @@ export default class FilesController extends ApiController { /** * @description Get a specific File by uid */ - @Get("/api/v1/super-admin/files/upload/:uid") - protected async getFileData(req: Request, response: Response) { + @Get("/api/v1/super-admin/files/download/:uid") + protected async download(req: Request, response: Response) { + const uid = req.params["uid"]; + if (!uid) { + this.httpBadRequest(response, "uid not found"); + return; + } try { - const uid = req.params["uid"]; - if (!uid) { - throw new Error("No uid provided"); + const fileInfo = await this.filesService.download(uid); + + if (!fileInfo) { + this.httpNotFoundRequest(response); + return; } - const file = await this.filesService.updload(uid); - - this.httpSuccess(response, file); + const type = fileInfo.file.file_name.split(".").pop(); + if (type?.toLowerCase() === "pdf") response.setHeader("Content-Type", "application/pdf"); + response.setHeader("Content-Disposition", `inline; filename=${encodeURIComponent(fileInfo.file.file_name)}`); + + this.httpSuccess(response, fileInfo.buffer); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response); return; } } @@ -66,23 +75,22 @@ export default class FilesController extends ApiController { @Post("/api/v1/super-admin/files") protected async post(req: Request, response: Response) { try { - //get file - if(!req.file) throw new Error('No file provided') + if (!req.file) throw new Error("No file provided"); //init File resource with request body values const fileEntity = File.hydrate(JSON.parse(req.body["q"])); - + //validate File await validateOrReject(fileEntity, { groups: ["createFile"] }); //call service to get prisma entity const prismaEntityCreated = await this.filesService.create(fileEntity, req.file); - const document: Document = await this.documentService.getByUid(fileEntity.document!.uid!) + const document: Document = await this.documentService.getByUid(fileEntity.document!.uid!); document.document_status = "DEPOSITED"; await this.documentService.update(document.uid!, document); - + //Hydrate ressource with prisma entity const fileEntityCreated = File.hydrate(prismaEntityCreated, { strategy: "excludeAll", @@ -135,19 +143,24 @@ export default class FilesController extends ApiController { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } //call service to get prisma entity - const fileEntity: Files = await this.filesService.delete(uid); + const fileEntity = await this.filesService.deleteKeyAndArchive(uid); + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; + } //Hydrate ressource with prisma entity const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); //success this.httpSuccess(response, file); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response); return; } } @@ -160,18 +173,24 @@ export default class FilesController extends ApiController { try { const uid = req.params["uid"]; if (!uid) { - throw new Error("No uid provided"); + this.httpBadRequest(response, "No uid provided"); + return; } const fileEntity = await this.filesService.getByUid(uid); - + + if (!fileEntity) { + this.httpNotFoundRequest(response, "file not found"); + return; + } + //Hydrate ressource with prisma entity const file = File.hydrate(fileEntity, { strategy: "excludeAll" }); //success this.httpSuccess(response, file); } catch (error) { - this.httpBadRequest(response, error); + this.httpInternalError(response); return; } } diff --git a/src/common/repositories/FilesRepository.ts b/src/common/repositories/FilesRepository.ts index 34f2f89c..f3003b40 100644 --- a/src/common/repositories/FilesRepository.ts +++ b/src/common/repositories/FilesRepository.ts @@ -58,9 +58,9 @@ export default class FilesRepository extends BaseRepository { } /** - * @description : Delete a file + * @description : Delete a file key and archive */ - public async delete(uid: string): Promise { + public async deleteKeyAndArchive(uid: string): Promise { return this.model.update({ where: { uid: uid, @@ -75,17 +75,12 @@ export default class FilesRepository extends BaseRepository { /** * @description : Find unique file */ - public async findOneByUid(uid: string): Promise { + public async findOneByUid(uid: string): Promise { const fileEntity = await this.model.findUnique({ where: { uid: uid, }, }); - - if (!fileEntity) { - throw new Error("File not found"); - } - return fileEntity; } } diff --git a/src/common/system/controller-pattern/BaseController.ts b/src/common/system/controller-pattern/BaseController.ts index 3b128b1f..24906610 100644 --- a/src/common/system/controller-pattern/BaseController.ts +++ b/src/common/system/controller-pattern/BaseController.ts @@ -24,7 +24,7 @@ export default abstract class BaseController { return this.httpResponse(response, HttpCodes.NOT_FOUND, responseData); } - protected httpInternaleError(response: Response, responseData: IResponseData = "http Internal Server Error") { + protected httpInternalError(response: Response, responseData: IResponseData = "http Internal Server Error") { return this.httpResponse(response, HttpCodes.INTERNAL_ERROR, responseData); } diff --git a/src/entries/App.ts b/src/entries/App.ts index da76f6ae..d9874748 100644 --- a/src/entries/App.ts +++ b/src/entries/App.ts @@ -8,7 +8,10 @@ import bodyParser from "body-parser"; // import TezosLink from "@Common/databases/TezosLink"; import errorHandler from "@App/middlewares/ErrorHandler"; import { BackendVariables } from "@Common/config/variables/Variables"; -import fileHandler from "@App/middlewares/FileHandler"; +//import fileHandler from "@App/middlewares/FileHandler"; +import multer from "multer"; + +const storage = multer.memoryStorage(); (async () => { try { @@ -23,7 +26,7 @@ import fileHandler from "@App/middlewares/FileHandler"; label, port: parseInt(port), rootUrl, - middlwares: [cors({ origin: "*" }), fileHandler, bodyParser.urlencoded({ extended: true }), bodyParser.json()], + middlwares: [cors({ origin: "*" }), multer({storage:storage}).single('file'), bodyParser.urlencoded({ extended: true }), bodyParser.json()], errorHandler, }); diff --git a/src/services/private-services/FilesService/FilesService.ts b/src/services/private-services/FilesService/FilesService.ts index 88e5948b..6aacc1d0 100644 --- a/src/services/private-services/FilesService/FilesService.ts +++ b/src/services/private-services/FilesService/FilesService.ts @@ -39,12 +39,12 @@ export default class FilesService extends BaseService { * @description : view a file * @throws {Error} If file cannot be deleted */ - public async updload(uid: string) { + public async download(uid: string) { const file = await this.filesRepository.findOneByUid(uid); - if (!file.key) throw new Error("file deleted"); + if (!file?.key) return null; const fileResult = await fetch(file.file_path); const fileContent = await fileResult.arrayBuffer(); - return await this.cryptoService.decrypt(Buffer.from(fileContent), file.key); + return {file: file, buffer: await this.cryptoService.decrypt(Buffer.from(fileContent), file.key)}; } /** @@ -53,8 +53,9 @@ export default class FilesService extends BaseService { */ public async create(file: File, fileData: Express.Multer.File) { const key = v4(); + fileData.mimetype; + fileData.size; const encryptedFile = await this.cryptoService.encrypt(fileData.buffer, key); - //const encryptedFileName = await this.cryptoService.encrypt(Buffer.from(fileData.originalname, 'utf-8'), key); const upload = await this.ipfsService.pinFile(Readable.from(encryptedFile), fileData.originalname); file.file_name = fileData.originalname; //encryptedFileName.toString('utf-8') file.file_path = this.variables.PINATA_GATEWAY.concat(upload.IpfsHash); @@ -71,18 +72,19 @@ export default class FilesService extends BaseService { } /** - * @description : Delete a file - * @throws {Error} If file cannot be deleted + * @description : Delete a file key and archive + * @throws {Error} If file key cannot be deleted or archived */ - public async delete(uid: string) { + public async deleteKeyAndArchive(uid: string) { try { const fileToUnpin = await this.filesRepository.findOneByUid(uid); - const fileHash = fileToUnpin.file_path.substring(this.variables.PINATA_GATEWAY.length); - await this.ipfsService.unpinFile(fileHash); + if(!fileToUnpin) return null; + const fileHash = fileToUnpin.file_path.substring(this.variables.PINATA_GATEWAY.length); + await this.ipfsService.unpinFile(fileHash); } catch(error) { console.error(error); } - return this.filesRepository.delete(uid); + return this.filesRepository.deleteKeyAndArchive(uid); } }