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()}`;
}