From 7331cc78f54127973a7877594c8491611e4e6788 Mon Sep 17 00:00:00 2001 From: chenos Date: Fri, 14 Mar 2025 20:18:14 +0800 Subject: [PATCH] fix: unable to delete files stored in S3 (#6467) --- .../src/server/storages/s3.ts | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/packages/plugins/@nocobase/plugin-file-manager/src/server/storages/s3.ts b/packages/plugins/@nocobase/plugin-file-manager/src/server/storages/s3.ts index 19670740a2..a8e6114d60 100644 --- a/packages/plugins/@nocobase/plugin-file-manager/src/server/storages/s3.ts +++ b/packages/plugins/@nocobase/plugin-file-manager/src/server/storages/s3.ts @@ -7,6 +7,8 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ +import { DeleteObjectsCommand } from '@aws-sdk/client-s3'; +import crypto from 'crypto'; import { AttachmentModel, StorageType } from '.'; import { STORAGE_TYPE_S3 } from '../../constants'; import { cloudFilenameGetter, getFileKey } from '../utils'; @@ -62,18 +64,39 @@ export default class extends StorageType { }); } - async delete(records: AttachmentModel[]): Promise<[number, AttachmentModel[]]> { - const { DeleteObjectsCommand } = require('@aws-sdk/client-s3'); - const { s3 } = this.make(); - const { Deleted } = await s3.send( - new DeleteObjectsCommand({ - Bucket: this.storage.options.bucket, - Delete: { - Objects: records.map((record) => ({ Key: getFileKey(record) })), - }, - }), - ); + calculateContentMD5(body) { + const hash = crypto.createHash('md5').update(body).digest('base64'); + return hash; + } + async deleteS3Objects(bucketName: string, objects: string[]) { + const deleteBody = JSON.stringify({ + Objects: objects.map((objectKey) => ({ Key: objectKey })), + }); + + const contentMD5 = this.calculateContentMD5(deleteBody); + + const deleteCommand = new DeleteObjectsCommand({ + Bucket: bucketName, + Delete: JSON.parse(deleteBody), + }); + + deleteCommand.middlewareStack.add( + (next, context) => async (args) => { + args.request['headers']['Content-Md5'] = contentMD5; + return next(args); + }, + { step: 'build' }, + ); + const { s3 } = this.make(); + return await s3.send(deleteCommand); + } + + async delete(records: AttachmentModel[]): Promise<[number, AttachmentModel[]]> { + const { Deleted } = await this.deleteS3Objects( + this.storage.options.bucket, + records.map((record) => getFileKey(record)), + ); return [Deleted.length, records.filter((record) => !Deleted.find((item) => item.Key === getFileKey(record)))]; } }