import { Body, Controller, Delete, Get, Path, Post, Put, Query, Request, Route, Security, SuccessResponse, Tags, } from "tsoa"; import * as Minio from "minio"; import HttpError from "../interfaces/http-error"; import HttpStatusCode from "../interfaces/http-status"; import { listFolder, pathExist, replaceIllegalChars } from "../utils/minio"; import { EhrFolder } from "../interfaces/ehr-fs"; import minioClient from "../storage"; @Route("/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder") export class SubFolderController extends Controller { @Get("/") @Tags("SubFolder") @SuccessResponse(HttpStatusCode.OK) public async listFolder( @Path() cabinetName: string, @Path() drawerName: string, @Path() folderName: string, ): Promise { const fullpath = [cabinetName, drawerName, folderName].join("/") + "/"; if (!(await pathExist(fullpath))) { throw new HttpError(HttpStatusCode.NOT_FOUND, "Provided path does not exist."); } return listFolder(fullpath); } @Post("/") @Tags("SubFolder") @Security("bearerAuth") @SuccessResponse(HttpStatusCode.CREATED) public async createFolder( @Request() request: { user: { preferred_username: string } }, @Body() body: { name: string }, @Path() cabinetName: string, @Path() drawerName: string, @Path() folderName: string, ) { if (!(await pathExist(`${cabinetName}/${drawerName}/${folderName}`))) { throw new HttpError( HttpStatusCode.PRECONDITION_FAILED, "Cabinet, drawer or folder cannot be found.", ); } const uploaded = await minioClient .putObject( "ehr", `${cabinetName}/${drawerName}/${folderName}/${replaceIllegalChars(body.name)}/.keep`, "", 0, { createdAt: new Date().toISOString(), createdBy: request.user.preferred_username, }, ) .catch((e) => console.error(e)); if (!uploaded) { throw new Error("Object storage error occured."); } return this.setStatus(HttpStatusCode.CREATED); } @Put("/{subFolderName}") @Tags("SubFolder") @Security("bearerAuth") @SuccessResponse(HttpStatusCode.NO_CONTENT) public async editFolder( @Body() body: { name: string }, @Query() cabinetName: string, @Query() drawerName: string, @Query() folderName: string, @Query() subFolderName: string, ) { const fullpath = [cabinetName, drawerName, folderName, subFolderName].join("/") + "/"; if (!(await pathExist(fullpath))) { throw new HttpError( HttpStatusCode.PRECONDITION_FAILED, "Provided resource location does not exist.", ); } return new Promise((resolve, reject) => { const stream = minioClient.listObjectsV2("ehr", fullpath, true); stream.on("data", (v) => { if (!(v && v.name)) return; const destination = `${cabinetName}/${drawerName}/${folderName}/${replaceIllegalChars( body.name, )}/${v.name.slice(fullpath.length)}`; const source = `/ehr/${v.name}`; const cond = new Minio.CopyConditions(); minioClient.copyObject("ehr", destination, source, cond, (e) => { if (e) { return reject(new Error("Failed to move.")); } return minioClient.removeObject("ehr", v.name); }); }); stream.on("end", () => { resolve(this.setStatus(HttpStatusCode.NO_CONTENT)); }); stream.on("error", () => reject(new Error("Object storage error occured."))); }); } @Delete("/{subFolderName}") @Tags("SubFolder") @Security("bearerAuth") @SuccessResponse(HttpStatusCode.NO_CONTENT) public async deleteFolder( @Path() cabinetName: string, @Path() drawerName: string, @Path() folderName: string, @Path() subFolderName: string, ) { return new Promise((resolve, reject) => { const objects: string[] = []; const stream = minioClient.listObjectsV2( "ehr", `${cabinetName}/${drawerName}/${folderName}/${subFolderName}`, true, ); stream.on("data", (v) => { if (!(v && v.name)) return; objects.push(v.name); }); stream.on("close", () => minioClient.removeObjects("ehr", objects)); stream.on("error", () => reject(new Error("Object storage error occured."))); resolve(this.setStatus(HttpStatusCode.NO_CONTENT)); }); } }