refactor: rabbitmq file upload process

This commit is contained in:
Methapon2001 2023-11-27 13:41:46 +07:00
parent 732a4b3989
commit 2c4d3846f1
No known key found for this signature in database
GPG key ID: 849924FEF46BD132
4 changed files with 398 additions and 427 deletions

View file

@ -7,6 +7,7 @@ import {
Path,
Post,
Request,
Response,
Route,
Security,
SuccessResponse,
@ -32,8 +33,12 @@ if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified."
export class FileController extends Controller {
@Post("/")
@Tags("File")
@Security("bearerAuth")
@SuccessResponse(HttpStatusCode.CREATED)
@Security("bearerAuth", ["admin"])
@Response(
HttpStatusCode.NOT_FOUND,
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
)
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
public async uploadFile(
@Request() request: { user: { preferred_username: string } },
@Body()
@ -56,7 +61,25 @@ export class FileController extends Controller {
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
);
}
const rec = await popInfo(pathname);
const result = await esClient
.search<EhrFile & { attachment?: Record<string, unknown> }>({
index: DEFAULT_INDEX!,
query: { match: { pathname } },
})
.catch((e) => console.error(e));
// pathname is unique and should not have multiple record with same path
if (result && result.hits.hits.length > 0 && result.hits.hits[0]._source) {
await esClient
.delete({
index: DEFAULT_INDEX!,
id: result.hits.hits[0]._id,
})
.catch((e) => console.error(e));
}
const rec = result ? result.hits.hits[0]._source : false;
const metadata: Partial<EhrFile> = {
pathname,
@ -75,7 +98,7 @@ export class FileController extends Controller {
};
await esClient.index({
index: "dev-index",
index: DEFAULT_INDEX!,
document: metadata,
});
@ -85,24 +108,21 @@ export class FileController extends Controller {
createdBy: metadata.createdBy,
updatedAt: metadata.updatedAt,
updatedBy: metadata.updatedBy,
upload: await minioClient.presignedPutObject("ehr", pathname),
upload: await minioClient.presignedPutObject(DEFAULT_BUCKET!, pathname),
};
}
@Get("/")
@Tags("File")
@SuccessResponse(HttpStatusCode.OK)
@Security("bearerAuth")
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
public async getFile(
@Path() cabinetName: string,
@Path() drawerName: string,
@Path() folderName: string,
): Promise<EhrFile[]> {
const search = await esClient.search<
EhrFile & {
attachment: Record<string, string>;
}
>({
index: process.env.ELASTICSEARCH_INDEX ?? "ehr-index",
const search = await esClient.search<EhrFile & { attachment: Record<string, string> }>({
index: DEFAULT_INDEX!,
query: {
prefix: {
pathname: `${cabinetName}/${drawerName}/${folderName}/`,
@ -124,8 +144,9 @@ export class FileController extends Controller {
@Patch("/{fileName}")
@Tags("File")
@Security("bearerAuth")
@SuccessResponse(HttpStatusCode.OK)
@Security("bearerAuth", ["admin"])
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างแฟ้ม")
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
public async updateFile(
@Request() request: { user: { preferred_username: string } },
@Path() cabinetName: string,
@ -141,26 +162,30 @@ export class FileController extends Controller {
keyword?: string;
},
): Promise<void | { upload: string }> {
const pathname = `${cabinetName}/${drawerName}/${folderName}/${fileName}`;
const basePath = `${cabinetName}/${drawerName}/${folderName}/`;
const pathname = `${basePath}${fileName}`;
if (!(await pathExist(`${cabinetName}/${drawerName}/${folderName}/`))) {
throw new HttpError(
HttpStatusCode.PRECONDITION_FAILED,
"Cabinet, drawer or folder cannot be found.",
);
if (
!Boolean(
await minioClient.statObject(DEFAULT_BUCKET!, `${pathname}`).catch((e) => {
if (e.code === "NotFound") return false;
throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
}),
)
) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบไฟล์");
}
// assume user will replace file by re-upload
// assume user will probably replace file by re-upload but maybe just rename
if (body.file) {
const destination = `${cabinetName}/${drawerName}/${folderName}/${body.file}`;
const source = `ehr/${cabinetName}/${drawerName}/${folderName}/${fileName}`;
const copy = await minioClient.copyObject("ehr", destination, source, copyCond);
const destination = `${basePath}${body.file}`;
const source = `/${DEFAULT_BUCKET}/${basePath}${fileName}`;
const copy = await minioClient.copyObject(DEFAULT_BUCKET!, destination, source, copyCond);
if (copy) {
const search = await esClient
.search<EhrFile & { attachment?: Record<string, unknown> }>({
index: "my-test-index",
index: DEFAULT_INDEX!,
query: { match: { pathname } },
})
.catch((e) => console.error(e));
@ -177,15 +202,15 @@ export class FileController extends Controller {
updatedBy: request.user.preferred_username ?? "n/a",
},
})
.then(() => minioClient.removeObject("ehr", pathname));
.then(() => minioClient.removeObject(DEFAULT_BUCKET!, pathname));
} else {
await minioClient.removeObject("ehr", pathname);
await minioClient.removeObject(DEFAULT_BUCKET!, pathname);
}
}
} else {
const search = await esClient
.search<EhrFile & { attachment?: Record<string, unknown> }>({
index: "my-test-index",
index: DEFAULT_INDEX!,
query: { match: { pathname } },
})
.catch((e) => console.error(e));
@ -207,52 +232,36 @@ export class FileController extends Controller {
}
return body.file
? this.setStatus(HttpStatusCode.NO_CONTENT)
: {
? {
upload: await minioClient.presignedPutObject(
"ehr",
`${cabinetName}/${drawerName}/${folderName}/${body.file ?? fileName}`,
DEFAULT_BUCKET!,
`${basePath}${body.file ?? fileName}`,
),
};
}
: this.setStatus(HttpStatusCode.NO_CONTENT);
}
@Delete("/{fileName}")
@Tags("File")
@Security("bearerAuth")
@SuccessResponse(HttpStatusCode.OK)
@Security("bearerAuth", ["admin"])
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
public async deleteFile(
@Path() cabinetName: string,
@Path() drawerName: string,
@Path() folderName: string,
@Path() fileName: string,
) {
const result = await esClient
.deleteByQuery({
index: process.env.ELASTICSEARCH_INDEX ?? "ehr-index",
query: {
match: {
pathname: `${cabinetName}/${drawerName}/${folderName}/${fileName}`,
},
},
})
.catch((e) => console.error(e));
if (result && result.total === 0) {
throw new HttpError(HttpStatusCode.NOT_FOUND, "Data not found");
}
if (!result) {
throw new Error("An error occured, cannot perform this action.");
}
await minioClient.removeObject("ehr", `${cabinetName}/${drawerName}/${folderName}/${fileName}`);
await minioClient.removeObject(
DEFAULT_BUCKET!,
`${cabinetName}/${drawerName}/${folderName}/${fileName}`,
);
return this.setStatus(HttpStatusCode.NO_CONTENT);
}
@Get("/{fileName}")
@Tags("File")
@SuccessResponse(HttpStatusCode.OK)
@Tags("Download")
@Security("bearerAuth")
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
public async downloadFile(
@Path() cabinetName: string,
@Path() drawerName: string,
@ -260,7 +269,7 @@ export class FileController extends Controller {
@Path() fileName: string,
) {
const search = await esClient.search<EhrFile & { attachment: Record<string, string> }>({
index: process.env.ELASTICSEARCH_INDEX ?? "ehr-index",
index: DEFAULT_INDEX!,
query: {
match: { pathname: `${cabinetName}/${drawerName}/${folderName}/${fileName}` },
},
@ -270,43 +279,14 @@ export class FileController extends Controller {
throw new HttpError(HttpStatusCode.NOT_FOUND, "Not found");
}
const data = search.hits.hits[0]._source;
if (!data) {
throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "Found data but no info.");
}
const { attachment, ...rest } = data;
const { attachment, ...rest } = search.hits.hits[0]._source!;
return {
...rest,
download: await minioClient.presignedGetObject(
"ehr",
DEFAULT_BUCKET!,
`${cabinetName}/${drawerName}/${folderName}/${fileName}`,
),
};
}
}
async function popInfo(pathname: string) {
const result = await esClient
.search<EhrFile & { attachment?: Record<string, unknown> }>({
index: DEFAULT_INDEX!,
query: { match: { pathname } },
})
.catch((e) => console.error(e));
// pathname is unique and should not have multiple record with same path
if (result && result.hits.hits.length > 0 && result.hits.hits[0]._source) {
await esClient
.delete({
index: DEFAULT_INDEX!,
id: result.hits.hits[0]._id,
})
.catch((e) => console.error(e));
return result.hits.hits[0]._source;
}
return false;
}