@@ -14,6 +14,7 @@ import {
1414import { randomBytes } from 'crypto' ;
1515import { AttachmentResponseDto } from '../tasks/dto/task-responses.dto' ;
1616import { UploadAttachmentDto } from './upload-attachment.dto' ;
17+ import { s3Client } from '@/app/s3' ;
1718
1819@Injectable ( )
1920export class AttachmentsService {
@@ -27,20 +28,14 @@ export class AttachmentsService {
2728 // Safe to access environment variables directly since they're validated
2829 this . bucketName = process . env . APP_AWS_BUCKET_NAME ! ;
2930
30- if (
31- ! process . env . APP_AWS_ACCESS_KEY_ID ||
32- ! process . env . APP_AWS_SECRET_ACCESS_KEY
33- ) {
34- console . warn ( 'AWS credentials are missing, S3 client may fail' ) ;
31+ if ( ! s3Client ) {
32+ console . error ( 'S3 Client is not initialized. Check AWS S3 configuration.' ) ;
33+ throw new Error (
34+ 'S3 Client is not initialized. Check AWS S3 configuration.' ,
35+ ) ;
3536 }
3637
37- this . s3Client = new S3Client ( {
38- region : process . env . APP_AWS_REGION || 'us-east-1' ,
39- credentials : {
40- accessKeyId : process . env . APP_AWS_ACCESS_KEY_ID ! ,
41- secretAccessKey : process . env . APP_AWS_SECRET_ACCESS_KEY ! ,
42- } ,
43- } ) ;
38+ this . s3Client = s3Client ;
4439 }
4540
4641 /**
@@ -385,6 +380,25 @@ export class AttachmentsService {
385380 return this . generateSignedUrl ( s3Key ) ;
386381 }
387382
383+ /**
384+ * Generate presigned download URL with a custom download filename
385+ */
386+ async getPresignedDownloadUrlWithFilename (
387+ s3Key : string ,
388+ downloadFilename : string ,
389+ ) : Promise < string > {
390+ const sanitizedFilename = this . sanitizeHeaderValue ( downloadFilename ) ;
391+ const getCommand = new GetObjectCommand ( {
392+ Bucket : this . bucketName ,
393+ Key : s3Key ,
394+ ResponseContentDisposition : `attachment; filename="${ sanitizedFilename } "` ,
395+ } ) ;
396+
397+ return getSignedUrl ( this . s3Client , getCommand , {
398+ expiresIn : this . SIGNED_URL_EXPIRY ,
399+ } ) ;
400+ }
401+
388402 async getObjectBuffer ( s3Key : string ) : Promise < Buffer > {
389403 const getCommand = new GetObjectCommand ( {
390404 Bucket : this . bucketName ,
0 commit comments