fix: getFileKey (#6523)

* fix: getFileKey

* fix: storage cannot be deleted
This commit is contained in:
chenos 2025-03-22 05:13:24 +08:00 committed by GitHub
parent 1470ed902a
commit 44ee058730
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 30 additions and 6 deletions

View File

@ -62,11 +62,21 @@ export class PluginFileManagerServer extends Plugin {
return; return;
} }
if (!record.get('storageId')) {
return;
}
const storage = this.storagesCache.get(record.get('storageId')); const storage = this.storagesCache.get(record.get('storageId'));
if (!storage) {
return;
}
if (storage?.paranoid) { if (storage?.paranoid) {
return; return;
} }
const Type = this.storageTypes.get(storage.type); const Type = this.storageTypes.get(storage.type);
if (!Type) {
return;
}
const storageConfig = new Type(storage); const storageConfig = new Type(storage);
const result = await storageConfig.delete([record as unknown as AttachmentModel]); const result = await storageConfig.delete([record as unknown as AttachmentModel]);
if (!result[0]) { if (!result[0]) {
@ -245,6 +255,15 @@ export class PluginFileManagerServer extends Plugin {
); );
}); });
Storage.afterDestroy((m, { transaction }) => { Storage.afterDestroy((m, { transaction }) => {
for (const collection of this.db.collections.values()) {
if (collection?.options?.template === 'file' && collection?.options?.storage === m.name) {
throw new Error(
this.t(
`The storage "${m.name}" is in use in collection "${collection.name}" and cannot be deleted.`,
) as any,
);
}
}
this.storagesCache.delete(m.id); this.storagesCache.delete(m.id);
this.sendSyncMessage( this.sendSyncMessage(
{ {

View File

@ -10,7 +10,7 @@
import { isURL } from '@nocobase/utils'; import { isURL } from '@nocobase/utils';
import { StorageEngine } from 'multer'; import { StorageEngine } from 'multer';
import urlJoin from 'url-join'; import urlJoin from 'url-join';
import { encodeURL, ensureUrlEncoded } from '../utils'; import { encodeURL, ensureUrlEncoded, getFileKey } from '../utils';
export interface StorageModel { export interface StorageModel {
id?: number; id?: number;
@ -42,6 +42,10 @@ export abstract class StorageType {
abstract make(): StorageEngine; abstract make(): StorageEngine;
abstract delete(records: AttachmentModel[]): [number, AttachmentModel[]] | Promise<[number, AttachmentModel[]]>; abstract delete(records: AttachmentModel[]): [number, AttachmentModel[]] | Promise<[number, AttachmentModel[]]>;
getFileKey(record: AttachmentModel) {
return getFileKey(record);
}
getFileData?(file: { [key: string]: any }): { [key: string]: any }; getFileData?(file: { [key: string]: any }): { [key: string]: any };
getFileURL(file: AttachmentModel, preview?: boolean): string | Promise<string> { getFileURL(file: AttachmentModel, preview?: boolean): string | Promise<string> {
// 兼容历史数据 // 兼容历史数据

View File

@ -7,11 +7,11 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { S3Client, DeleteObjectCommand } from '@aws-sdk/client-s3'; import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3';
import crypto from 'crypto'; import crypto from 'crypto';
import { AttachmentModel, StorageType } from '.'; import { AttachmentModel, StorageType } from '.';
import { STORAGE_TYPE_S3 } from '../../constants'; import { STORAGE_TYPE_S3 } from '../../constants';
import { cloudFilenameGetter, getFileKey } from '../utils'; import { cloudFilenameGetter } from '../utils';
export default class extends StorageType { export default class extends StorageType {
static defaults() { static defaults() {
@ -87,8 +87,8 @@ export default class extends StorageType {
async delete(records: AttachmentModel[]): Promise<[number, AttachmentModel[]]> { async delete(records: AttachmentModel[]): Promise<[number, AttachmentModel[]]> {
const { Deleted } = await this.deleteS3Objects( const { Deleted } = await this.deleteS3Objects(
this.storage.options.bucket, this.storage.options.bucket,
records.map((record) => getFileKey(record)), records.map((record) => this.getFileKey(record)),
); );
return [Deleted.length, records.filter((record) => !Deleted.find((item) => item.Key === getFileKey(record)))]; return [Deleted.length, records.filter((record) => !Deleted.find((item) => item.Key === this.getFileKey(record)))];
} }
} }

View File

@ -9,6 +9,7 @@
import { uid } from '@nocobase/utils'; import { uid } from '@nocobase/utils';
import path from 'path'; import path from 'path';
import urlJoin from 'url-join';
export function getFilename(req, file, cb) { export function getFilename(req, file, cb) {
const originalname = Buffer.from(file.originalname, 'binary').toString('utf8'); const originalname = Buffer.from(file.originalname, 'binary').toString('utf8');
@ -27,7 +28,7 @@ export const cloudFilenameGetter = (storage) => (req, file, cb) => {
}; };
export function getFileKey(record) { export function getFileKey(record) {
return [record.path.replace(/^\/|\/$/g, ''), record.filename].filter(Boolean).join('/'); return urlJoin(record.path, record.filename).replace(/^\//, '');
} }
export function ensureUrlEncoded(value) { export function ensureUrlEncoded(value) {