feat: socketio and user identity
This commit is contained in:
parent
cd43bb53c3
commit
185b1f540a
2 changed files with 90 additions and 14 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,3 +9,5 @@ export function setInstance(server: Server) {
|
|||
export function getInstance() {
|
||||
return io;
|
||||
}
|
||||
|
||||
export default { getInstance, setInstance };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue