fix: path leading slash and remove unused endpoint
This commit is contained in:
parent
d1abd6684e
commit
51528afc74
12 changed files with 295 additions and 5364 deletions
|
|
@ -1,218 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
Request,
|
||||
Response,
|
||||
Example,
|
||||
} from "tsoa";
|
||||
|
||||
import minioClient from "../minio";
|
||||
import esClient from "../elasticsearch";
|
||||
|
||||
import { copyCond, listFolder, listItem, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile, StorageFolder } from "../interfaces/storage-fs";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("cabinet")
|
||||
export class CabinetController extends Controller {
|
||||
@Get("/")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth")
|
||||
@Response(
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR,
|
||||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการตู้เอกสารได้ กรุณาลองใหม่ในภายหลัง",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/",
|
||||
name: "ตู้เอกสาร 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 2/",
|
||||
name: "ตู้เอกสาร 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
])
|
||||
public async listCabinet(): Promise<StorageFolder[]> {
|
||||
const list = await listFolder(DEFAULT_BUCKET!).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
if (!list)
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการตู้เอกสารได้ กรุณาลองใหม่ในภายหลัง");
|
||||
return list;
|
||||
}
|
||||
|
||||
@Post("/")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดกับระบบจัดการไฟล์")
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
public async createCabinet(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "ตู้เอกสาร 1"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
) {
|
||||
const meta = {
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: request.user.preferred_username,
|
||||
};
|
||||
|
||||
const created = await minioClient
|
||||
.putObject(DEFAULT_BUCKET!, `${replaceIllegalChars(body.name)}/.keep`, "", 0, meta)
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("CreateFolder", {
|
||||
pathname: `${replaceIllegalChars(body.name)}/`,
|
||||
name: replaceIllegalChars(body.name),
|
||||
...meta,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Put("/{cabinetName}")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดไม่สามารถย้ายไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async editCabinet(
|
||||
@Path() cabinetName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "ตู้เอกสารใหม่"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
const path = `${cabinetName}/`;
|
||||
const list = await listItem(DEFAULT_BUCKET!, path, true);
|
||||
|
||||
await Promise.all(
|
||||
list.map(async (current) => {
|
||||
if (!current.name) return;
|
||||
|
||||
const base = `${replaceIllegalChars(body.name)}/`;
|
||||
const destination = `${base}${current.name.slice(path.length)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${current.name}`;
|
||||
|
||||
return await minioClient
|
||||
.copyObject(DEFAULT_BUCKET!, destination, source, copyCond)
|
||||
.then(async () => {
|
||||
if (current.name.includes(".keep")) {
|
||||
return await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
}
|
||||
|
||||
const search = await esClient.search<
|
||||
StorageFile & { attachment: Record<string, string> }
|
||||
>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: current.name } },
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) throw new Error("ไม่พบข้อมูลในฐานข้อมูล");
|
||||
|
||||
const data = search.hits.hits[0];
|
||||
|
||||
await esClient.update({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: data._id,
|
||||
doc: {
|
||||
pathname: destination,
|
||||
path: destination.split("/").slice(0, -1).join("/") + "/",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("EditFolder", { from: `${cabinetName}/`, to: `${replaceIllegalChars(body.name)}/` });
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Delete("/{cabinetName}")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteCabinet(@Path() cabinetName: string) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(DEFAULT_BUCKET!, `${cabinetName}/`, true);
|
||||
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.name) objects.push(v.name);
|
||||
});
|
||||
stream.on("close", async () =>
|
||||
resolve(await minioClient.removeObjects(DEFAULT_BUCKET!, objects)),
|
||||
);
|
||||
stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")));
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("DeleteFolder", { pathname: `${cabinetName}/` });
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Get("/{cabinetName}/size")
|
||||
@Tags("ตู้เอกสาร")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async calc(@Path() cabinetName: string) {
|
||||
const list = await listItem(DEFAULT_BUCKET!, `${cabinetName}/`, true).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
|
||||
return { size: list.reduce<number>((a, c) => a + c.size, 0) };
|
||||
}
|
||||
}
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
Request,
|
||||
Response,
|
||||
Example,
|
||||
} from "tsoa";
|
||||
|
||||
import minioClient from "../minio";
|
||||
import esClient from "../elasticsearch";
|
||||
|
||||
import { copyCond, listFolder, listItem, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile, StorageFolder } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("/cabinet/{cabinetName}/drawer")
|
||||
export class DrawerController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth")
|
||||
@Response(
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR,
|
||||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการลิ้นชักได้ กรุณาลองใหม่ในภายหลัง",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/",
|
||||
name: "ลิ้นชัก 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 2/",
|
||||
name: "ลิ้นชัก 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
])
|
||||
public async listDrawer(@Path() cabinetName: string): Promise<StorageFolder[]> {
|
||||
const list = await listFolder(DEFAULT_BUCKET!, `${cabinetName}/`).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
if (!list)
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการลิ้นชักได้ กรุณาลองใหม่ในภายหลัง");
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบลิ้นชัก")
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดกับระบบจัดการไฟล์")
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
public async createDrawer(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Path() cabinetName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "ลิ้นชัก 1"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
) {
|
||||
const basePath = `${cabinetName}/`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างลิ้นชัก");
|
||||
}
|
||||
|
||||
const meta = {
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: request.user.preferred_username,
|
||||
};
|
||||
|
||||
const created = await minioClient
|
||||
.putObject(DEFAULT_BUCKET!, `${basePath}${replaceIllegalChars(body.name)}/.keep`, "", 0, meta)
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("CreateFolder", {
|
||||
pathname: `${basePath}${replaceIllegalChars(body.name)}/`,
|
||||
name: replaceIllegalChars(body.name),
|
||||
...meta,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Put("/{drawerName}")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดไม่สามารถย้ายไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async editDrawer(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "ลิ้นชักใหม่"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
const path = `${cabinetName}/${drawerName}/`;
|
||||
const list = await listItem(DEFAULT_BUCKET!, path, true);
|
||||
|
||||
await Promise.all(
|
||||
list.map(async (current) => {
|
||||
if (!current.name) return;
|
||||
|
||||
const base = `${cabinetName}/${replaceIllegalChars(body.name)}/`;
|
||||
const destination = `${base}${current.name.slice(path.length)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${current.name}`;
|
||||
|
||||
return await minioClient
|
||||
.copyObject(DEFAULT_BUCKET!, destination, source, copyCond)
|
||||
.then(async () => {
|
||||
if (current.name.includes(".keep")) {
|
||||
return await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
}
|
||||
|
||||
const search = await esClient.search<
|
||||
StorageFile & { attachment: Record<string, string> }
|
||||
>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: current.name } },
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) throw new Error("ไม่พบข้อมูลในฐานข้อมูล");
|
||||
|
||||
const data = search.hits.hits[0];
|
||||
|
||||
await esClient.update({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: data._id,
|
||||
doc: {
|
||||
pathname: destination,
|
||||
path: destination.split("/").slice(0, -1).join("/") + "/",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("EditFolder", {
|
||||
from: `${cabinetName}/${drawerName}/`,
|
||||
to: `${cabinetName}/${replaceIllegalChars(body.name)}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Delete("/{drawerName}")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteDrawer(@Path() cabinetName: string, @Path() drawerName: string) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/`,
|
||||
true,
|
||||
);
|
||||
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.name) objects.push(v.name);
|
||||
});
|
||||
stream.on("close", async () =>
|
||||
resolve(await minioClient.removeObjects(DEFAULT_BUCKET!, objects)),
|
||||
);
|
||||
stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")));
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("DeleteFolder", {
|
||||
pathname: `${cabinetName}/${drawerName}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Get("/{drawerName}/size")
|
||||
@Tags("ลิ้นชัก")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async calc(@Path() cabinetName: string, @Path() drawerName: string) {
|
||||
const list = await listItem(DEFAULT_BUCKET!, `${cabinetName}/${drawerName}/`, true).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
|
||||
return { size: list.reduce<number>((a, c) => a + c.size, 0) };
|
||||
}
|
||||
}
|
||||
|
|
@ -1,438 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Example,
|
||||
Get,
|
||||
Patch,
|
||||
Path,
|
||||
Post,
|
||||
Request,
|
||||
Response,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
} from "tsoa";
|
||||
|
||||
import esClient from "../elasticsearch";
|
||||
import minioClient from "../minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
|
||||
import { copyCond, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/file")
|
||||
export class FileController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
},
|
||||
])
|
||||
public async getFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
): Promise<StorageFile[]> {
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: {
|
||||
path: `${cabinetName}/${drawerName}/${folderName}/`,
|
||||
},
|
||||
},
|
||||
size: 10000,
|
||||
});
|
||||
|
||||
const records = search.hits.hits
|
||||
.map((v) => {
|
||||
if (v._source) {
|
||||
const { attachment, ...rest } = v._source;
|
||||
return rest satisfies StorageFile;
|
||||
}
|
||||
})
|
||||
.filter((v: StorageFile | undefined): v is StorageFile => !!v);
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(
|
||||
HttpStatusCode.NOT_FOUND,
|
||||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
})
|
||||
public async uploadFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสาร 1"
|
||||
*/
|
||||
file: string;
|
||||
/**
|
||||
* @example "เอกสาร"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
) {
|
||||
if (body.file.length > 85) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ชื่อไฟล์ยาวเกินกำหนด");
|
||||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/`;
|
||||
const pathname = `${basePath}${replaceIllegalChars(body.file)}`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(
|
||||
HttpStatusCode.NOT_FOUND,
|
||||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
);
|
||||
}
|
||||
|
||||
const result = await esClient
|
||||
.search<StorageFile & { 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.length > 0 ? result.hits.hits[0]._source : false;
|
||||
|
||||
const metadata: Partial<StorageFile> = {
|
||||
pathname,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(body.file),
|
||||
fileSize: 0,
|
||||
fileType: "",
|
||||
title: body.title ?? "",
|
||||
description: body.description ?? "",
|
||||
category: body.category ?? [],
|
||||
keyword: body.keyword ?? [],
|
||||
upload: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: rec ? rec.createdBy : "n/a",
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
|
||||
await esClient.index({
|
||||
index: DEFAULT_INDEX!,
|
||||
document: metadata,
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUploadRequest", metadata);
|
||||
|
||||
return {
|
||||
...body,
|
||||
createdAt: metadata.createdAt,
|
||||
createdBy: metadata.createdBy,
|
||||
updatedAt: metadata.updatedAt,
|
||||
updatedBy: metadata.updatedBy,
|
||||
upload: await minioClient.presignedPutObject(DEFAULT_BUCKET!, pathname),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Patch("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างแฟ้ม")
|
||||
@Response(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async updateFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() fileName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสารใหม่"
|
||||
*/
|
||||
file?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงินฉบับใหม่"
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
): Promise<void | { upload: string }> {
|
||||
if (body.file && body.file.length > 85) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ชื่อไฟล์ยาวเกินกำหนด");
|
||||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/`;
|
||||
const pathname = `${basePath}${fileName}`;
|
||||
|
||||
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, "ไม่พบไฟล์");
|
||||
}
|
||||
|
||||
const { file, ...metadata } = body;
|
||||
|
||||
// assume user will probably replace file by re-upload but maybe just rename
|
||||
if (file) {
|
||||
const destination = `${basePath}${replaceIllegalChars(file)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${basePath}${fileName}`;
|
||||
const copy = await minioClient.copyObject(DEFAULT_BUCKET!, destination, source, copyCond);
|
||||
|
||||
if (copy) {
|
||||
const search = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (search && search.hits.hits.length > 0 && search.hits.hits[0]._source) {
|
||||
const { _index: index, _id: id } = search.hits.hits[0];
|
||||
const meta = {
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
await esClient
|
||||
.update({
|
||||
index,
|
||||
id,
|
||||
doc: {
|
||||
...metadata,
|
||||
pathname: destination,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(file),
|
||||
...meta,
|
||||
},
|
||||
refresh: "wait_for",
|
||||
})
|
||||
.then(() => minioClient.removeObject(DEFAULT_BUCKET!, pathname));
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUpdateMove", {
|
||||
from: search.hits.hits[0]._source,
|
||||
to: {
|
||||
...search.hits.hits[0]._source,
|
||||
...metadata,
|
||||
pathname: destination,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(file),
|
||||
...meta,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, pathname);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const search = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (search && search.hits.hits.length > 0 && search.hits.hits[0]._source) {
|
||||
const { _index: index, _id: id } = search.hits.hits[0];
|
||||
const meta = {
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
await esClient.update({
|
||||
index,
|
||||
id,
|
||||
doc: { ...metadata, ...meta },
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
const updated: StorageFile = {
|
||||
...search.hits.hits[0]._source,
|
||||
...metadata,
|
||||
...meta,
|
||||
};
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUpdate", updated);
|
||||
}
|
||||
}
|
||||
|
||||
return body.file
|
||||
? {
|
||||
upload: await minioClient.presignedPutObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${basePath}${replaceIllegalChars(body.file) ?? fileName}`,
|
||||
),
|
||||
}
|
||||
: this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example fileName "เอกสารใหม่"
|
||||
*/
|
||||
@Delete("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async deleteFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() fileName: string,
|
||||
) {
|
||||
await minioClient.removeObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${fileName}`,
|
||||
);
|
||||
await esClient.deleteByQuery({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: { pathname: `${cabinetName}/${drawerName}/${folderName}/${fileName}` },
|
||||
},
|
||||
});
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example fileName "เอกสารใหม่"
|
||||
*/
|
||||
@Get("/{fileName}")
|
||||
@Tags("ดาวน์โหลด")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async downloadFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() fileName: string,
|
||||
) {
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: { pathname: `${cabinetName}/${drawerName}/${folderName}/${fileName}` },
|
||||
},
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
const { attachment, ...rest } = search.hits.hits[0]._source!;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
download: await minioClient.presignedGetObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${fileName}`,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
Request,
|
||||
Response,
|
||||
Example,
|
||||
} from "tsoa";
|
||||
|
||||
import minioClient from "../minio";
|
||||
import esClient from "../elasticsearch";
|
||||
|
||||
import { copyCond, listFolder, listItem, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile, StorageFolder } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("/cabinet/{cabinetName}/drawer/{drawerName}/folder")
|
||||
export class FolderController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth")
|
||||
@Response(
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR,
|
||||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1",
|
||||
name: "แฟ้ม 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 2",
|
||||
name: "แฟ้ม 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
])
|
||||
public async listFolder(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
): Promise<StorageFolder[]> {
|
||||
const list = await listFolder(DEFAULT_BUCKET!, `${cabinetName}/${drawerName}`).catch((e) =>
|
||||
console.error(`Error List Folder: ${e}`),
|
||||
);
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างแฟ้ม")
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดกับระบบจัดการไฟล์")
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
public async createFolder(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "แฟ้ม 1"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
) {
|
||||
const basePath = `${cabinetName}/${drawerName}/`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างลิ้นชัก");
|
||||
}
|
||||
|
||||
const meta = {
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: request.user.preferred_username,
|
||||
};
|
||||
|
||||
const created = await minioClient
|
||||
.putObject(DEFAULT_BUCKET!, `${basePath}${replaceIllegalChars(body.name)}/.keep`, "", 0, meta)
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("CreateFolder", {
|
||||
pathname: `${basePath}${replaceIllegalChars(body.name)}/`,
|
||||
name: replaceIllegalChars(body.name),
|
||||
...meta,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Put("/{folderName}")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดไม่สามารถย้ายไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async editFolder(
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "แฟ้มใหม่"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
) {
|
||||
const path = `${cabinetName}/${drawerName}/${folderName}/`;
|
||||
const list = await listItem(DEFAULT_BUCKET!, path, true);
|
||||
|
||||
await Promise.all(
|
||||
list.map(async (current) => {
|
||||
if (!current.name) return;
|
||||
|
||||
const base = `${cabinetName}/${drawerName}/${replaceIllegalChars(body.name)}/`;
|
||||
const destination = `${base}${current.name.slice(path.length)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${current.name}`;
|
||||
|
||||
return await minioClient
|
||||
.copyObject(DEFAULT_BUCKET!, destination, source, copyCond)
|
||||
.then(async () => {
|
||||
if (current.name.includes(".keep")) {
|
||||
return await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
}
|
||||
|
||||
const search = await esClient.search<
|
||||
StorageFile & { attachment: Record<string, string> }
|
||||
>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: current.name } },
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) throw new Error("ไม่พบข้อมูลในฐานข้อมูล");
|
||||
|
||||
const data = search.hits.hits[0];
|
||||
|
||||
await esClient.update({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: data._id,
|
||||
doc: {
|
||||
pathname: destination,
|
||||
path: destination.split("/").slice(0, -1).join("/") + "/",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("EditFolder", {
|
||||
from: `${cabinetName}/${drawerName}/${folderName}/`,
|
||||
to: `${cabinetName}/${drawerName}/${replaceIllegalChars(body.name)}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Delete("/{folderName}")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteFolder(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}`,
|
||||
true,
|
||||
);
|
||||
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.name) objects.push(v.name);
|
||||
});
|
||||
stream.on("close", async () =>
|
||||
resolve(await minioClient.removeObjects(DEFAULT_BUCKET!, objects)),
|
||||
);
|
||||
stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")));
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("DeleteFolder", { pathname: `${cabinetName}/${drawerName}/${folderName}/` });
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Get("/{folderName}/size")
|
||||
@Tags("แฟ้ม")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async calc(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
) {
|
||||
const list = await listItem(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/`,
|
||||
true,
|
||||
).catch((e) => console.error(`Error List Folder: ${e}`));
|
||||
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
|
||||
return { size: list.reduce<number>((a, c) => a + c.size, 0) };
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified."
|
|||
@Route("/search")
|
||||
export class SearchController extends Controller {
|
||||
@Post("/")
|
||||
@Tags("ค้นหา")
|
||||
@Tags("Search")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async searchFile(@Body() search: Search): Promise<StorageFile[]> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
Post,
|
||||
Put,
|
||||
Request,
|
||||
Response,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
|
|
@ -114,6 +115,10 @@ interface DownloadFileBody {
|
|||
file: string;
|
||||
}
|
||||
|
||||
function stripLeadingSlash(str: string) {
|
||||
return str.replace(/^\//, "");
|
||||
}
|
||||
|
||||
async function folderSize(path: string[]) {
|
||||
const size = await new Promise<number>((resolve, reject) => {
|
||||
const stream = minioClient.listObjectsV2(
|
||||
|
|
@ -138,7 +143,7 @@ async function listFolder(path: string[], hidden: boolean = false) {
|
|||
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET,
|
||||
path.length === 0 ? "" : path.join("/") + "/",
|
||||
stripLeadingSlash(`${path.join("/")}/`),
|
||||
);
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.prefix)
|
||||
|
|
@ -182,7 +187,7 @@ async function listFile(path: string[], hidden: boolean = false) {
|
|||
sort: [{ pathname: "asc" }],
|
||||
query: {
|
||||
bool: {
|
||||
must: { match: { path: path.join("/") + "/" } },
|
||||
must: { match: { path: stripLeadingSlash(`${path.join("/")}/`) } },
|
||||
must_not: !hidden ? { match: { hidden: true } } : undefined,
|
||||
},
|
||||
},
|
||||
|
|
@ -202,14 +207,14 @@ async function listFile(path: string[], hidden: boolean = false) {
|
|||
return records;
|
||||
}
|
||||
|
||||
async function checkPathExist(bucket: string, path: string) {
|
||||
if (path.split("/").filter(Boolean).length === 0) return true; // root does not contain any mark
|
||||
return await checkFileExist(bucket, `${path}/.keep`);
|
||||
async function checkPathExist(bucket: string, path: string[]) {
|
||||
if (path.filter(Boolean).length === 0) return true; // root does not contain any mark
|
||||
return await checkFileExist(bucket, `${path.filter(Boolean).join("/")}/.keep`);
|
||||
}
|
||||
|
||||
async function checkFileExist(bucket: string, pathname: string) {
|
||||
return Boolean(
|
||||
await minioClient.statObject(bucket, pathname).catch((e) => {
|
||||
await minioClient.statObject(bucket, stripLeadingSlash(pathname)).catch((e) => {
|
||||
if (e.code === "NotFound") return false;
|
||||
console.error(`Storage Error: ${e}`);
|
||||
throw new Error(MINIO_ERROR_MESSAGE);
|
||||
|
|
@ -219,16 +224,21 @@ async function checkFileExist(bucket: string, pathname: string) {
|
|||
|
||||
@Route("storage")
|
||||
export class StorageController extends Controller {
|
||||
/**
|
||||
* @summary แสดงรายการแฟ้มหรือไฟล์
|
||||
*/
|
||||
@Post("list")
|
||||
@Tags("Storage Folder", "Storage File")
|
||||
@Security("bearerAuth")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
name: "แฟ้ม 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 2",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 2/",
|
||||
name: "แฟ้ม 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
|
|
@ -243,6 +253,7 @@ export class StorageController extends Controller {
|
|||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
hidden: false,
|
||||
fileName: "เอกสาร 1.pdf",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
|
|
@ -252,15 +263,21 @@ export class StorageController extends Controller {
|
|||
updatedBy: "admin",
|
||||
},
|
||||
])
|
||||
@Tags("Storage Folder", "Storage File")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async getList(@Body() body: ListRequestBody) {
|
||||
const path = body.path.filter(Boolean);
|
||||
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
|
||||
if (body.operation === "folder") return await listFolder(path, body.hidden);
|
||||
if (body.operation === "file") return await listFile(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary สร้างแฟ้ม
|
||||
*/
|
||||
@Post("folder")
|
||||
@Tags("Storage Folder")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
|
|
@ -271,7 +288,7 @@ export class StorageController extends Controller {
|
|||
) {
|
||||
const { path, name } = body;
|
||||
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path.join("/")))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
|
||||
|
|
@ -283,7 +300,7 @@ export class StorageController extends Controller {
|
|||
const created = await minioClient
|
||||
.putObject(
|
||||
DEFAULT_BUCKET,
|
||||
`${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/.keep`,
|
||||
stripLeadingSlash(`${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/.keep`),
|
||||
"",
|
||||
0,
|
||||
meta,
|
||||
|
|
@ -293,7 +310,9 @@ export class StorageController extends Controller {
|
|||
if (!created) throw new Error(MINIO_ERROR_MESSAGE);
|
||||
|
||||
io.getInstance()?.emit("FolderCreate", {
|
||||
pathname: `${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/`,
|
||||
pathname: stripLeadingSlash(
|
||||
`${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/`,
|
||||
),
|
||||
name: name.replace(/[/\\?%*:|"<>#]/g, "-").trim(),
|
||||
...meta,
|
||||
});
|
||||
|
|
@ -302,23 +321,26 @@ export class StorageController extends Controller {
|
|||
}
|
||||
|
||||
/**
|
||||
* ยา้ย Folder ภายใต้ Folder (Path) หนึ่ง ไปภายใน Folder (Path) หนึ่งและสามารถเปลี่ยนชื่อได้
|
||||
* ยา้ยแฟ้มภายในตำแหน่งหนึ่งไปภายในอีกแฟ้มหนึ่ง
|
||||
* หรือเปลี่ยนชื่อได้
|
||||
*
|
||||
* @summary ยา้ยแฟ้ม
|
||||
*/
|
||||
@Put("folder")
|
||||
@Tags("Storage Folder")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async moveFolder(@Body() body: PutFolderBody) {
|
||||
const src = `${body.from.path.join("/")}/${body.from.name}`;
|
||||
const dst = `${body.to.path.join("/")}/${body.to.name}`;
|
||||
const src = stripLeadingSlash(`${body.from.path.join("/")}/${body.from.name}`);
|
||||
const dst = stripLeadingSlash(`${body.to.path.join("/")}/${body.to.name}`);
|
||||
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, src))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, src.split("/")))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
if (await checkPathExist(DEFAULT_BUCKET, dst)) {
|
||||
if (await checkPathExist(DEFAULT_BUCKET, dst.split("/"))) {
|
||||
throw new HttpError(HttpStatusCode.CONFLICT, PATH_ALREADY_EXIST);
|
||||
}
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, body.to.path.join("/")))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, body.to.path))) {
|
||||
throw new HttpError(HttpStatusCode.PRECONDITION_FAILED, "ไม่พบตำแหน่งที่ต้องการย้าย");
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +358,7 @@ export class StorageController extends Controller {
|
|||
await Promise.all(
|
||||
list.map(async (v) => {
|
||||
const from = `/${DEFAULT_BUCKET}/${v.pathname}`;
|
||||
const to = `${dst}/${v.pathname.slice(`${src}/`.length)}`;
|
||||
const to = stripLeadingSlash(`${dst}/${v.pathname.slice(`${src}/`.length)}`);
|
||||
|
||||
const result = await minioClient
|
||||
.copyObject(DEFAULT_BUCKET, to, from, copyCond)
|
||||
|
|
@ -376,7 +398,7 @@ export class StorageController extends Controller {
|
|||
id: data._id,
|
||||
doc: {
|
||||
pathname: to,
|
||||
path: to.split("/").slice(0, -1).join("/") + "/",
|
||||
path: stripLeadingSlash(`${to.split("/").slice(0, -1).join("/")}/`),
|
||||
},
|
||||
refresh: "wait_for",
|
||||
})
|
||||
|
|
@ -390,8 +412,8 @@ export class StorageController extends Controller {
|
|||
);
|
||||
|
||||
io.getInstance()?.emit("FolderMove", {
|
||||
from: `${src}/`,
|
||||
to: `${dst}/`,
|
||||
from: stripLeadingSlash(`${src}/`),
|
||||
to: stripLeadingSlash(`${dst}/`),
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
|
|
@ -400,6 +422,10 @@ export class StorageController extends Controller {
|
|||
@Post("folder/size")
|
||||
@Tags("Storage Folder")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example({
|
||||
size: 10240,
|
||||
})
|
||||
public async folderSize(@Body() body: FolderBody) {
|
||||
return { size: await folderSize([...body.path, body.name]) };
|
||||
}
|
||||
|
|
@ -412,9 +438,17 @@ export class StorageController extends Controller {
|
|||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteStorage(@Body() body: DeleteFolderBody) {
|
||||
if (body.path.length === 0) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ไม่สามารถลบได้");
|
||||
}
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(DEFAULT_BUCKET, body.path.join("/") + "/", true);
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET,
|
||||
stripLeadingSlash(`${body.path.join("/")}/`),
|
||||
true,
|
||||
);
|
||||
|
||||
stream.on("data", (v) => v && v.name && objects.push(v.name));
|
||||
stream.on("close", async () => {
|
||||
|
|
@ -435,30 +469,53 @@ export class StorageController extends Controller {
|
|||
@Tags("Storage File")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1.pdf",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
hidden: false,
|
||||
fileName: "เอกสาร 1.pdf",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
uploadUrl: "s3.storage.upload",
|
||||
})
|
||||
public async postFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body() body: FileBody,
|
||||
) {
|
||||
const { path, file } = body;
|
||||
const validFileName = file.replace(/[/\\?%*:|"<>#]/g, "-").trim();
|
||||
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path.join("/")))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, path))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||
}
|
||||
|
||||
const result = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: path.join("/") + "/" } },
|
||||
query: {
|
||||
match: {
|
||||
pathname: stripLeadingSlash(`${path.join("/")}/${validFileName}`),
|
||||
},
|
||||
},
|
||||
})
|
||||
.catch((e) => console.error(`MinIO Error: ${e}`));
|
||||
|
||||
const metadata: StorageFile = {
|
||||
path: path.join("/") + "/",
|
||||
pathname: path.join("/") + "/" + file.replace(/[/\\?%*:|"<>#]/g, "-").trim(),
|
||||
fileName: file.replace(/[/\\?%*:|"<>#]/g, "-").trim(),
|
||||
path: stripLeadingSlash(`${path.join("/")}/`),
|
||||
pathname: stripLeadingSlash(`${path.join("/")}/${validFileName}`),
|
||||
fileName: validFileName,
|
||||
fileSize: 0, // Will be get by minio object storage after file is uploaded
|
||||
fileType: "", // Will be determined by minio object storage after file is uploaded
|
||||
title: body.title ?? file.replace(/[/\\?%*:|"<>#]/g, "-").trim(), // default to same as filename
|
||||
title: body.title ?? validFileName, // default to same as filename
|
||||
description: body.description ?? "",
|
||||
category: body.category ?? [],
|
||||
keyword: body.keyword ?? [],
|
||||
|
|
@ -504,6 +561,8 @@ export class StorageController extends Controller {
|
|||
@Tags("Storage File")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Response(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
@Example({ uploadUrl: "s3.storage.upload" })
|
||||
public async moveFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body() body: PutFileBody,
|
||||
|
|
@ -512,7 +571,9 @@ export class StorageController extends Controller {
|
|||
.search<StorageFile & { attachment: Record<string, any> }>({
|
||||
index: DEFAULT_INDEX,
|
||||
query: {
|
||||
match: { pathname: body.from.path.join("/") + `/${body.from.file}` },
|
||||
match: {
|
||||
pathname: stripLeadingSlash(`${body.from.path.join("/")}/${body.from.file}`),
|
||||
},
|
||||
},
|
||||
})
|
||||
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
|
||||
|
|
@ -523,7 +584,12 @@ export class StorageController extends Controller {
|
|||
if (search && search.hits.hits.length === 0) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบไฟล์ดังกล่าว");
|
||||
}
|
||||
if (!(await checkFileExist(DEFAULT_BUCKET, body.from.path.join("/") + `/${body.from.file}`))) {
|
||||
if (
|
||||
!(await checkFileExist(
|
||||
DEFAULT_BUCKET,
|
||||
stripLeadingSlash(`${body.from.path.join("/")}/${body.from.file}`),
|
||||
))
|
||||
) {
|
||||
await esClient.delete({
|
||||
index: DEFAULT_INDEX,
|
||||
id: search.hits.hits[0]._id,
|
||||
|
|
@ -531,10 +597,15 @@ export class StorageController extends Controller {
|
|||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบไฟล์ดังกล่าว");
|
||||
}
|
||||
if (body.to && JSON.stringify(body.from) !== JSON.stringify(body.to)) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, body.to.path.join("/")))) {
|
||||
if (!(await checkPathExist(DEFAULT_BUCKET, body.to.path))) {
|
||||
throw new HttpError(HttpStatusCode.PRECONDITION_FAILED, "ไม่พบตำแหน่งที่ต้องการย้าย");
|
||||
}
|
||||
if (await checkFileExist(DEFAULT_BUCKET, body.to.path.join("/") + `/${body.to.file}`)) {
|
||||
if (
|
||||
await checkFileExist(
|
||||
DEFAULT_BUCKET,
|
||||
stripLeadingSlash(`${body.to.path.join("/")}/${body.to.file}`),
|
||||
)
|
||||
) {
|
||||
throw new HttpError(
|
||||
HttpStatusCode.PRECONDITION_FAILED,
|
||||
"พบไฟล์ในต้ำแหน่งปลายทาง ไม่สามารถย้ายได้",
|
||||
|
|
@ -563,7 +634,7 @@ export class StorageController extends Controller {
|
|||
|
||||
if (from && to && JSON.stringify(from) !== JSON.stringify(to)) {
|
||||
const src = [DEFAULT_BUCKET, ...from.path, ""].join("/") + from.file;
|
||||
const dst = to.path.join("/") + `/${to.file}`;
|
||||
const dst = stripLeadingSlash(`${to.path.join("/")}/${to.file}`);
|
||||
|
||||
const result = await minioClient.copyObject(DEFAULT_BUCKET, dst, src, copyCond).catch((e) => {
|
||||
console.error(`MinIO Error: ${e}`);
|
||||
|
|
@ -577,7 +648,7 @@ export class StorageController extends Controller {
|
|||
id: id,
|
||||
doc: {
|
||||
...metadata,
|
||||
path: to.path.join("/") + "/",
|
||||
path: stripLeadingSlash(`${to.path.join("/")}/`),
|
||||
pathname: dst,
|
||||
fileName: to.file,
|
||||
...dateMeta,
|
||||
|
|
@ -586,7 +657,10 @@ export class StorageController extends Controller {
|
|||
})
|
||||
.then(
|
||||
async () =>
|
||||
await minioClient.removeObject(DEFAULT_BUCKET, from.path.join("/") + `/${from.file}`),
|
||||
await minioClient.removeObject(
|
||||
DEFAULT_BUCKET,
|
||||
stripLeadingSlash(`${from.path.join("/")}/${from.file}`),
|
||||
),
|
||||
)
|
||||
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
|
||||
|
||||
|
|
@ -595,7 +669,7 @@ export class StorageController extends Controller {
|
|||
to: {
|
||||
...source,
|
||||
...metadata,
|
||||
path: to.path.join("/") + "/",
|
||||
path: stripLeadingSlash(`${to.path.join("/")}/`),
|
||||
pathname: dst,
|
||||
fileName: to.file,
|
||||
...dateMeta,
|
||||
|
|
@ -633,7 +707,7 @@ export class StorageController extends Controller {
|
|||
});
|
||||
|
||||
if (upload) {
|
||||
const src = from.path.join("/") + `/${from.file}`;
|
||||
const src = stripLeadingSlash(`${from.path.join("/")}/${from.file}`);
|
||||
const presignedUrl = await minioClient.presignedPutObject(DEFAULT_BUCKET, src);
|
||||
return { uploadUrl: presignedUrl };
|
||||
}
|
||||
|
|
@ -650,7 +724,7 @@ export class StorageController extends Controller {
|
|||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteFile(@Body() body: DeleteFileBody) {
|
||||
const pathname = body.path.join("/") + `/${body.file}`;
|
||||
const pathname = stripLeadingSlash(`${body.path.join("/")}/${body.file}`);
|
||||
|
||||
await minioClient
|
||||
.removeObject(DEFAULT_BUCKET, pathname)
|
||||
|
|
@ -671,8 +745,26 @@ export class StorageController extends Controller {
|
|||
@Tags("Download")
|
||||
@Security("bearerAuth", ["management-role", "admin"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1.pdf",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
hidden: false,
|
||||
fileName: "เอกสาร 1.pdf",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
downloadUrl: "s3.storage.download",
|
||||
})
|
||||
public async downloadFile(@Body() body: DownloadFileBody) {
|
||||
const pathname = body.path.join("/") + `/${body.file}`;
|
||||
const pathname = stripLeadingSlash(`${body.path.join("/")}/${body.file}`);
|
||||
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX,
|
||||
|
|
|
|||
|
|
@ -1,270 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
Request,
|
||||
Response,
|
||||
Example,
|
||||
} from "tsoa";
|
||||
|
||||
import minioClient from "../minio";
|
||||
import esClient from "../elasticsearch";
|
||||
|
||||
import { copyCond, listFolder, listItem, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile, StorageFolder } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder")
|
||||
export class SubFolderController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth")
|
||||
@Response(
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR,
|
||||
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1",
|
||||
name: "แฟ้มย่อย 1",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
{
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 2",
|
||||
name: "แฟ้มย่อย 2",
|
||||
createdAt: "2022-01-23T16:05:02.114Z",
|
||||
createdBy: "admin",
|
||||
},
|
||||
])
|
||||
public async listFolder(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
): Promise<StorageFolder[]> {
|
||||
const list = await listFolder(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}`,
|
||||
).catch((e) => console.error(`Error List Folder: ${e}`));
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบของแฟ้ม")
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดกับระบบจัดการไฟล์")
|
||||
@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,
|
||||
) {
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างลิ้นชัก");
|
||||
}
|
||||
const meta = {
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: request.user.preferred_username,
|
||||
};
|
||||
|
||||
const created = await minioClient
|
||||
.putObject(DEFAULT_BUCKET!, `${basePath}${replaceIllegalChars(body.name)}/.keep`, "", 0, meta)
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("CreateFolder", {
|
||||
pathname: `${basePath}${replaceIllegalChars(body.name)}/`,
|
||||
name: replaceIllegalChars(body.name),
|
||||
...meta,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Put("/{subFolderName}")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดไม่สามารถย้ายไฟล์ได้")
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async editFolder(
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "แฟ้มใหม่"
|
||||
*/
|
||||
name: string;
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
) {
|
||||
const path = `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`;
|
||||
const list = await listItem(DEFAULT_BUCKET!, path, true);
|
||||
|
||||
await Promise.all(
|
||||
list.map(async (current) => {
|
||||
if (!current.name) return;
|
||||
|
||||
const base = `${cabinetName}/${drawerName}/${folderName}/${replaceIllegalChars(
|
||||
body.name,
|
||||
)}/`;
|
||||
const destination = `${base}${current.name.slice(path.length)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${current.name}`;
|
||||
|
||||
return await minioClient
|
||||
.copyObject(DEFAULT_BUCKET!, destination, source, copyCond)
|
||||
.then(async () => {
|
||||
if (current.name.includes(".keep")) {
|
||||
return await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
}
|
||||
|
||||
const search = await esClient.search<
|
||||
StorageFile & { attachment: Record<string, string> }
|
||||
>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname: current.name } },
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) throw new Error("ไม่พบข้อมูลในฐานข้อมูล");
|
||||
|
||||
const data = search.hits.hits[0];
|
||||
|
||||
await esClient.update({
|
||||
index: DEFAULT_INDEX!,
|
||||
id: data._id,
|
||||
doc: {
|
||||
pathname: destination,
|
||||
path: destination.split("/").slice(0, -1).join("/") + "/",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, current.name);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("EditFolder", {
|
||||
from: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`,
|
||||
to: `${cabinetName}/${drawerName}/${folderName}/${replaceIllegalChars(body.name)}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Delete("/{subFolderName}")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||
public async deleteFolder(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const objects: string[] = [];
|
||||
const stream = minioClient.listObjectsV2(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${subFolderName}`,
|
||||
true,
|
||||
);
|
||||
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.name) objects.push(v.name);
|
||||
});
|
||||
stream.on("close", async () =>
|
||||
resolve(await minioClient.removeObjects(DEFAULT_BUCKET!, objects)),
|
||||
);
|
||||
stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้")));
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("DeleteFolder", {
|
||||
pathname: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`,
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Get("/{subFolderName}/size")
|
||||
@Tags("แฟ้มย่อย")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async calc(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
) {
|
||||
const list = await listItem(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${subFolderName}`,
|
||||
true,
|
||||
).catch((e) => console.error(`Error List Folder: ${e}`));
|
||||
|
||||
if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง");
|
||||
|
||||
return { size: list.reduce<number>((a, c) => a + c.size, 0) };
|
||||
}
|
||||
}
|
||||
|
|
@ -1,455 +0,0 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Example,
|
||||
Get,
|
||||
Patch,
|
||||
Path,
|
||||
Post,
|
||||
Request,
|
||||
Response,
|
||||
Route,
|
||||
Security,
|
||||
SuccessResponse,
|
||||
Tags,
|
||||
} from "tsoa";
|
||||
|
||||
import esClient from "../elasticsearch";
|
||||
import minioClient from "../minio";
|
||||
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import { StorageFile } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
|
||||
import { copyCond, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
import { getInstance } from "../lib/websocket";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route(
|
||||
"/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder/{subFolderName}/file",
|
||||
)
|
||||
export class SubFolderFileController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
},
|
||||
])
|
||||
public async getFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
): Promise<StorageFile[]> {
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: {
|
||||
path: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`,
|
||||
},
|
||||
},
|
||||
size: 10000,
|
||||
});
|
||||
|
||||
const records = search.hits.hits
|
||||
.map((v) => {
|
||||
if (v._source) {
|
||||
const { attachment, ...rest } = v._source;
|
||||
return rest satisfies StorageFile;
|
||||
}
|
||||
})
|
||||
.filter((v: StorageFile | undefined): v is StorageFile => !!v);
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(
|
||||
HttpStatusCode.NOT_FOUND,
|
||||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
})
|
||||
public async uploadFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสาร 1"
|
||||
*/
|
||||
file: string;
|
||||
/**
|
||||
* @example "เอกสาร"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
) {
|
||||
if (body.file && body.file.length > 85) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ชื่อไฟล์ยาวเกินกำหนด");
|
||||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`;
|
||||
const pathname = `${basePath}${replaceIllegalChars(body.file)}`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(
|
||||
HttpStatusCode.NOT_FOUND,
|
||||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
);
|
||||
}
|
||||
|
||||
const result = await esClient
|
||||
.search<StorageFile & { 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.length > 0 ? result.hits.hits[0]._source : false;
|
||||
|
||||
const metadata: Partial<StorageFile> = {
|
||||
pathname,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(body.file),
|
||||
fileSize: 0,
|
||||
fileType: "",
|
||||
title: body.title ?? "",
|
||||
description: body.description ?? "",
|
||||
category: body.category ?? [],
|
||||
keyword: body.keyword ?? [],
|
||||
upload: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: rec ? rec.createdBy : "n/a",
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
|
||||
await esClient.index({
|
||||
index: DEFAULT_INDEX!,
|
||||
document: metadata,
|
||||
refresh: "wait_for",
|
||||
});
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUploadRequest", metadata);
|
||||
|
||||
return {
|
||||
...body,
|
||||
createdAt: metadata.createdAt,
|
||||
createdBy: metadata.createdBy,
|
||||
updatedAt: metadata.updatedAt,
|
||||
updatedBy: metadata.updatedBy,
|
||||
upload: await minioClient.presignedPutObject(DEFAULT_BUCKET!, pathname),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Patch("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@Response(HttpStatusCode.NOT_FOUND, "ไม่พบตำแหน่งที่ต้องการสร้างแฟ้ม")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async updateFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
@Path() fileName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสารใหม่"
|
||||
*/
|
||||
file?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงินฉบับใหม่"
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
) {
|
||||
if (body.file && body.file.length > 85) {
|
||||
throw new HttpError(HttpStatusCode.BAD_REQUEST, "ชื่อไฟล์ยาวเกินกำหนด");
|
||||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`;
|
||||
const pathname = `${basePath}${fileName}`;
|
||||
|
||||
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, "ไม่พบไฟล์");
|
||||
}
|
||||
|
||||
const { file, ...metadata } = body;
|
||||
|
||||
// assume user will probably replace file by re-upload but maybe just rename
|
||||
if (file) {
|
||||
const destination = `${basePath}${replaceIllegalChars(file)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${basePath}${fileName}`;
|
||||
const copy = await minioClient.copyObject(DEFAULT_BUCKET!, destination, source, copyCond);
|
||||
|
||||
if (copy) {
|
||||
const search = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
const meta = {
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
if (search && search.hits.hits.length > 0 && search.hits.hits[0]._source) {
|
||||
const { _index: index, _id: id } = search.hits.hits[0];
|
||||
await esClient
|
||||
.update({
|
||||
index,
|
||||
id,
|
||||
doc: {
|
||||
...metadata,
|
||||
pathname: destination,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(file),
|
||||
...meta,
|
||||
},
|
||||
refresh: "wait_for",
|
||||
})
|
||||
.then(() => minioClient.removeObject(DEFAULT_BUCKET!, pathname));
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUpdateMove", {
|
||||
from: search.hits.hits[0]._source,
|
||||
to: {
|
||||
...search.hits.hits[0]._source,
|
||||
...metadata,
|
||||
pathname: destination,
|
||||
path: basePath,
|
||||
fileName: replaceIllegalChars(file),
|
||||
...meta,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await minioClient.removeObject(DEFAULT_BUCKET!, pathname);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const search = await esClient
|
||||
.search<StorageFile & { attachment?: Record<string, unknown> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: { match: { pathname } },
|
||||
})
|
||||
.catch((e) => console.error(e));
|
||||
|
||||
if (search && search.hits.hits.length > 0 && search.hits.hits[0]._source) {
|
||||
const { _index: index, _id: id } = search.hits.hits[0];
|
||||
const meta = {
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
};
|
||||
await esClient.update({
|
||||
index,
|
||||
id,
|
||||
doc: {
|
||||
...metadata,
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
},
|
||||
refresh: "wait_for",
|
||||
});
|
||||
const updated: StorageFile = {
|
||||
...search.hits.hits[0]._source,
|
||||
...metadata,
|
||||
...meta,
|
||||
};
|
||||
|
||||
const io = getInstance();
|
||||
io?.emit("FileUpdate", updated);
|
||||
}
|
||||
}
|
||||
|
||||
return body.file
|
||||
? {
|
||||
upload: await minioClient.presignedPutObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${basePath}${replaceIllegalChars(body.file) ?? fileName}`,
|
||||
),
|
||||
}
|
||||
: this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Delete("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin", "management-role"])
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
public async deleteFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
@Path() fileName: string,
|
||||
) {
|
||||
await minioClient.removeObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${subFolderName}/${fileName}`,
|
||||
);
|
||||
await esClient.deleteByQuery({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: {
|
||||
pathname: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/${fileName}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example folderName "แฟ้มย่อย 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Get("/{fileName}")
|
||||
@Tags("ดาวน์โหลด")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK)
|
||||
public async downloadFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
@Path() folderName: string,
|
||||
@Path() subFolderName: string,
|
||||
@Path() fileName: string,
|
||||
) {
|
||||
const search = await esClient.search<StorageFile & { attachment: Record<string, string> }>({
|
||||
index: DEFAULT_INDEX!,
|
||||
query: {
|
||||
match: {
|
||||
pathname: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/${fileName}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (search && search.hits.hits.length === 0) {
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "Not found");
|
||||
}
|
||||
|
||||
const { attachment, ...rest } = search.hits.hits[0]._source!;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
download: await minioClient.presignedGetObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${cabinetName}/${drawerName}/${folderName}/${subFolderName}/${fileName}`,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ async function handleNotFoundRecord(
|
|||
buffer: Buffer,
|
||||
stat: { size: number; type: string },
|
||||
) {
|
||||
const path = pathname.split("/").slice(0, -1).join("/") + "/";
|
||||
const path = stripLeadingSlash(pathname.split("/").slice(0, -1).join("/") + "/");
|
||||
const filename = pathname.split("/").at(-1);
|
||||
const base64 = Buffer.from(buffer).toString("base64");
|
||||
|
||||
|
|
@ -175,3 +175,7 @@ async function handleFoundRecord(
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
function stripLeadingSlash(str: string) {
|
||||
return str.replace(/^\//, "");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,10 @@
|
|||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { Controller, ValidationService, FieldErrors, ValidateError, TsoaRoute, HttpStatusCodeLiteral, TsoaResponse, fetchMiddlewares } from '@tsoa/runtime';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { CabinetController } from './controllers/cabinetController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { DrawerController } from './controllers/drawerController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { FileController } from './controllers/fileController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { FolderController } from './controllers/folderController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { SearchController } from './controllers/searchController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { StorageController } from './controllers/storageController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { SubFolderController } from './controllers/subFolderController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { SubFolderFileController } from './controllers/subFolderFileController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { VersionController } from './controllers/versionController';
|
||||
import { expressAuthentication } from './utils/auth';
|
||||
// @ts-ignore - no great way to install types from subpackage
|
||||
|
|
@ -28,17 +16,6 @@ import type { RequestHandler, Router } from 'express';
|
|||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
const models: TsoaRoute.Models = {
|
||||
"StorageFolder": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
"pathname": {"dataType":"string","required":true},
|
||||
"name": {"dataType":"string","required":true},
|
||||
"createdAt": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||
"createdBy": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||
},
|
||||
"additionalProperties": false,
|
||||
},
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
"StorageFile": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
|
|
@ -71,6 +48,17 @@ const models: TsoaRoute.Models = {
|
|||
"additionalProperties": false,
|
||||
},
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
"StorageFolder": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
"pathname": {"dataType":"string","required":true},
|
||||
"name": {"dataType":"string","required":true},
|
||||
"createdAt": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||
"createdBy": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||
},
|
||||
"additionalProperties": false,
|
||||
},
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
"ListRequestBody": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
|
|
@ -124,11 +112,11 @@ const models: TsoaRoute.Models = {
|
|||
"PutFileBody": {
|
||||
"dataType": "refObject",
|
||||
"properties": {
|
||||
"hidden": {"dataType":"boolean"},
|
||||
"keyword": {"dataType":"array","array":{"dataType":"string"}},
|
||||
"title": {"dataType":"string"},
|
||||
"description": {"dataType":"string"},
|
||||
"category": {"dataType":"array","array":{"dataType":"string"}},
|
||||
"keyword": {"dataType":"array","array":{"dataType":"string"}},
|
||||
"hidden": {"dataType":"boolean"},
|
||||
"from": {"dataType":"nestedObjectLiteral","nestedProperties":{"file":{"dataType":"string","required":true},"path":{"dataType":"array","array":{"dataType":"string"},"required":true}},"required":true},
|
||||
"to": {"dataType":"nestedObjectLiteral","nestedProperties":{"file":{"dataType":"string","required":true},"path":{"dataType":"array","array":{"dataType":"string"},"required":true}}},
|
||||
"upload": {"dataType":"boolean"},
|
||||
|
|
@ -164,561 +152,6 @@ export function RegisterRoutes(app: Router) {
|
|||
// NOTE: If you do not see routes for all of your controllers in this file, then you might not have informed tsoa of where to look
|
||||
// Please look into the "controllerPathGlobs" config option described in the readme: https://github.com/lukeautry/tsoa
|
||||
// ###########################################################################################################
|
||||
app.get('/cabinet',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.listCabinet)),
|
||||
|
||||
function CabinetController_listCabinet(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.listCabinet.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.createCabinet)),
|
||||
|
||||
function CabinetController_createCabinet(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.createCabinet.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.put('/cabinet/:cabinetName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.editCabinet)),
|
||||
|
||||
function CabinetController_editCabinet(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.editCabinet.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.deleteCabinet)),
|
||||
|
||||
function CabinetController_deleteCabinet(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.deleteCabinet.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/size',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController)),
|
||||
...(fetchMiddlewares<RequestHandler>(CabinetController.prototype.calc)),
|
||||
|
||||
function CabinetController_calc(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new CabinetController();
|
||||
|
||||
|
||||
const promise = controller.calc.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.listDrawer)),
|
||||
|
||||
function DrawerController_listDrawer(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.listDrawer.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.createDrawer)),
|
||||
|
||||
function DrawerController_createDrawer(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.createDrawer.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.put('/cabinet/:cabinetName/drawer/:drawerName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.editDrawer)),
|
||||
|
||||
function DrawerController_editDrawer(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.editDrawer.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.deleteDrawer)),
|
||||
|
||||
function DrawerController_deleteDrawer(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.deleteDrawer.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/size',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController)),
|
||||
...(fetchMiddlewares<RequestHandler>(DrawerController.prototype.calc)),
|
||||
|
||||
function DrawerController_calc(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new DrawerController();
|
||||
|
||||
|
||||
const promise = controller.calc.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.getFile)),
|
||||
|
||||
function FileController_getFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.getFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.uploadFile)),
|
||||
|
||||
function FileController_uploadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.uploadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.patch('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.updateFile)),
|
||||
|
||||
function FileController_updateFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string"}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.updateFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.deleteFile)),
|
||||
|
||||
function FileController_deleteFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.deleteFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FileController.prototype.downloadFile)),
|
||||
|
||||
function FileController_downloadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FileController();
|
||||
|
||||
|
||||
const promise = controller.downloadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.listFolder)),
|
||||
|
||||
function FolderController_listFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.listFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer/:drawerName/folder',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.createFolder)),
|
||||
|
||||
function FolderController_createFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.createFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.put('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.editFolder)),
|
||||
|
||||
function FolderController_editFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.editFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.deleteFolder)),
|
||||
|
||||
function FolderController_deleteFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.deleteFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/size',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(FolderController.prototype.calc)),
|
||||
|
||||
function FolderController_calc(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new FolderController();
|
||||
|
||||
|
||||
const promise = controller.calc.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/search',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SearchController)),
|
||||
|
|
@ -765,7 +198,7 @@ export function RegisterRoutes(app: Router) {
|
|||
|
||||
|
||||
const promise = controller.getList.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, undefined, next);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
|
@ -844,7 +277,7 @@ export function RegisterRoutes(app: Router) {
|
|||
|
||||
|
||||
const promise = controller.folderSize.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, undefined, next);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
|
@ -975,304 +408,6 @@ export function RegisterRoutes(app: Router) {
|
|||
const controller = new StorageController();
|
||||
|
||||
|
||||
const promise = controller.downloadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.listFolder)),
|
||||
|
||||
function SubFolderController_listFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.listFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.createFolder)),
|
||||
|
||||
function SubFolderController_createFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.createFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.put('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.editFolder)),
|
||||
|
||||
function SubFolderController_editFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.editFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.deleteFolder)),
|
||||
|
||||
function SubFolderController_deleteFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.deleteFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/size',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController.prototype.calc)),
|
||||
|
||||
function SubFolderController_calc(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderController();
|
||||
|
||||
|
||||
const promise = controller.calc.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.getFile)),
|
||||
|
||||
function SubFolderFileController_getFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.getFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.uploadFile)),
|
||||
|
||||
function SubFolderFileController_uploadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.uploadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.patch('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.updateFile)),
|
||||
|
||||
function SubFolderFileController_updateFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string"}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.updateFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.delete('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":["admin","management-role"]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.deleteFile)),
|
||||
|
||||
function SubFolderFileController_deleteFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.deleteFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file/:fileName',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController)),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderFileController.prototype.downloadFile)),
|
||||
|
||||
function SubFolderFileController_downloadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new SubFolderFileController();
|
||||
|
||||
|
||||
const promise = controller.downloadFile.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -25,16 +25,7 @@
|
|||
"description": "Keycloak Bearer Token",
|
||||
"in": "header"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{ "name": "ตู้เอกสาร" },
|
||||
{ "name": "ลิ้นชัก" },
|
||||
{ "name": "แฟ้ม" },
|
||||
{ "name": "แฟ้มย่อย" },
|
||||
{ "name": "ไฟล์" },
|
||||
{ "name": "ดาวน์โหลด" },
|
||||
{ "name": "ค้นหา" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"routes": {
|
||||
"routesDir": "src",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue