diff --git a/Prototype/server/src/controllers/folderController.ts b/Prototype/server/src/controllers/folderController.ts index 3cd0380..b845972 100644 --- a/Prototype/server/src/controllers/folderController.ts +++ b/Prototype/server/src/controllers/folderController.ts @@ -1,22 +1,34 @@ -import { Body, Controller, Get, Post, Put, Query, Route, SuccessResponse, Tags } from "tsoa"; +import { + Body, + Controller, + Delete, + Get, + Path, + Post, + Put, + Query, + Route, + SuccessResponse, + Tags, +} from "tsoa"; +import * as Minio from "minio"; + import HttpError from "../interfaces/http-error"; import HttpStatusCode from "../interfaces/http-status"; import { listFolder, pathExist } from "../utils/minio"; import { EhrFolder } from "../interfaces/ehr-fs"; import minioClient from "../storage"; -@Route("/folder") +@Route("/cabinet") export class FolderController extends Controller { - @Get("/") + @Get("/{cabinetName}/drawer/{drawerName}/folder") @Tags("Folder") - @SuccessResponse(HttpStatusCode.OK, "List of folder under drawer or under subfolder") + @SuccessResponse(HttpStatusCode.OK) public async listFolder( - @Query() cabinet: string, - @Query() drawer: string, - @Query() path?: string, + @Path() cabinetName: string, + @Path() drawerName: string, ): Promise { - const fullpath = - [cabinet, drawer, path?.replace(/^\/|\/$/g, "")].filter((v) => !!v).join("/") + "/"; + const fullpath = [cabinetName, drawerName].join("/") + "/"; if (!(await pathExist(fullpath))) { throw new HttpError(HttpStatusCode.NOT_FOUND, "Provided path does not exist."); @@ -25,24 +37,20 @@ export class FolderController extends Controller { return listFolder(fullpath); } - @Post("/") + @Post("/{cabinetName}/drawer/{drawerName}/folder") @Tags("Folder") - @SuccessResponse(HttpStatusCode.CREATED, "Folder created.") + @SuccessResponse(HttpStatusCode.CREATED) public async createFolder( @Body() body: { name: string }, - @Query() cabinet: string, - @Query() drawer: string, - @Query() path?: string, + @Path() cabinetName: string, + @Path() drawerName: string, ) { - const fullpath = - [cabinet, drawer, path?.replace(/^\/|\/$/g, "")].filter((v) => !!v).join("/") + "/"; - - if (!(await pathExist(fullpath))) { - throw new HttpError(HttpStatusCode.PRECONDITION_FAILED, "Provided path does not exist."); + if (!(await pathExist(`${cabinetName}/${drawerName}/`))) { + throw new HttpError(HttpStatusCode.PRECONDITION_FAILED, "Cabinet or drawer cannot be found."); } const uploaded = await minioClient - .putObject("ehr", `${fullpath}${body.name}/.keep`, "", 0, { + .putObject("ehr", `${cabinetName}/${drawerName}/${body.name}/.keep`, "", 0, { createdAt: new Date().toISOString(), createdBy: "SomeUser", }) @@ -52,39 +60,80 @@ export class FolderController extends Controller { throw new Error("Object storage error occured."); } - this.setStatus(HttpStatusCode.CREATED); - return; + return this.setStatus(HttpStatusCode.CREATED); } - @Put("/") + @Put("/{cabinetName}/drawer/{drawerName}/folder/{folderName}") @Tags("Folder") - @SuccessResponse(HttpStatusCode.NO_CONTENT, "Folder name changed.") + @SuccessResponse(HttpStatusCode.NO_CONTENT) public async editFolder( @Body() body: { name: string }, - @Query() cabinet: string, - @Query() drawer: string, - @Query() path: string, + @Query() cabinetName: string, + @Query() drawerName: string, + @Query() folderName: string, ) { - const fullpath = - [cabinet, drawer, path.replace(/^\/|\/$/g, "")].filter((v) => !!v).join("/") + "/"; + const fullpath = [cabinetName, drawerName, folderName].join("/") + "/"; if (!(await pathExist(fullpath))) { - throw new HttpError(HttpStatusCode.PRECONDITION_FAILED, "Provided path does not exist."); + throw new HttpError( + HttpStatusCode.PRECONDITION_FAILED, + "Provided resource location does not exist.", + ); } - // TODO: Recursive get object and move - // const uploaded = await minioClient - // .putObject("ehr", `${fullpath}${body.name}/.keep`, "", 0, { - // createdAt: new Date().toISOString(), - // createdBy: "SomeUser", - // }) - // .catch((e) => console.error(e)); - // - // if (!uploaded) { - // throw new Error("Object storage error occured."); - // } + return new Promise((resolve, reject) => { + const stream = minioClient.listObjectsV2("ehr", fullpath, true); - this.setStatus(HttpStatusCode.CREATED); - return; + stream.on("data", (v) => { + if (!(v && v.name)) return; + + const destination = `${cabinetName}/${drawerName}/${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("/{cabinetName}/drawer/{drawerName}/folder/{folderName}") + @Tags("Folder") + @SuccessResponse(HttpStatusCode.NO_CONTENT) + public async deleteFolder( + @Path() cabinetName: string, + @Path() drawerName: string, + @Path() folderName: string, + ) { + return new Promise((resolve, reject) => { + const objects: string[] = []; + const stream = minioClient.listObjectsV2( + "ehr", + `${cabinetName}/${drawerName}/${folderName}`, + 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)); + }); } }