import { app } from '@/app.ts'; import { getFileStat, getMinioList, deleteFile, updateFileStat, deleteFiles } from './module/get-minio-list.ts'; import path from 'path'; import { CustomError } from '@kevisual/router'; import { get } from 'http'; import { callDetectAppVersion } from '../app-manager/export.ts'; /** * 清理prefix中的'..' * @param prefix * @returns */ const handlePrefix = (prefix: string) => { // 清理所有的 '..' if (!prefix) return ''; if (prefix.includes('..')) { throw new CustomError('invalid prefix'); } return prefix; }; /** * 根据用户名获取prefix * @param data * @param tokenUser * @returns */ const getPrefixByUser = (data: { prefix: string }, tokenUser: { username: string }) => { const prefixBase = '/' + tokenUser.username; const _prefix = handlePrefix(data.prefix); return { len: prefixBase.length, prefix: path.join(prefixBase, './', _prefix), }; }; app .route({ path: 'file', key: 'list', middleware: ['auth'], }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; const data = ctx.query.data || {}; const { len, prefix } = getPrefixByUser(data, tokenUser); const recursive = data.recursive; const list = await getMinioList({ prefix: prefix.slice(1), recursive: recursive }); ctx.body = list.map((item) => { if ('prefix' in item) { return { ...item, prefix: item.prefix.slice(len), }; } else { return { ...item, name: item.name.slice(len) }; } }); return ctx; }) .addTo(app); app .route({ path: 'file', key: 'stat', middleware: ['auth'], }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; const data = ctx.query.data || {}; const { prefix } = getPrefixByUser(data, tokenUser); console.log('prefix', prefix); const stat = await getFileStat(prefix.slice(1)); ctx.body = stat; return ctx; }) .addTo(app); app .route({ path: 'file', key: 'me-all-file-stat', middleware: ['auth'], }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; const list = await getMinioList({ prefix: '' + tokenUser.username, recursive: true }); const size = list.reduce((acc, item) => { if ('size' in item) { return acc + item.size; } return acc; }, 0); const sizeMb = size / 1024 / 1024; ctx.body = { list, total: list.length, size, sizeMb, }; }) .addTo(app); app .route({ path: 'file', key: 'delete', middleware: ['auth'], }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; const data = ctx.query.data || {}; const { prefix } = getPrefixByUser(data, tokenUser); const [username, appKey, version] = prefix.slice(1).split('/'); const res = await deleteFile(prefix.slice(1)); if (res.code === 200) { ctx.body = 'delete success'; } else { ctx.throw(500, res.message || 'delete failed'); } const r = await callDetectAppVersion({ appKey, version, username }, ctx.query.token); if (r.code !== 200) { console.error('callDetectAppVersion failed', r, prefix); } }) .addTo(app); app .route({ path: 'file', key: 'update-metadata', middleware: ['auth'], }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; const data = ctx.query.data || {}; if (!data.metadata || JSON.stringify(data.metadata) === '{}') { ctx.throw(400, 'metadata is required'); } const { prefix } = getPrefixByUser(data, tokenUser); const res = await updateFileStat(prefix.slice(1), data.metadata); if (res.code === 200) { ctx.body = 'update metadata success'; } else { ctx.throw(500, res.message || 'update metadata failed'); } return ctx; }) .addTo(app); app .route({ path: 'file', key: 'delete-all', middleware: ['auth'], }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; let directory = ctx.query.data?.directory as string; if (!directory) { ctx.throw(400, 'directory is required'); } if (directory.startsWith('/')) { ctx.throw(400, 'directory is invalid, cannot start with /'); } if (directory.endsWith('/')) { ctx.throw(400, 'directory is invalid, cannot end with /'); } const prefix = tokenUser.username + '/' + directory + '/'; const list = await getMinioList({ prefix, recursive: true }); if (list.length === 0) { ctx.throw(400, 'directory is empty'); } const res = await deleteFiles(list.map((item) => item.name)); if (!res) { ctx.throw(500, 'delete all failed'); } ctx.body = { deleted: list.length, message: 'delete all success', }; }) .addTo(app);