feat(admin): add file delete action which delete minio file also and allow fuzzy match of objectName

pull/146/head
moonrailgun 2 years ago
parent 17464b0c6f
commit c98dc4714d

@ -23,15 +23,11 @@ import {
} from 'tushan/icon'; } from 'tushan/icon';
import { authHTTPClient, authProvider } from './auth'; import { authHTTPClient, authProvider } from './auth';
import { Dashboard } from './components/Dashboard'; import { Dashboard } from './components/Dashboard';
import { import { discoverFields, mailFields, messageFields } from './fields';
discoverFields,
fileFields,
mailFields,
messageFields,
} from './fields';
import { i18n } from './i18n'; import { i18n } from './i18n';
import { GroupList } from './resources/group'; import { GroupList } from './resources/group';
import { UserList } from './resources/user'; import { UserList } from './resources/user';
import { FileList } from './resources/file';
import { TailchatAnalytics } from './routes/analytics'; import { TailchatAnalytics } from './routes/analytics';
import { CacheManager } from './routes/cache'; import { CacheManager } from './routes/cache';
import { TailchatNetwork } from './routes/network'; import { TailchatNetwork } from './routes/network';
@ -84,21 +80,7 @@ function App() {
<Resource name="groups" icon={<IconUserGroup />} list={<GroupList />} /> <Resource name="groups" icon={<IconUserGroup />} list={<GroupList />} />
<Resource <Resource name="file" icon={<IconFile />} list={<FileList />} />
name="file"
icon={<IconFile />}
list={
<ListTable
filter={[
createTextField('q', {
label: 'Search',
}),
]}
fields={fileFields}
action={{ detail: true }}
/>
}
/>
<Resource <Resource
name="mail" name="mail"

@ -0,0 +1,19 @@
import React from 'react';
import { createTextField, ListTable } from 'tushan';
import { fileFields } from '../fields';
export const FileList: React.FC = React.memo(() => {
return (
<ListTable
filter={[
createTextField('q', {
label: 'Search',
}),
]}
fields={fileFields}
action={{ detail: true, delete: true }}
batchAction={{ delete: true }}
/>
);
});
FileList.displayName = 'FileList';

@ -8,6 +8,7 @@ import { fileRouter } from './file';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import userModel from '../../../../models/user/user'; import userModel from '../../../../models/user/user';
import messageModel from '../../../../models/chat/message'; import messageModel from '../../../../models/chat/message';
import fileModel from '../../../../models/file';
import groupModel from '../../../../models/group/group'; import groupModel from '../../../../models/group/group';
import { raExpressMongoose } from '../middleware/express-mongoose-ra-json-server'; import { raExpressMongoose } from '../middleware/express-mongoose-ra-json-server';
import { cacheRouter } from './cache'; 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( router.use(
'/file', '/file',
auth(), auth(),
raExpressMongoose(require('../../../../models/file').default, { raExpressMongoose(fileModel, {
q: ['objectName'], q: ['objectName'],
allowedRegexFields: ['objectName'],
capabilities: {
delete: false,
},
}) })
); );
router.use( router.use(

@ -59,6 +59,13 @@ class FileService extends TcService {
}, },
disableSocket: true, disableSocket: true,
}); });
this.registerAction('delete', this.delete, {
params: {
objectName: 'string',
},
disableSocket: true,
visibility: 'public',
});
} }
async onInited() { async onInited() {
@ -307,19 +314,36 @@ class FileService extends TcService {
) { ) {
const objectName = ctx.params.objectName; const objectName = ctx.params.objectName;
const stream = await this.actions['getObject']( const stream = await this.minioClient.getObject(
{ this.bucketName,
bucketName: this.bucketName, objectName
objectName,
},
{
parentCtx: ctx,
}
); );
return stream; 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() { private randomName() {
return `unnamed_${this.broker.nodeID}_${Date.now()}`; return `unnamed_${this.broker.nodeID}_${Date.now()}`;
} }

Loading…
Cancel
Save