Merge branch 'feat/storage-endpoint' into development
This commit is contained in:
commit
f0346901df
7 changed files with 1537 additions and 24 deletions
|
|
@ -1,15 +1,25 @@
|
||||||
PUBLIC_KEY=
|
# Keycloak public key
|
||||||
|
PUBLIC_KEY=keycloak.public.key
|
||||||
MINIO_HOST=localhost
|
REALM_URL=https://keycloak.local/realms/EDM
|
||||||
MINIO_PORT=9000
|
PREFERRED_AUTH=online
|
||||||
|
MANAGEMENT_ROLE=doc-management
|
||||||
|
# App port
|
||||||
|
PORT=25570
|
||||||
|
# Real host name must be used.
|
||||||
|
# Sdk will generate presigned url based on host name.
|
||||||
|
MINIO_HOST=minio.local
|
||||||
|
MINIO_PORT=443
|
||||||
|
MINIO_SSL=true
|
||||||
MINIO_ACCESS_KEY=
|
MINIO_ACCESS_KEY=
|
||||||
MINIO_SECRET_KEY=
|
MINIO_SECRET_KEY=
|
||||||
|
# Bucket notification event needed to be configured
|
||||||
|
# Can use prepare script to create bucket
|
||||||
|
MINIO_BUCKET=dev
|
||||||
ELASTICSEARCH_PROTOCOL=http
|
ELASTICSEARCH_PROTOCOL=http
|
||||||
ELASTICSEARCH_HOST=localhost
|
ELASTICSEARCH_HOST=localhost
|
||||||
ELASTICSEARCH_PORT=9200
|
ELASTICSEARCH_PORT=3001
|
||||||
|
# Can use prepare script
|
||||||
|
ELASTICSEARCH_INDEX=dev-index
|
||||||
|
AMQ_URL=amqp://admin:1234@localhost:3002
|
||||||
|
AMQ_QUEUE=queue-name
|
||||||
|
|
||||||
AMQ_URL=amqp://admin:1234@localhost:9999
|
|
||||||
AMQ_QUEUE=queue
|
|
||||||
|
|
||||||
AUTH_BYPASS=false # MUST NOT TURN THIS ON IN PRODUCTION
|
|
||||||
|
|
|
||||||
|
|
@ -42,14 +42,8 @@ const io = new Server(server, {
|
||||||
});
|
});
|
||||||
|
|
||||||
setInstance(io);
|
setInstance(io);
|
||||||
|
io.on("connection", () => console.log("[Socket.IO] User connected."));
|
||||||
io.on("connection", (socket) => {
|
io.on("disconnected", () => console.log("[Socket.IO] User disconnected."));
|
||||||
console.log("User Connected");
|
|
||||||
|
|
||||||
socket.on("disconnected", () => {
|
|
||||||
console.log("User Disconnected");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
server.listen(PORT, "0.0.0.0", () =>
|
server.listen(PORT, "0.0.0.0", () =>
|
||||||
console.log(`[APP] Application is running on http://localhost:${PORT}`),
|
console.log(`[APP] Application is running on http://localhost:${PORT}`),
|
||||||
|
|
|
||||||
614
Services/server/src/controllers/storageController.ts
Normal file
614
Services/server/src/controllers/storageController.ts
Normal file
|
|
@ -0,0 +1,614 @@
|
||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Delete,
|
||||||
|
Example,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Request,
|
||||||
|
Route,
|
||||||
|
Security,
|
||||||
|
SuccessResponse,
|
||||||
|
Tags,
|
||||||
|
} from "tsoa";
|
||||||
|
|
||||||
|
import minioClient from "../minio";
|
||||||
|
import esClient from "../elasticsearch";
|
||||||
|
|
||||||
|
import HttpError from "../interfaces/http-error";
|
||||||
|
import HttpStatusCode from "../interfaces/http-status";
|
||||||
|
import { StorageFile, StorageFolder } from "../interfaces/storage-fs";
|
||||||
|
|
||||||
|
import { copyCond } from "../utils/minio";
|
||||||
|
|
||||||
|
import * as io from "../lib/websocket";
|
||||||
|
|
||||||
|
if (!process.env.MINIO_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||||
|
if (!process.env.ELASTICSEARCH_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||||
|
|
||||||
|
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||||
|
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||||
|
const MINIO_ERROR_MESSAGE = "เกิดข้อผิดพลาดกับระบบจัดการไฟล์";
|
||||||
|
const PATH_NOT_FOUND_MESSAGE = "ไม่พบตำแหน่งที่ต้องการนำข้อมูลเข้า";
|
||||||
|
const PATH_ALREADY_EXIST = "ตำแหน่งดังกล่าวมีในระบบแล้ว";
|
||||||
|
|
||||||
|
interface ListRequestBody {
|
||||||
|
operation: "folder" | "file";
|
||||||
|
path: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FolderBody {
|
||||||
|
/** @example ["แฟ้ม 1", "แฟ้ม 2"] */
|
||||||
|
path: string[];
|
||||||
|
/** @example "แฟ้ม 3" */
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PutFolderBody {
|
||||||
|
from: {
|
||||||
|
/** @example ["แฟ้ม 1", "แฟ้ม 2"] */
|
||||||
|
path: string[];
|
||||||
|
/** @example "แฟ้ม 3" */
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
to: {
|
||||||
|
/** @example ["แฟ้ม 1", "แฟ้ม 2"] */
|
||||||
|
path: string[];
|
||||||
|
/** @example "แฟ้ม 3 แก้ไข" */
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteFolderBody {
|
||||||
|
/** @example ["แฟ้ม 1", "แฟ้ม 2", "แฟ้ม 3 แก้ไข"] */
|
||||||
|
path: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FileBody {
|
||||||
|
/** @example ["แฟ้ม 1", "แฟ้ม 2", "แฟ้ม 3"] */
|
||||||
|
path: string[];
|
||||||
|
/** @example "ไฟล์ 1.xlsx" */
|
||||||
|
file: string;
|
||||||
|
/** @example "การเงิน" */
|
||||||
|
title?: string;
|
||||||
|
/** @example "การเงิน" */
|
||||||
|
description?: string;
|
||||||
|
/** @example ["การเงิน", "รายงาน"] */
|
||||||
|
category?: string[];
|
||||||
|
/** @example ["การเงิน", "รายรับ", "รายจ่าย"] */
|
||||||
|
keyword?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PutFileBody extends Omit<FileBody, "file" | "path"> {
|
||||||
|
/** หากต้องการอัพโหลดไฟล์ด้วยให้ส่งค่าเป็นจริง */
|
||||||
|
from: {
|
||||||
|
/** @example ["แฟ้ม 1", "แฟ้ม 2", "แฟ้ม 3"] */
|
||||||
|
path: string[];
|
||||||
|
/** @example "ไฟล์ 1.xlsx" */
|
||||||
|
file: string;
|
||||||
|
};
|
||||||
|
to?: {
|
||||||
|
/** @example ["แฟ้ม 1", "แฟ้ม 2", "แฟ้ม 3"] */
|
||||||
|
path: string[];
|
||||||
|
/** @example "ไฟล์ 1 แก้ไข.xlsx" */
|
||||||
|
file: string;
|
||||||
|
};
|
||||||
|
/** @example false */
|
||||||
|
upload?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteFileBody {
|
||||||
|
/** @example ["แฟ้ม 1", "แฟ้ม 2", "แฟ้ม 3"] */
|
||||||
|
path: string[];
|
||||||
|
/** @example "ไฟล์ 1 แก้ไข.xlsx" */
|
||||||
|
file: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listFolder(path: string[]) {
|
||||||
|
const list = await new Promise<{ pathname: string; name: string }[]>((resolve, reject) => {
|
||||||
|
const item: { pathname: string; name: string }[] = [];
|
||||||
|
|
||||||
|
const stream = minioClient.listObjectsV2(DEFAULT_BUCKET, path.join("/") + "/");
|
||||||
|
stream.on("data", (v) => {
|
||||||
|
if (v && v.prefix)
|
||||||
|
item.push({
|
||||||
|
pathname: v.prefix,
|
||||||
|
name: v.prefix.split("/").filter(Boolean).at(-1)!,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
stream.on("end", () => resolve(item));
|
||||||
|
stream.on("error", () => reject(new Error(MINIO_ERROR_MESSAGE)));
|
||||||
|
});
|
||||||
|
|
||||||
|
const folder = await Promise.all(
|
||||||
|
list.map(async (v) => {
|
||||||
|
// Get stat from hidden object that used to mark as folder as minio doesn't really have folder
|
||||||
|
const stat = await minioClient
|
||||||
|
.statObject(DEFAULT_BUCKET, `${v.pathname}.keep`)
|
||||||
|
.catch((e) => console.error(`MinIO Error: ${e}`));
|
||||||
|
|
||||||
|
if (!stat) return undefined;
|
||||||
|
|
||||||
|
const { createdat, createdby } = stat.metaData;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...v,
|
||||||
|
createdAt: createdat ?? "n/a",
|
||||||
|
createdBy: createdby ?? "n/a",
|
||||||
|
} satisfies StorageFolder;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return folder.filter((v: StorageFolder | undefined): v is StorageFolder => !!v);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listFile(path: string[]) {
|
||||||
|
const result = await esClient
|
||||||
|
.search<StorageFile & { attachment: Record<string, string> }>({
|
||||||
|
index: DEFAULT_INDEX,
|
||||||
|
sort: [{ pathname: "asc" }],
|
||||||
|
query: { match: { path: path.join("/") + "/" } },
|
||||||
|
size: 10000,
|
||||||
|
})
|
||||||
|
.then((r) => r.hits.hits);
|
||||||
|
|
||||||
|
const records = result
|
||||||
|
.map((v) => {
|
||||||
|
if (v._source) {
|
||||||
|
const { attachment, ...rest } = v._source;
|
||||||
|
return rest satisfies StorageFile;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((v: StorageFile | undefined): v is StorageFile => !!v);
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkPathExist(bucket: string, path: string) {
|
||||||
|
return await checkFileExist(bucket, `${path}/.keep`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkFileExist(bucket: string, pathname: string) {
|
||||||
|
return Boolean(
|
||||||
|
await minioClient.statObject(bucket, pathname).catch((e) => {
|
||||||
|
if (e.code === "NotFound") return false;
|
||||||
|
console.error(`Storage Error: ${e}`);
|
||||||
|
throw new Error(MINIO_ERROR_MESSAGE);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Route("storage")
|
||||||
|
export class StorageController extends Controller {
|
||||||
|
@Post("list")
|
||||||
|
@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",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
@Example([
|
||||||
|
{
|
||||||
|
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1.pdf",
|
||||||
|
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||||
|
title: "เอกสาร",
|
||||||
|
description: "เอกสารการเงิน",
|
||||||
|
category: ["บัญชี"],
|
||||||
|
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||||
|
upload: 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",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
@Tags("Storage Folder", "Storage File")
|
||||||
|
@Security("bearerAuth")
|
||||||
|
public async getList(@Body() body: ListRequestBody) {
|
||||||
|
const path = body.path.filter(Boolean);
|
||||||
|
|
||||||
|
if (body.operation === "folder") return await listFolder(path);
|
||||||
|
if (body.operation === "file") return await listFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("folder")
|
||||||
|
@Tags("Storage Folder")
|
||||||
|
@Security("bearerAuth", ["management-role", "admin"])
|
||||||
|
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||||
|
public async postFolder(
|
||||||
|
@Request() request: { user: { preferred_username: string } },
|
||||||
|
@Body() body: FolderBody,
|
||||||
|
) {
|
||||||
|
const { path, name } = body;
|
||||||
|
|
||||||
|
if (!(await checkPathExist(DEFAULT_BUCKET, path.join("/")))) {
|
||||||
|
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
createdBy: request.user.preferred_username,
|
||||||
|
};
|
||||||
|
|
||||||
|
const created = await minioClient
|
||||||
|
.putObject(
|
||||||
|
DEFAULT_BUCKET,
|
||||||
|
`${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/.keep`,
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
meta,
|
||||||
|
)
|
||||||
|
.catch((e) => console.error(`MinIO Error: ${e}`));
|
||||||
|
|
||||||
|
if (!created) throw new Error(MINIO_ERROR_MESSAGE);
|
||||||
|
|
||||||
|
io.getInstance()?.emit("FolderCreate", {
|
||||||
|
pathname: `${path.join("/")}/${name.replace(/[/\\?%*:|"<>#]/g, "-").trim()}/`,
|
||||||
|
name: name.replace(/[/\\?%*:|"<>#]/g, "-").trim(),
|
||||||
|
...meta,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ยา้ย Folder ภายใต้ Folder (Path) หนึ่ง ไปภายใน Folder (Path) หนึ่งและสามารถเปลี่ยนชื่อได้
|
||||||
|
*/
|
||||||
|
@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}`;
|
||||||
|
|
||||||
|
if (!(await checkPathExist(DEFAULT_BUCKET, src))) {
|
||||||
|
throw new HttpError(HttpStatusCode.NOT_FOUND, PATH_NOT_FOUND_MESSAGE);
|
||||||
|
}
|
||||||
|
if (await checkPathExist(DEFAULT_BUCKET, dst)) {
|
||||||
|
throw new HttpError(HttpStatusCode.CONFLICT, PATH_ALREADY_EXIST);
|
||||||
|
}
|
||||||
|
if (!(await checkPathExist(DEFAULT_BUCKET, body.to.path.join("/")))) {
|
||||||
|
throw new HttpError(HttpStatusCode.PRECONDITION_FAILED, "ไม่พบตำแหน่งที่ต้องการย้าย");
|
||||||
|
}
|
||||||
|
|
||||||
|
const list = await new Promise<{ pathname: string }[]>((resolve, reject) => {
|
||||||
|
const stream = minioClient.listObjectsV2(DEFAULT_BUCKET, `${src}/`, true);
|
||||||
|
const item: { pathname: string }[] = [];
|
||||||
|
|
||||||
|
stream.on("data", (v) => {
|
||||||
|
if (v && v.name) item.push({ pathname: v.name });
|
||||||
|
});
|
||||||
|
stream.on("end", () => resolve(item));
|
||||||
|
stream.on("error", () => reject(new Error(MINIO_ERROR_MESSAGE)));
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
list.map(async (v) => {
|
||||||
|
const from = `/${DEFAULT_BUCKET}/${v.pathname}`;
|
||||||
|
const to = `${dst}/${v.pathname.slice(`${src}/`.length)}`;
|
||||||
|
|
||||||
|
const result = await minioClient
|
||||||
|
.copyObject(DEFAULT_BUCKET, to, from, copyCond)
|
||||||
|
.catch((e) => {
|
||||||
|
console.error(`MinIO Error: ${e}`);
|
||||||
|
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
if (v.pathname.includes(".keep")) {
|
||||||
|
return await minioClient
|
||||||
|
.removeObject(DEFAULT_BUCKET, v.pathname)
|
||||||
|
.catch((e) => console.error(`MinIO Error: ${e}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
const search = await esClient.search<
|
||||||
|
StorageFile & { attachment: Record<string, string> }
|
||||||
|
>({
|
||||||
|
index: DEFAULT_INDEX!,
|
||||||
|
query: { match: { pathname: v.pathname } },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (search && search.hits.hits.length === 0) {
|
||||||
|
await minioClient
|
||||||
|
.removeObject(DEFAULT_BUCKET, v.pathname)
|
||||||
|
.catch((e) => console.error(`MinIO Error: ${e}`));
|
||||||
|
return console.log(
|
||||||
|
`Trying to update file in storage but not exist in database: ${from} > ${to}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = search.hits.hits[0];
|
||||||
|
|
||||||
|
await esClient
|
||||||
|
.update({
|
||||||
|
index: DEFAULT_INDEX!,
|
||||||
|
id: data._id,
|
||||||
|
doc: {
|
||||||
|
pathname: to,
|
||||||
|
path: to.split("/").slice(0, -1).join("/") + "/",
|
||||||
|
},
|
||||||
|
refresh: "wait_for",
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
|
||||||
|
|
||||||
|
await minioClient
|
||||||
|
.removeObject(DEFAULT_BUCKET, v.pathname)
|
||||||
|
.catch((e) => console.error(`MinIO Error: ${e}`));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
io.getInstance()?.emit("FolderMove", {
|
||||||
|
from: `${src}/`,
|
||||||
|
to: `${dst}/`,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ลบ Folder หรือ File ออกจากระบบ
|
||||||
|
*/
|
||||||
|
@Delete("folder")
|
||||||
|
@Tags("Storage Folder")
|
||||||
|
@Security("bearerAuth", ["management-role", "admin"])
|
||||||
|
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||||
|
public async deleteStorage(@Body() body: DeleteFolderBody) {
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
const objects: string[] = [];
|
||||||
|
const stream = minioClient.listObjectsV2(DEFAULT_BUCKET, body.path.join("/") + "/", true);
|
||||||
|
|
||||||
|
stream.on("data", (v) => v && v.name && objects.push(v.name));
|
||||||
|
stream.on("close", async () => {
|
||||||
|
resolve(await minioClient.removeObjects(DEFAULT_BUCKET, objects));
|
||||||
|
});
|
||||||
|
stream.on("error", () => reject(new Error(MINIO_ERROR_MESSAGE)));
|
||||||
|
});
|
||||||
|
|
||||||
|
io.getInstance()?.emit("FolderDelete", { pathname: body.path.join("/") + "/" });
|
||||||
|
|
||||||
|
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ร้องขอการอัพโหลดไฟล์ โดยเมื่อร้องขอจะได้ URL สำหรับอัพโหลดไฟล์มาพร้อมข้อมูลของไฟล์ที่จะทำการอัพโหลด
|
||||||
|
*/
|
||||||
|
@Post("file")
|
||||||
|
@Tags("Storage File")
|
||||||
|
@Security("bearerAuth", ["management-role", "admin"])
|
||||||
|
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||||
|
public async postFile(
|
||||||
|
@Request() request: { user: { preferred_username: string } },
|
||||||
|
@Body() body: FileBody,
|
||||||
|
) {
|
||||||
|
const { path, file } = body;
|
||||||
|
|
||||||
|
if (!(await checkPathExist(DEFAULT_BUCKET, path.join("/")))) {
|
||||||
|
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("/") + "/" } },
|
||||||
|
})
|
||||||
|
.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(),
|
||||||
|
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
|
||||||
|
description: body.description ?? "",
|
||||||
|
category: body.category ?? [],
|
||||||
|
keyword: body.keyword ?? [],
|
||||||
|
upload: false, // flag
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
createdBy: request.user.preferred_username,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
updatedBy: request.user.preferred_username,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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(`MinIO Error: ${e}`));
|
||||||
|
|
||||||
|
const rec = result.hits.hits[0]._source;
|
||||||
|
|
||||||
|
// File exist get created at and created by field but all other will be replaced
|
||||||
|
// by provided infomation or blank if not provided
|
||||||
|
metadata.createdAt = rec.createdAt;
|
||||||
|
metadata.createdBy = rec.createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
await esClient.index({
|
||||||
|
index: DEFAULT_INDEX!,
|
||||||
|
document: metadata,
|
||||||
|
refresh: "wait_for", // Must have or else it doesn't wait for updated index resulted in data not found on fetch
|
||||||
|
});
|
||||||
|
|
||||||
|
io.getInstance()?.emit("FileUploadRequest", metadata);
|
||||||
|
|
||||||
|
const presignedUrl = await minioClient.presignedPutObject(DEFAULT_BUCKET, metadata.pathname);
|
||||||
|
|
||||||
|
return { ...metadata, uploadUrl: presignedUrl };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Put("file")
|
||||||
|
@Tags("Storage File")
|
||||||
|
@Security("bearerAuth", ["management-role", "admin"])
|
||||||
|
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||||
|
public async moveFile(
|
||||||
|
@Request() request: { user: { preferred_username: string } },
|
||||||
|
@Body() body: PutFileBody,
|
||||||
|
) {
|
||||||
|
const search = await esClient
|
||||||
|
.search<StorageFile & { attachment: Record<string, any> }>({
|
||||||
|
index: DEFAULT_INDEX,
|
||||||
|
query: {
|
||||||
|
match: { pathname: body.from.path.join("/") + `/${body.from.file}` },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
|
||||||
|
|
||||||
|
if (!search) {
|
||||||
|
throw new Error("เกิดข้อผิดพลาดกับระบบฐานข้อมูล กรุณาลองใหม่ในภายหลัง");
|
||||||
|
}
|
||||||
|
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}`))) {
|
||||||
|
await esClient.delete({
|
||||||
|
index: DEFAULT_INDEX,
|
||||||
|
id: search.hits.hits[0]._id,
|
||||||
|
});
|
||||||
|
throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบไฟล์ดังกล่าว");
|
||||||
|
}
|
||||||
|
if (body.to && !(await checkPathExist(DEFAULT_BUCKET, body.to.path.join("/")))) {
|
||||||
|
throw new HttpError(HttpStatusCode.PRECONDITION_FAILED, "ไม่พบตำแหน่งที่ต้องการย้าย");
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
body.to &&
|
||||||
|
(await checkFileExist(DEFAULT_BUCKET, body.to.path.join("/") + `/${body.to.file}`))
|
||||||
|
) {
|
||||||
|
throw new HttpError(
|
||||||
|
HttpStatusCode.PRECONDITION_FAILED,
|
||||||
|
"พบไฟล์ในต้ำแหน่งปลายทาง ไม่สามารถย้ายได้",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!search.hits.hits[0]._source) {
|
||||||
|
// This should not possible.
|
||||||
|
// Just in case the result found with no associated data.
|
||||||
|
await esClient.delete({
|
||||||
|
index: DEFAULT_INDEX,
|
||||||
|
id: search.hits.hits[0]._id,
|
||||||
|
});
|
||||||
|
throw new Error("ไม่พบข้อมูลในฐานข้อมูล");
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = search.hits.hits[0]._id;
|
||||||
|
const { attachment: _, ...source } = search.hits.hits[0]._source;
|
||||||
|
|
||||||
|
const { to, from, upload, ...metadata } = body;
|
||||||
|
|
||||||
|
const dateMeta = {
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
updatedBy: request.user.preferred_username,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (from && to) {
|
||||||
|
const src = [DEFAULT_BUCKET, ...from.path, ""].join("/") + from.file;
|
||||||
|
const dst = to.path.join("/") + `/${to.file}`;
|
||||||
|
|
||||||
|
const result = await minioClient.copyObject(DEFAULT_BUCKET, dst, src, copyCond).catch((e) => {
|
||||||
|
console.error(`MinIO Error: ${e}`);
|
||||||
|
throw new Error("เกิดข้อผิดพลาด ไม่สามารถย้ายไฟล์ได้");
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
await esClient
|
||||||
|
.update({
|
||||||
|
index: DEFAULT_INDEX,
|
||||||
|
id: id,
|
||||||
|
doc: {
|
||||||
|
...metadata,
|
||||||
|
path: to.path.join("/") + "/",
|
||||||
|
pathname: dst,
|
||||||
|
...dateMeta,
|
||||||
|
},
|
||||||
|
refresh: "wait_for",
|
||||||
|
})
|
||||||
|
.then(async () => await minioClient.removeObject(DEFAULT_INDEX, src))
|
||||||
|
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
|
||||||
|
|
||||||
|
io.getInstance()?.emit("FileMove", {
|
||||||
|
from: source,
|
||||||
|
to: {
|
||||||
|
...source,
|
||||||
|
...metadata,
|
||||||
|
path: to.path.join("/") + "/",
|
||||||
|
pathname: dst,
|
||||||
|
...dateMeta,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (upload) {
|
||||||
|
const presignedUrl = await minioClient.presignedPutObject(DEFAULT_BUCKET, dst);
|
||||||
|
return { uploadUrl: presignedUrl };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from) {
|
||||||
|
await esClient
|
||||||
|
.update({
|
||||||
|
index: DEFAULT_INDEX,
|
||||||
|
id: id,
|
||||||
|
doc: {
|
||||||
|
...metadata,
|
||||||
|
...dateMeta,
|
||||||
|
},
|
||||||
|
refresh: "wait_for",
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
|
||||||
|
|
||||||
|
io.getInstance()?.emit("FileMove", {
|
||||||
|
from: source,
|
||||||
|
to: {
|
||||||
|
...source,
|
||||||
|
...metadata,
|
||||||
|
...dateMeta,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (upload) {
|
||||||
|
const src = from.path.join("/") + `/${from.file}`;
|
||||||
|
const presignedUrl = await minioClient.presignedPutObject(DEFAULT_BUCKET, src);
|
||||||
|
return { uploadUrl: presignedUrl };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete("file")
|
||||||
|
@Tags("Storage File")
|
||||||
|
@Security("bearerAuth", ["management-role", "admin"])
|
||||||
|
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
|
||||||
|
public async deleteFile(@Body() body: DeleteFileBody) {
|
||||||
|
const pathname = body.path.join("/") + body.file;
|
||||||
|
|
||||||
|
await minioClient
|
||||||
|
.removeObject(DEFAULT_BUCKET, pathname)
|
||||||
|
.catch((e) => console.error(`MinIO Error: ${e}`));
|
||||||
|
await esClient
|
||||||
|
.deleteByQuery({
|
||||||
|
index: DEFAULT_INDEX,
|
||||||
|
query: { match: { pathname } },
|
||||||
|
})
|
||||||
|
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
|
||||||
|
|
||||||
|
io.getInstance()?.emit("FileDelete", { pathname });
|
||||||
|
|
||||||
|
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,3 +9,5 @@ export function setInstance(server: Server) {
|
||||||
export function getInstance() {
|
export function getInstance() {
|
||||||
return io;
|
return io;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default { getInstance, setInstance };
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ 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
|
// 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';
|
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
|
// 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';
|
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
|
// 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';
|
import { SubFolderFileController } from './controllers/subFolderFileController';
|
||||||
|
|
@ -65,6 +67,77 @@ const models: TsoaRoute.Models = {
|
||||||
"additionalProperties": false,
|
"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
|
// 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": {
|
||||||
|
"operation": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["folder"]},{"dataType":"enum","enums":["file"]}],"required":true},
|
||||||
|
"path": {"dataType":"array","array":{"dataType":"string"},"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
|
||||||
|
"FolderBody": {
|
||||||
|
"dataType": "refObject",
|
||||||
|
"properties": {
|
||||||
|
"path": {"dataType":"array","array":{"dataType":"string"},"required":true},
|
||||||
|
"name": {"dataType":"string","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
|
||||||
|
"PutFolderBody": {
|
||||||
|
"dataType": "refObject",
|
||||||
|
"properties": {
|
||||||
|
"from": {"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true},"path":{"dataType":"array","array":{"dataType":"string"},"required":true}},"required":true},
|
||||||
|
"to": {"dataType":"nestedObjectLiteral","nestedProperties":{"name":{"dataType":"string","required":true},"path":{"dataType":"array","array":{"dataType":"string"},"required":true}},"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
|
||||||
|
"DeleteFolderBody": {
|
||||||
|
"dataType": "refObject",
|
||||||
|
"properties": {
|
||||||
|
"path": {"dataType":"array","array":{"dataType":"string"},"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
|
||||||
|
"FileBody": {
|
||||||
|
"dataType": "refObject",
|
||||||
|
"properties": {
|
||||||
|
"path": {"dataType":"array","array":{"dataType":"string"},"required":true},
|
||||||
|
"file": {"dataType":"string","required":true},
|
||||||
|
"title": {"dataType":"string"},
|
||||||
|
"description": {"dataType":"string"},
|
||||||
|
"category": {"dataType":"array","array":{"dataType":"string"}},
|
||||||
|
"keyword": {"dataType":"array","array":{"dataType":"string"}},
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
"PutFileBody": {
|
||||||
|
"dataType": "refObject",
|
||||||
|
"properties": {
|
||||||
|
"title": {"dataType":"string"},
|
||||||
|
"description": {"dataType":"string"},
|
||||||
|
"category": {"dataType":"array","array":{"dataType":"string"}},
|
||||||
|
"keyword": {"dataType":"array","array":{"dataType":"string"}},
|
||||||
|
"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"},
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
"DeleteFileBody": {
|
||||||
|
"dataType": "refObject",
|
||||||
|
"properties": {
|
||||||
|
"path": {"dataType":"array","array":{"dataType":"string"},"required":true},
|
||||||
|
"file": {"dataType":"string","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
|
||||||
};
|
};
|
||||||
const validationService = new ValidationService(models);
|
const validationService = new ValidationService(models);
|
||||||
|
|
||||||
|
|
@ -656,6 +729,181 @@ export function RegisterRoutes(app: Router) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 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
|
// 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('/storage/list',
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.getList)),
|
||||||
|
|
||||||
|
function StorageController_getList(request: any, response: any, next: any) {
|
||||||
|
const args = {
|
||||||
|
body: {"in":"body","name":"body","required":true,"ref":"ListRequestBody"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 StorageController();
|
||||||
|
|
||||||
|
|
||||||
|
const promise = controller.getList.apply(controller, validatedArgs as any);
|
||||||
|
promiseHandler(controller, promise, response, undefined, 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('/storage/folder',
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.postFolder)),
|
||||||
|
|
||||||
|
function StorageController_postFolder(request: any, response: any, next: any) {
|
||||||
|
const args = {
|
||||||
|
body: {"in":"body","name":"body","required":true,"ref":"FolderBody"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 StorageController();
|
||||||
|
|
||||||
|
|
||||||
|
const promise = controller.postFolder.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.put('/storage/folder',
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.moveFolder)),
|
||||||
|
|
||||||
|
function StorageController_moveFolder(request: any, response: any, next: any) {
|
||||||
|
const args = {
|
||||||
|
body: {"in":"body","name":"body","required":true,"ref":"PutFolderBody"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 StorageController();
|
||||||
|
|
||||||
|
|
||||||
|
const promise = controller.moveFolder.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('/storage/folder',
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.deleteStorage)),
|
||||||
|
|
||||||
|
function StorageController_deleteStorage(request: any, response: any, next: any) {
|
||||||
|
const args = {
|
||||||
|
body: {"in":"body","name":"body","required":true,"ref":"DeleteFolderBody"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 StorageController();
|
||||||
|
|
||||||
|
|
||||||
|
const promise = controller.deleteStorage.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.post('/storage/file',
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.postFile)),
|
||||||
|
|
||||||
|
function StorageController_postFile(request: any, response: any, next: any) {
|
||||||
|
const args = {
|
||||||
|
body: {"in":"body","name":"body","required":true,"ref":"FileBody"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 StorageController();
|
||||||
|
|
||||||
|
|
||||||
|
const promise = controller.postFile.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.put('/storage/file',
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.moveFile)),
|
||||||
|
|
||||||
|
function StorageController_moveFile(request: any, response: any, next: any) {
|
||||||
|
const args = {
|
||||||
|
body: {"in":"body","name":"body","required":true,"ref":"PutFileBody"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 StorageController();
|
||||||
|
|
||||||
|
|
||||||
|
const promise = controller.moveFile.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('/storage/file',
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||||
|
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.deleteFile)),
|
||||||
|
|
||||||
|
function StorageController_deleteFile(request: any, response: any, next: any) {
|
||||||
|
const args = {
|
||||||
|
body: {"in":"body","name":"body","required":true,"ref":"DeleteFileBody"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 StorageController();
|
||||||
|
|
||||||
|
|
||||||
|
const promise = controller.deleteFile.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',
|
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder',
|
||||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,299 @@
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"ListRequestBody": {
|
||||||
|
"properties": {
|
||||||
|
"operation": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"folder",
|
||||||
|
"file"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"operation",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"FolderBody": {
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"แฟ้ม 1",
|
||||||
|
"แฟ้ม 2"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "แฟ้ม 3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"path",
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"PutFolderBody": {
|
||||||
|
"properties": {
|
||||||
|
"from": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "แฟ้ม 3"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"แฟ้ม 1",
|
||||||
|
"แฟ้ม 2"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "แฟ้ม 3 แก้ไข"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"แฟ้ม 1",
|
||||||
|
"แฟ้ม 2"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"from",
|
||||||
|
"to"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"DeleteFolderBody": {
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"แฟ้ม 1",
|
||||||
|
"แฟ้ม 2",
|
||||||
|
"แฟ้ม 3 แก้ไข"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"FileBody": {
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"แฟ้ม 1",
|
||||||
|
"แฟ้ม 2",
|
||||||
|
"แฟ้ม 3"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "ไฟล์ 1.xlsx"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "การเงิน"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "การเงิน"
|
||||||
|
},
|
||||||
|
"category": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"การเงิน",
|
||||||
|
"รายงาน"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"keyword": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"การเงิน",
|
||||||
|
"รายรับ",
|
||||||
|
"รายจ่าย"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"path",
|
||||||
|
"file"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"PutFileBody": {
|
||||||
|
"properties": {
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "การเงิน"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "การเงิน"
|
||||||
|
},
|
||||||
|
"category": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"การเงิน",
|
||||||
|
"รายงาน"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"keyword": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"การเงิน",
|
||||||
|
"รายรับ",
|
||||||
|
"รายจ่าย"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"from": {
|
||||||
|
"properties": {
|
||||||
|
"file": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "ไฟล์ 1.xlsx"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"แฟ้ม 1",
|
||||||
|
"แฟ้ม 2",
|
||||||
|
"แฟ้ม 3"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"file",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"description": "หากต้องการอัพโหลดไฟล์ด้วยให้ส่งค่าเป็นจริง"
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"properties": {
|
||||||
|
"file": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "ไฟล์ 1 แก้ไข.xlsx"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"แฟ้ม 1",
|
||||||
|
"แฟ้ม 2",
|
||||||
|
"แฟ้ม 3"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"file",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"from"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"DeleteFileBody": {
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
"แฟ้ม 1",
|
||||||
|
"แฟ้ม 2",
|
||||||
|
"แฟ้ม 3"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "ไฟล์ 1 แก้ไข.xlsx"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"path",
|
||||||
|
"file"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securitySchemes": {
|
"securitySchemes": {
|
||||||
|
|
@ -1662,6 +1955,356 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/storage/list": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "GetList",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Ok",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/StorageFolder"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/StorageFile"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"Example 1": {
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Example 2": {
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"pathname": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1.pdf",
|
||||||
|
"path": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||||
|
"title": "เอกสาร",
|
||||||
|
"description": "เอกสารการเงิน",
|
||||||
|
"category": [
|
||||||
|
"บัญชี"
|
||||||
|
],
|
||||||
|
"keyword": [
|
||||||
|
"เงิน",
|
||||||
|
"บัญชี",
|
||||||
|
"รายจ่าย",
|
||||||
|
"รายรับ"
|
||||||
|
],
|
||||||
|
"upload": 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Storage Folder",
|
||||||
|
"Storage File"
|
||||||
|
],
|
||||||
|
"security": [],
|
||||||
|
"parameters": [],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ListRequestBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/storage/folder": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "PostFolder",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "สำเร็จ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Storage Folder"
|
||||||
|
],
|
||||||
|
"security": [],
|
||||||
|
"parameters": [],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/FolderBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"operationId": "MoveFolder",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "สำเร็จ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "ยา้ย Folder ภายใต้ Folder (Path) หนึ่ง ไปภายใน Folder (Path) หนึ่งและสามารถเปลี่ยนชื่อได้",
|
||||||
|
"tags": [
|
||||||
|
"Storage Folder"
|
||||||
|
],
|
||||||
|
"security": [],
|
||||||
|
"parameters": [],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/PutFolderBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"operationId": "DeleteStorage",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "สำเร็จ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "ลบ Folder หรือ File ออกจากระบบ",
|
||||||
|
"tags": [
|
||||||
|
"Storage Folder"
|
||||||
|
],
|
||||||
|
"security": [],
|
||||||
|
"parameters": [],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/DeleteFolderBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/storage/file": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "PostFile",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "สำเร็จ",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"properties": {
|
||||||
|
"createdBy": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"updatedBy": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"keyword": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"category": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"fileType": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"fileSize": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "double"
|
||||||
|
},
|
||||||
|
"fileName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"pathname": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uploadUrl": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"createdBy",
|
||||||
|
"createdAt",
|
||||||
|
"updatedBy",
|
||||||
|
"updatedAt",
|
||||||
|
"upload",
|
||||||
|
"path",
|
||||||
|
"keyword",
|
||||||
|
"category",
|
||||||
|
"description",
|
||||||
|
"title",
|
||||||
|
"fileType",
|
||||||
|
"fileSize",
|
||||||
|
"fileName",
|
||||||
|
"pathname",
|
||||||
|
"uploadUrl"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "ร้องขอการอัพโหลดไฟล์ โดยเมื่อร้องขอจะได้ URL สำหรับอัพโหลดไฟล์มาพร้อมข้อมูลของไฟล์ที่จะทำการอัพโหลด",
|
||||||
|
"tags": [
|
||||||
|
"Storage File"
|
||||||
|
],
|
||||||
|
"security": [],
|
||||||
|
"parameters": [],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/FileBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"operationId": "MoveFile",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "สำเร็จ",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"anyOf": [
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"uploadUrl": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"uploadUrl"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Storage File"
|
||||||
|
],
|
||||||
|
"security": [],
|
||||||
|
"parameters": [],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/PutFileBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"operationId": "DeleteFile",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "สำเร็จ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Storage File"
|
||||||
|
],
|
||||||
|
"security": [],
|
||||||
|
"parameters": [],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/DeleteFileBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder": {
|
"/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "ListFolder",
|
"operationId": "ListFolder",
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,9 @@ export async function expressAuthentication(
|
||||||
securityName: string,
|
securityName: string,
|
||||||
scopes?: string[],
|
scopes?: string[],
|
||||||
) {
|
) {
|
||||||
if (process.env.AUTH_BYPASS) return { preferred_username: "bypassed" };
|
if (process.env.NODE_ENV !== "production" && process.env.AUTH_BYPASS) {
|
||||||
|
return { preferred_username: "bypassed" };
|
||||||
|
}
|
||||||
|
|
||||||
if (securityName !== "bearerAuth") throw new Error("Unknown authentication method.");
|
if (securityName !== "bearerAuth") throw new Error("Unknown authentication method.");
|
||||||
|
|
||||||
|
|
@ -36,7 +38,7 @@ export async function expressAuthentication(
|
||||||
? request.headers["authorization"].split(" ")[1]
|
? request.headers["authorization"].split(" ")[1]
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (!token) throw new HttpError(HttpStatusCode.UNAUTHORIZED, "No token provided.");
|
if (!token) throw new HttpError(HttpStatusCode.UNAUTHORIZED, "ไม่พบข้อมูลสำหัรบบืนบันตัวตน");
|
||||||
|
|
||||||
let payload: JwtPayload = {};
|
let payload: JwtPayload = {};
|
||||||
|
|
||||||
|
|
@ -60,7 +62,7 @@ export async function expressAuthentication(
|
||||||
.map((v) => (v === "management-role" ? process.env.MANAGEMENT_ROLE : v))
|
.map((v) => (v === "management-role" ? process.env.MANAGEMENT_ROLE : v))
|
||||||
.every((v) => !payload.resource_access[payload.azp].roles.includes(v))
|
.every((v) => !payload.resource_access[payload.azp].roles.includes(v))
|
||||||
) {
|
) {
|
||||||
throw new HttpError(HttpStatusCode.FORBIDDEN, "You are not allowed to perform this action.");
|
throw new HttpError(HttpStatusCode.FORBIDDEN, "คุณไม่มีสิทธิในเข้าถึงข้อมูลนี้");
|
||||||
}
|
}
|
||||||
|
|
||||||
return payload;
|
return payload;
|
||||||
|
|
@ -68,7 +70,7 @@ export async function expressAuthentication(
|
||||||
|
|
||||||
async function verifyOffline(token: string) {
|
async function verifyOffline(token: string) {
|
||||||
const payload = await jwtVerify(token).catch((_) => null);
|
const payload = await jwtVerify(token).catch((_) => null);
|
||||||
if (!payload) throw new HttpError(HttpStatusCode.UNAUTHORIZED, "Invalid token provided.");
|
if (!payload) throw new HttpError(HttpStatusCode.UNAUTHORIZED, "ไม่สามารถยืนยันตัวตนได้");
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,8 +79,8 @@ async function verifyOnline(token: string) {
|
||||||
headers: { authorization: `Bearer ${token}` },
|
headers: { authorization: `Bearer ${token}` },
|
||||||
}).catch((e) => console.error(e));
|
}).catch((e) => console.error(e));
|
||||||
|
|
||||||
if (!res) throw new Error("Cannot connect to auth service.");
|
if (!res) throw new Error("ไม่สามารถเข้าถึงระบบยืนยันตัวตน");
|
||||||
if (!res.ok) throw new HttpError(HttpStatusCode.UNAUTHORIZED, "Invalid token provided.");
|
if (!res.ok) throw new HttpError(HttpStatusCode.UNAUTHORIZED, "ไม่สามารถยืนยันตัวตนได้");
|
||||||
|
|
||||||
return await jwtDecode(token);
|
return await jwtDecode(token);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue