mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-08 06:59:26 +08:00
refactor(plugin-file-manager): move destroy to collection event (#6127)
This commit is contained in:
parent
19ffa45ee9
commit
55a7d9a828
@ -129,69 +129,3 @@ export async function createMiddleware(ctx: Context, next: Next) {
|
|||||||
|
|
||||||
await multipart(ctx, next);
|
await multipart(ctx, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroyMiddleware(ctx: Context, next: Next) {
|
|
||||||
const { resourceName, actionName, sourceId } = ctx.action;
|
|
||||||
const collection = ctx.db.getCollection(resourceName);
|
|
||||||
|
|
||||||
if (collection?.options?.template !== 'file' || actionName !== 'destroy') {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
const repository = ctx.db.getRepository(resourceName, sourceId);
|
|
||||||
|
|
||||||
const { filterByTk, filter } = ctx.action.params;
|
|
||||||
|
|
||||||
const records = await repository.find({
|
|
||||||
filterByTk,
|
|
||||||
filter,
|
|
||||||
context: ctx,
|
|
||||||
});
|
|
||||||
|
|
||||||
const storageIds = new Set(records.map((record) => record.storageId));
|
|
||||||
const storageGroupedRecords = records.reduce((result, record) => {
|
|
||||||
const storageId = record.storageId;
|
|
||||||
if (!result[storageId]) {
|
|
||||||
result[storageId] = [];
|
|
||||||
}
|
|
||||||
result[storageId].push(record);
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const storages = await ctx.db.getRepository('storages').find({
|
|
||||||
filter: {
|
|
||||||
id: [...storageIds] as any[],
|
|
||||||
paranoid: {
|
|
||||||
$ne: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let count = 0;
|
|
||||||
const undeleted = [];
|
|
||||||
await storages.reduce(
|
|
||||||
(promise, storage) =>
|
|
||||||
promise.then(async () => {
|
|
||||||
const storageConfig = ctx.app.pm.get(Plugin).storageTypes.get(storage.type);
|
|
||||||
const result = await storageConfig.delete(storage, storageGroupedRecords[storage.id]);
|
|
||||||
count += result[0];
|
|
||||||
undeleted.push(...result[1]);
|
|
||||||
}),
|
|
||||||
Promise.resolve(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (undeleted.length) {
|
|
||||||
const ids = undeleted.map((record) => record.id);
|
|
||||||
ctx.action.mergeParams({
|
|
||||||
filter: {
|
|
||||||
id: {
|
|
||||||
$notIn: ids,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.logger.error('[file-manager] some of attachment files are not successfully deleted: ', { ids });
|
|
||||||
}
|
|
||||||
|
|
||||||
await next();
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import actions from '@nocobase/actions';
|
import actions from '@nocobase/actions';
|
||||||
import { createMiddleware, destroyMiddleware } from './attachments';
|
import { createMiddleware } from './attachments';
|
||||||
import * as storageActions from './storages';
|
import * as storageActions from './storages';
|
||||||
|
|
||||||
export default function ({ app }) {
|
export default function ({ app }) {
|
||||||
@ -18,6 +18,4 @@ export default function ({ app }) {
|
|||||||
});
|
});
|
||||||
app.resourcer.use(createMiddleware, { tag: 'createMiddleware', after: 'auth' });
|
app.resourcer.use(createMiddleware, { tag: 'createMiddleware', after: 'auth' });
|
||||||
app.resourcer.registerActionHandler('upload', actions.create);
|
app.resourcer.registerActionHandler('upload', actions.create);
|
||||||
|
|
||||||
app.resourcer.use(destroyMiddleware);
|
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,14 @@ import { Registry } from '@nocobase/utils';
|
|||||||
|
|
||||||
import { basename, resolve } from 'path';
|
import { basename, resolve } from 'path';
|
||||||
|
|
||||||
import { Transactionable } from '@nocobase/database';
|
import { Model, Transactionable } from '@nocobase/database';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { STORAGE_TYPE_ALI_OSS, STORAGE_TYPE_LOCAL, STORAGE_TYPE_S3, STORAGE_TYPE_TX_COS } from '../constants';
|
import { STORAGE_TYPE_ALI_OSS, STORAGE_TYPE_LOCAL, STORAGE_TYPE_S3, STORAGE_TYPE_TX_COS } from '../constants';
|
||||||
import { FileModel } from './FileModel';
|
import { FileModel } from './FileModel';
|
||||||
import initActions from './actions';
|
import initActions from './actions';
|
||||||
import { getFileData } from './actions/attachments';
|
import { getFileData } from './actions/attachments';
|
||||||
import { AttachmentInterface } from './interfaces/attachment-interface';
|
import { AttachmentInterface } from './interfaces/attachment-interface';
|
||||||
import { IStorage, StorageModel } from './storages';
|
import { AttachmentModel, IStorage, StorageModel } from './storages';
|
||||||
import StorageTypeAliOss from './storages/ali-oss';
|
import StorageTypeAliOss from './storages/ali-oss';
|
||||||
import StorageTypeLocal from './storages/local';
|
import StorageTypeLocal from './storages/local';
|
||||||
import StorageTypeS3 from './storages/s3';
|
import StorageTypeS3 from './storages/s3';
|
||||||
@ -29,6 +29,16 @@ export type * from './storages';
|
|||||||
|
|
||||||
const DEFAULT_STORAGE_TYPE = STORAGE_TYPE_LOCAL;
|
const DEFAULT_STORAGE_TYPE = STORAGE_TYPE_LOCAL;
|
||||||
|
|
||||||
|
class FileDeleteError extends Error {
|
||||||
|
data: Model;
|
||||||
|
|
||||||
|
constructor(message: string, data: Model) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'FileDeleteError';
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type FileRecordOptions = {
|
export type FileRecordOptions = {
|
||||||
collectionName: string;
|
collectionName: string;
|
||||||
filePath: string;
|
filePath: string;
|
||||||
@ -46,6 +56,23 @@ export class PluginFileManagerServer extends Plugin {
|
|||||||
storageTypes = new Registry<IStorage>();
|
storageTypes = new Registry<IStorage>();
|
||||||
storagesCache = new Map<number, StorageModel>();
|
storagesCache = new Map<number, StorageModel>();
|
||||||
|
|
||||||
|
afterDestroy = async (record: Model, options) => {
|
||||||
|
const { collection } = record.constructor as typeof Model;
|
||||||
|
if (collection?.options?.template !== 'file' && collection.name !== 'attachments') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storage = this.storagesCache.get(record.get('storageId'));
|
||||||
|
if (storage?.paranoid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const storageConfig = this.storageTypes.get(storage.type);
|
||||||
|
const result = await storageConfig.delete(storage, [record as unknown as AttachmentModel]);
|
||||||
|
if (!result[0]) {
|
||||||
|
throw new FileDeleteError('Failed to delete file', record);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
registerStorageType(type: string, options: IStorage) {
|
registerStorageType(type: string, options: IStorage) {
|
||||||
this.storageTypes.register(type, options);
|
this.storageTypes.register(type, options);
|
||||||
}
|
}
|
||||||
@ -184,6 +211,8 @@ export class PluginFileManagerServer extends Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
|
this.db.on('afterDestroy', this.afterDestroy);
|
||||||
|
|
||||||
this.storageTypes.register(STORAGE_TYPE_LOCAL, new StorageTypeLocal());
|
this.storageTypes.register(STORAGE_TYPE_LOCAL, new StorageTypeLocal());
|
||||||
this.storageTypes.register(STORAGE_TYPE_ALI_OSS, new StorageTypeAliOss());
|
this.storageTypes.register(STORAGE_TYPE_ALI_OSS, new StorageTypeAliOss());
|
||||||
this.storageTypes.register(STORAGE_TYPE_S3, new StorageTypeS3());
|
this.storageTypes.register(STORAGE_TYPE_S3, new StorageTypeS3());
|
||||||
@ -224,8 +253,7 @@ export class PluginFileManagerServer extends Plugin {
|
|||||||
|
|
||||||
initActions(this);
|
initActions(this);
|
||||||
|
|
||||||
this.app.acl.allow('attachments', 'upload', 'loggedIn');
|
this.app.acl.allow('attachments', ['upload', 'create', 'destroy'], 'loggedIn');
|
||||||
this.app.acl.allow('attachments', 'create', 'loggedIn');
|
|
||||||
this.app.acl.allow('storages', 'getRules', 'loggedIn');
|
this.app.acl.allow('storages', 'getRules', 'loggedIn');
|
||||||
|
|
||||||
// this.app.resourcer.use(uploadMiddleware);
|
// this.app.resourcer.use(uploadMiddleware);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user