feat(api): hidden folder and file
This commit is contained in:
parent
e73f5cc855
commit
c48e8c9873
8 changed files with 113 additions and 5 deletions
|
|
@ -379,7 +379,7 @@ const useStorage = defineStore('storageStore', () => {
|
||||||
const arrayPath: string[] = path.split('/').filter(Boolean)
|
const arrayPath: string[] = path.split('/').filter(Boolean)
|
||||||
await api.post(`${import.meta.env.VITE_API_ENDPOINT}storage/folder`, {
|
await api.post(`${import.meta.env.VITE_API_ENDPOINT}storage/folder`, {
|
||||||
path: arrayPath,
|
path: arrayPath,
|
||||||
name: name,
|
name: name.replace(/^./, ''),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
loader.hide()
|
loader.hide()
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ export class SearchController extends Controller {
|
||||||
should: search.OR?.map((v) => ({
|
should: search.OR?.map((v) => ({
|
||||||
[type[search.exact || v.exact ? 1 : 0]]: { [v.field]: v.value },
|
[type[search.exact || v.exact ? 1 : 0]]: { [v.field]: v.value },
|
||||||
})),
|
})),
|
||||||
|
must_not: {
|
||||||
|
match: { hidden: true },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
size: 10000,
|
size: 10000,
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ const PATH_ALREADY_EXIST = "ตำแหน่งดังกล่าวมี
|
||||||
interface ListRequestBody {
|
interface ListRequestBody {
|
||||||
operation: "folder" | "file";
|
operation: "folder" | "file";
|
||||||
path: string[];
|
path: string[];
|
||||||
|
hidden?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FolderBody {
|
interface FolderBody {
|
||||||
|
|
@ -77,6 +78,8 @@ interface FileBody {
|
||||||
category?: string[];
|
category?: string[];
|
||||||
/** @example ["การเงิน", "รายรับ", "รายจ่าย"] */
|
/** @example ["การเงิน", "รายรับ", "รายจ่าย"] */
|
||||||
keyword?: string[];
|
keyword?: string[];
|
||||||
|
/** @example false */
|
||||||
|
hidden?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PutFileBody extends Omit<FileBody, "file" | "path"> {
|
interface PutFileBody extends Omit<FileBody, "file" | "path"> {
|
||||||
|
|
@ -111,7 +114,7 @@ interface DownloadFileBody {
|
||||||
file: string;
|
file: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listFolder(path: string[]) {
|
async function listFolder(path: string[], hidden: boolean = false) {
|
||||||
const list = await new Promise<{ pathname: string; name: string }[]>((resolve, reject) => {
|
const list = await new Promise<{ pathname: string; name: string }[]>((resolve, reject) => {
|
||||||
const item: { pathname: string; name: string }[] = [];
|
const item: { pathname: string; name: string }[] = [];
|
||||||
|
|
||||||
|
|
@ -132,6 +135,8 @@ async function listFolder(path: string[]) {
|
||||||
|
|
||||||
const folder = await Promise.all(
|
const folder = await Promise.all(
|
||||||
list.map(async (v) => {
|
list.map(async (v) => {
|
||||||
|
if (v.name.startsWith(".") && !hidden) return undefined;
|
||||||
|
|
||||||
// Get stat from hidden object that used to mark as folder as minio doesn't really have folder
|
// Get stat from hidden object that used to mark as folder as minio doesn't really have folder
|
||||||
const stat = await minioClient
|
const stat = await minioClient
|
||||||
.statObject(DEFAULT_BUCKET, `${v.pathname}.keep`)
|
.statObject(DEFAULT_BUCKET, `${v.pathname}.keep`)
|
||||||
|
|
@ -152,12 +157,17 @@ async function listFolder(path: string[]) {
|
||||||
return folder.filter((v: StorageFolder | undefined): v is StorageFolder => !!v);
|
return folder.filter((v: StorageFolder | undefined): v is StorageFolder => !!v);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listFile(path: string[]) {
|
async function listFile(path: string[], hidden: boolean = false) {
|
||||||
const result = await esClient
|
const result = await esClient
|
||||||
.search<StorageFile & { attachment: Record<string, string> }>({
|
.search<StorageFile & { attachment: Record<string, string> }>({
|
||||||
index: DEFAULT_INDEX,
|
index: DEFAULT_INDEX,
|
||||||
sort: [{ pathname: "asc" }],
|
sort: [{ pathname: "asc" }],
|
||||||
query: { match: { path: path.join("/") + "/" } },
|
query: {
|
||||||
|
bool: {
|
||||||
|
must: { match: { path: path.join("/") + "/" } },
|
||||||
|
must_not: !hidden ? { match: { hidden: true } } : undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
size: 10000,
|
size: 10000,
|
||||||
})
|
})
|
||||||
.then((r) => r.hits.hits);
|
.then((r) => r.hits.hits);
|
||||||
|
|
@ -229,7 +239,7 @@ export class StorageController extends Controller {
|
||||||
public async getList(@Body() body: ListRequestBody) {
|
public async getList(@Body() body: ListRequestBody) {
|
||||||
const path = body.path.filter(Boolean);
|
const path = body.path.filter(Boolean);
|
||||||
|
|
||||||
if (body.operation === "folder") return await listFolder(path);
|
if (body.operation === "folder") return await listFolder(path, body.hidden);
|
||||||
if (body.operation === "file") return await listFile(path);
|
if (body.operation === "file") return await listFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -428,6 +438,7 @@ export class StorageController extends Controller {
|
||||||
category: body.category ?? [],
|
category: body.category ?? [],
|
||||||
keyword: body.keyword ?? [],
|
keyword: body.keyword ?? [],
|
||||||
upload: false, // flag
|
upload: false, // flag
|
||||||
|
hidden: body.hidden ?? false,
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
createdBy: request.user.preferred_username,
|
createdBy: request.user.preferred_username,
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
|
|
|
||||||
11
Services/server/src/controllers/versionController.ts
Normal file
11
Services/server/src/controllers/versionController.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { Controller, Get, Route, Tags } from "tsoa";
|
||||||
|
import version from "../ver.json";
|
||||||
|
|
||||||
|
@Route("version")
|
||||||
|
export class VersionController extends Controller {
|
||||||
|
@Get()
|
||||||
|
@Tags("Version")
|
||||||
|
public async getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ export interface StorageFile {
|
||||||
|
|
||||||
path: string;
|
path: string;
|
||||||
upload: boolean;
|
upload: boolean;
|
||||||
|
hidden: boolean;
|
||||||
|
|
||||||
updatedAt: string | Date;
|
updatedAt: string | Date;
|
||||||
updatedBy: string;
|
updatedBy: string;
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@ async function handleNotFoundRecord(
|
||||||
category: [],
|
category: [],
|
||||||
keyword: [],
|
keyword: [],
|
||||||
upload: true,
|
upload: true,
|
||||||
|
hidden: false,
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
createdBy: "n/a",
|
createdBy: "n/a",
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ import { StorageController } from './controllers/storageController';
|
||||||
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';
|
||||||
|
// 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';
|
import { expressAuthentication } from './utils/auth';
|
||||||
// @ts-ignore - no great way to install types from subpackage
|
// @ts-ignore - no great way to install types from subpackage
|
||||||
const promiseAny = require('promise.any');
|
const promiseAny = require('promise.any');
|
||||||
|
|
@ -50,6 +52,7 @@ const models: TsoaRoute.Models = {
|
||||||
"keyword": {"dataType":"array","array":{"dataType":"string"},"required":true},
|
"keyword": {"dataType":"array","array":{"dataType":"string"},"required":true},
|
||||||
"path": {"dataType":"string","required":true},
|
"path": {"dataType":"string","required":true},
|
||||||
"upload": {"dataType":"boolean","required":true},
|
"upload": {"dataType":"boolean","required":true},
|
||||||
|
"hidden": {"dataType":"boolean","required":true},
|
||||||
"updatedAt": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
"updatedAt": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||||
"updatedBy": {"dataType":"string","required":true},
|
"updatedBy": {"dataType":"string","required":true},
|
||||||
"createdAt": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
"createdAt": {"dataType":"union","subSchemas":[{"dataType":"string"},{"dataType":"datetime"}],"required":true},
|
||||||
|
|
@ -73,6 +76,7 @@ const models: TsoaRoute.Models = {
|
||||||
"properties": {
|
"properties": {
|
||||||
"operation": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["folder"]},{"dataType":"enum","enums":["file"]}],"required":true},
|
"operation": {"dataType":"union","subSchemas":[{"dataType":"enum","enums":["folder"]},{"dataType":"enum","enums":["file"]}],"required":true},
|
||||||
"path": {"dataType":"array","array":{"dataType":"string"},"required":true},
|
"path": {"dataType":"array","array":{"dataType":"string"},"required":true},
|
||||||
|
"hidden": {"dataType":"boolean"},
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
},
|
},
|
||||||
|
|
@ -112,6 +116,7 @@ const models: TsoaRoute.Models = {
|
||||||
"description": {"dataType":"string"},
|
"description": {"dataType":"string"},
|
||||||
"category": {"dataType":"array","array":{"dataType":"string"}},
|
"category": {"dataType":"array","array":{"dataType":"string"}},
|
||||||
"keyword": {"dataType":"array","array":{"dataType":"string"}},
|
"keyword": {"dataType":"array","array":{"dataType":"string"}},
|
||||||
|
"hidden": {"dataType":"boolean"},
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
},
|
},
|
||||||
|
|
@ -123,6 +128,7 @@ const models: TsoaRoute.Models = {
|
||||||
"description": {"dataType":"string"},
|
"description": {"dataType":"string"},
|
||||||
"category": {"dataType":"array","array":{"dataType":"string"}},
|
"category": {"dataType":"array","array":{"dataType":"string"}},
|
||||||
"keyword": {"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},
|
"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}}},
|
"to": {"dataType":"nestedObjectLiteral","nestedProperties":{"file":{"dataType":"string","required":true},"path":{"dataType":"array","array":{"dataType":"string"},"required":true}}},
|
||||||
"upload": {"dataType":"boolean"},
|
"upload": {"dataType":"boolean"},
|
||||||
|
|
@ -1248,6 +1254,30 @@ 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.get('/version',
|
||||||
|
...(fetchMiddlewares<RequestHandler>(VersionController)),
|
||||||
|
...(fetchMiddlewares<RequestHandler>(VersionController.prototype.getVersion)),
|
||||||
|
|
||||||
|
function VersionController_getVersion(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 VersionController();
|
||||||
|
|
||||||
|
|
||||||
|
const promise = controller.getVersion.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
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,9 @@
|
||||||
"upload": {
|
"upload": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"hidden": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"updatedAt": {
|
"updatedAt": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
|
@ -125,6 +128,7 @@
|
||||||
"keyword",
|
"keyword",
|
||||||
"path",
|
"path",
|
||||||
"upload",
|
"upload",
|
||||||
|
"hidden",
|
||||||
"updatedAt",
|
"updatedAt",
|
||||||
"updatedBy",
|
"updatedBy",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
|
|
@ -198,6 +202,9 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": "array"
|
"type": "array"
|
||||||
|
},
|
||||||
|
"hidden": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
@ -352,6 +359,10 @@
|
||||||
"รายรับ",
|
"รายรับ",
|
||||||
"รายจ่าย"
|
"รายจ่าย"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"hidden": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
@ -392,6 +403,10 @@
|
||||||
"รายจ่าย"
|
"รายจ่าย"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"hidden": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": false
|
||||||
|
},
|
||||||
"from": {
|
"from": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"file": {
|
"file": {
|
||||||
|
|
@ -1522,6 +1537,9 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"hidden": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
@ -1568,6 +1586,7 @@
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"updatedBy",
|
"updatedBy",
|
||||||
"updatedAt",
|
"updatedAt",
|
||||||
|
"hidden",
|
||||||
"upload",
|
"upload",
|
||||||
"path",
|
"path",
|
||||||
"keyword",
|
"keyword",
|
||||||
|
|
@ -2216,6 +2235,9 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"hidden": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
@ -2262,6 +2284,7 @@
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"updatedBy",
|
"updatedBy",
|
||||||
"updatedAt",
|
"updatedAt",
|
||||||
|
"hidden",
|
||||||
"upload",
|
"upload",
|
||||||
"path",
|
"path",
|
||||||
"keyword",
|
"keyword",
|
||||||
|
|
@ -2424,6 +2447,9 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"hidden": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
@ -2470,6 +2496,7 @@
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"updatedBy",
|
"updatedBy",
|
||||||
"updatedAt",
|
"updatedAt",
|
||||||
|
"hidden",
|
||||||
"upload",
|
"upload",
|
||||||
"path",
|
"path",
|
||||||
"keyword",
|
"keyword",
|
||||||
|
|
@ -3409,6 +3436,9 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"hidden": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
@ -3455,6 +3485,7 @@
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"updatedBy",
|
"updatedBy",
|
||||||
"updatedAt",
|
"updatedAt",
|
||||||
|
"hidden",
|
||||||
"upload",
|
"upload",
|
||||||
"path",
|
"path",
|
||||||
"keyword",
|
"keyword",
|
||||||
|
|
@ -3535,6 +3566,26 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/version": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "GetVersion",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Ok",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Version"
|
||||||
|
],
|
||||||
|
"security": [],
|
||||||
|
"parameters": []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"servers": [
|
"servers": [
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue