feat: socketio and user identity

This commit is contained in:
Methapon2001 2023-12-12 13:02:22 +07:00
parent cd43bb53c3
commit 185b1f540a
No known key found for this signature in database
GPG key ID: 849924FEF46BD132
2 changed files with 90 additions and 14 deletions

View file

@ -1,4 +1,16 @@
import { Body, Controller, Delete, Example, Post, Put, Route, SuccessResponse, Tags } from "tsoa";
import {
Body,
Controller,
Delete,
Example,
Post,
Put,
Request,
Route,
Security,
SuccessResponse,
Tags,
} from "tsoa";
import minioClient from "../minio";
import esClient from "../elasticsearch";
@ -9,6 +21,8 @@ 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.");
@ -200,6 +214,7 @@ export class StorageController extends Controller {
},
])
@Tags("Storage Folder", "Storage File")
@Security("bearerAuth")
public async getList(@Body() body: ListRequestBody) {
const path = body.path.filter(Boolean);
@ -209,29 +224,41 @@ export class StorageController extends Controller {
@Post("folder")
@Tags("Storage Folder")
@Security("bearerAuth", ["management-role", "admin"])
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
public async postFolder(@Body() body: FolderBody) {
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,
{
createdAt: new Date().toISOString(),
createdBy: "n/a",
},
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);
}
@ -240,6 +267,7 @@ export class StorageController extends Controller {
*/
@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}`;
@ -322,6 +350,11 @@ export class StorageController extends Controller {
}),
);
io.getInstance()?.emit("FolderMove", {
from: `${src}/`,
to: `${dst}/`,
});
return this.setStatus(HttpStatusCode.NO_CONTENT);
}
@ -330,6 +363,7 @@ export class StorageController extends Controller {
*/
@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) => {
@ -343,6 +377,8 @@ export class StorageController extends Controller {
stream.on("error", () => reject(new Error(MINIO_ERROR_MESSAGE)));
});
io.getInstance()?.emit("FolderDelete", { pathname: body.path.join("/") + "/" });
return this.setStatus(HttpStatusCode.NO_CONTENT);
}
@ -351,8 +387,12 @@ export class StorageController extends Controller {
*/
@Post("file")
@Tags("Storage File")
@Security("bearerAuth", ["management-role", "admin"])
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
public async postFile(@Body() body: FileBody) {
public async postFile(
@Request() request: { user: { preferred_username: string } },
@Body() body: FileBody,
) {
const { path, file } = body;
if (!(await checkPathExist(DEFAULT_BUCKET, path.join("/")))) {
@ -378,9 +418,9 @@ export class StorageController extends Controller {
keyword: body.keyword ?? [],
upload: false, // flag
createdAt: new Date().toISOString(),
createdBy: "n/a",
createdBy: request.user.preferred_username,
updatedAt: new Date().toISOString(),
updatedBy: "n/a",
updatedBy: request.user.preferred_username,
};
// Pathname is unique and should not have multiple record with same path
@ -406,6 +446,8 @@ export class StorageController extends Controller {
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 };
@ -413,8 +455,12 @@ export class StorageController extends Controller {
@Put("file")
@Tags("Storage File")
@Security("bearerAuth", ["management-role", "admin"])
@SuccessResponse(HttpStatusCode.NO_CONTENT, "สำเร็จ")
public async moveFile(@Body() body: PutFileBody) {
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,
@ -460,9 +506,15 @@ export class StorageController extends Controller {
}
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}`;
@ -481,14 +533,24 @@ export class StorageController extends Controller {
...metadata,
path: to.path.join("/") + "/",
pathname: dst,
updatedAt: new Date().toISOString(),
updatedBy: "n/a",
...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 };
@ -503,12 +565,21 @@ export class StorageController extends Controller {
id: id,
doc: {
...metadata,
updatedAt: new Date().toISOString(),
updatedBy: "n/a",
...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);
@ -521,6 +592,7 @@ export class StorageController extends Controller {
@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;
@ -535,6 +607,8 @@ export class StorageController extends Controller {
})
.catch((e) => console.error(`ElasticSearch Error: ${e}`));
io.getInstance()?.emit("FileDelete", { pathname });
return this.setStatus(HttpStatusCode.NO_CONTENT);
}
}

View file

@ -9,3 +9,5 @@ export function setInstance(server: Server) {
export function getInstance() {
return io;
}
export default { getInstance, setInstance };