diff --git a/packages/core/src/core/file-storage/providers/s3.provider.ts b/packages/core/src/core/file-storage/providers/s3.provider.ts index 1eae6f6418f..a51c3f9dc53 100644 --- a/packages/core/src/core/file-storage/providers/s3.provider.ts +++ b/packages/core/src/core/file-storage/providers/s3.provider.ts @@ -184,10 +184,7 @@ export class S3Provider extends Provider { if (filename) { fileName = typeof filename === 'string' ? filename : filename(file, extension); } else { - fileName = `${prefix}-${moment().unix()}-${parseInt( - '' + Math.random() * 1000, - 10 - )}.${extension}`; + fileName = `${prefix}-${moment().unix()}-${parseInt('' + Math.random() * 1000, 10)}.${extension}`; } // Replace double backslashes with single forward slashes @@ -241,6 +238,9 @@ export class S3Provider extends Provider { */ async putFile(fileContent: string, key: string = ''): Promise { try { + // Replace double backslashes with single forward slashes + key = key.replace(/\\/g, '/'); + const s3Client = this.getS3Instance(); const filename = basename(key); @@ -332,7 +332,12 @@ export class S3Provider extends Provider { accessKeyId: this.config.aws_access_key_id, secretAccessKey: this.config.aws_secret_access_key }, - region + region, + /** + * Whether to force path style URLs for S3 objects + * (e.g., https://s3.amazonaws.com// instead of https://.s3.amazonaws.com/ + */ + forcePathStyle: true }); return s3Client; diff --git a/packages/core/src/core/file-storage/providers/wasabi-s3.provider.ts b/packages/core/src/core/file-storage/providers/wasabi-s3.provider.ts index 74ea952c0c4..d18d7699371 100644 --- a/packages/core/src/core/file-storage/providers/wasabi-s3.provider.ts +++ b/packages/core/src/core/file-storage/providers/wasabi-s3.provider.ts @@ -295,10 +295,7 @@ export class WasabiS3Provider extends Provider { if (filename) { fileName = typeof filename === 'string' ? filename : filename(file, extension); } else { - fileName = `${prefix}-${moment().unix()}-${parseInt( - '' + Math.random() * 1000, - 10 - )}.${extension}`; + fileName = `${prefix}-${moment().unix()}-${parseInt('' + Math.random() * 1000, 10)}.${extension}`; } // Replace double backslashes with single forward slashes @@ -356,6 +353,9 @@ export class WasabiS3Provider extends Provider { */ async putFile(fileContent: string, key: string = ''): Promise { try { + // Replace double backslashes with single forward slashes + key = key.replace(/\\/g, '/'); + const s3Client = this.getWasabiInstance(); if (s3Client) { @@ -460,7 +460,14 @@ export class WasabiS3Provider extends Provider { secretAccessKey: this.config.wasabi_aws_secret_access_key }, region: this.config.wasabi_aws_default_region || 'us-east-1', - endpoint + endpoint, + /** + * Whether to force path style URLs for S3 objects + * + * https://s3.wasabisys.com + * (e.g., https://s3.wasabisys.com// instead of https://.s3.wasabisys.com/ + */ + forcePathStyle: true }); return s3Client; diff --git a/packages/core/src/image-asset/image-asset.controller.ts b/packages/core/src/image-asset/image-asset.controller.ts index e4be83a5b5b..5b88db3dd73 100644 --- a/packages/core/src/image-asset/image-asset.controller.ts +++ b/packages/core/src/image-asset/image-asset.controller.ts @@ -57,8 +57,14 @@ export class ImageAssetController extends CrudController { const request: any = ctx.switchToHttp().getRequest(); const folder: string = request?.params?.folder || 'image_assets'; + // Define the base directory for storing media + const baseDirectory = path.join('uploads', folder); + + // Generate unique sub directories based on the current tenant + const subDirectory = path.join(RequestContext.currentTenantId() || uuid()); + return new FileStorage().storage({ - dest: () => path.join('uploads', folder, RequestContext.currentTenantId() || uuid()) + dest: () => path.join(baseDirectory, subDirectory), }); } }) @@ -94,7 +100,10 @@ export class ImageAssetController extends CrudController { const thumbName = `thumb-${file.filename}`; const thumbDir = path.dirname(file.key); - thumbnail = await provider.putFile(data, path.join(thumbDir, thumbName)); + // Replace double backslashes with single forward slashes + const fullPath = path.join(thumbDir, thumbName).replace(/\\/g, '/'); + + thumbnail = await provider.putFile(data, fullPath); } catch (error) { console.error('Error while uploading media asset into file storage provider:', error); }