diff --git a/server/admin/src/client/App.tsx b/server/admin/src/client/App.tsx index 30ea8305..9f8be26c 100644 --- a/server/admin/src/client/App.tsx +++ b/server/admin/src/client/App.tsx @@ -23,15 +23,11 @@ import { } from 'tushan/icon'; import { authHTTPClient, authProvider } from './auth'; import { Dashboard } from './components/Dashboard'; -import { - discoverFields, - fileFields, - mailFields, - messageFields, -} from './fields'; +import { discoverFields, mailFields, messageFields } from './fields'; import { i18n } from './i18n'; import { GroupList } from './resources/group'; import { UserList } from './resources/user'; +import { FileList } from './resources/file'; import { TailchatAnalytics } from './routes/analytics'; import { CacheManager } from './routes/cache'; import { TailchatNetwork } from './routes/network'; @@ -84,21 +80,7 @@ function App() { } list={} /> - } - list={ - - } - /> + } list={} /> { + return ( + + ); +}); +FileList.displayName = 'FileList'; diff --git a/server/admin/src/server/router/api.ts b/server/admin/src/server/router/api.ts index 43f0c9a8..2802e7f6 100644 --- a/server/admin/src/server/router/api.ts +++ b/server/admin/src/server/router/api.ts @@ -8,6 +8,7 @@ import { fileRouter } from './file'; import dayjs from 'dayjs'; import userModel from '../../../../models/user/user'; import messageModel from '../../../../models/chat/message'; +import fileModel from '../../../../models/file'; import groupModel from '../../../../models/group/group'; import { raExpressMongoose } from '../middleware/express-mongoose-ra-json-server'; import { cacheRouter } from './cache'; @@ -269,11 +270,33 @@ router.use( }, }) ); + +router.delete('/file/:id', auth(), async (req, res) => { + try { + const fileId = req.params.id; + + const record = await fileModel.findById(fileId); + if (record) { + await callBrokerAction('file.delete', { + objectName: record.objectName, + }); + } + + res.json({ id: fileId }); + } catch (err) { + console.error(err); + res.status(500).json({ message: (err as any).message }); + } +}); router.use( '/file', auth(), - raExpressMongoose(require('../../../../models/file').default, { + raExpressMongoose(fileModel, { q: ['objectName'], + allowedRegexFields: ['objectName'], + capabilities: { + delete: false, + }, }) ); router.use( diff --git a/server/services/core/file.service.ts b/server/services/core/file.service.ts index ccb2feb3..1d35aaea 100644 --- a/server/services/core/file.service.ts +++ b/server/services/core/file.service.ts @@ -59,6 +59,13 @@ class FileService extends TcService { }, disableSocket: true, }); + this.registerAction('delete', this.delete, { + params: { + objectName: 'string', + }, + disableSocket: true, + visibility: 'public', + }); } async onInited() { @@ -307,19 +314,36 @@ class FileService extends TcService { ) { const objectName = ctx.params.objectName; - const stream = await this.actions['getObject']( - { - bucketName: this.bucketName, - objectName, - }, - { - parentCtx: ctx, - } + const stream = await this.minioClient.getObject( + this.bucketName, + objectName ); return stream; } + /** + * 删除文件 + */ + async delete( + ctx: TcContext<{ + objectName: string; + }> + ) { + const objectName = ctx.params.objectName; + + try { + // 先删文件再删记录,确保文件被删除 + await this.minioClient.removeObject(this.bucketName, objectName); + await this.adapter.model.deleteMany({ + bucketName: this.bucketName, + objectName, + }); + } catch (err) { + this.logger.warn('Delete file error:', objectName, err); + } + } + private randomName() { return `unnamed_${this.broker.nodeID}_${Date.now()}`; }