Update code via agent code generation
This commit is contained in:
parent
a0aec8bfae
commit
939a1edbf6
@ -50,6 +50,8 @@
|
||||
"uuid": "^9.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"firebase-admin": "^11.10.1",
|
||||
"@aws-sdk/client-s3": "^3.450.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.450.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
|
161
src/aws/aws-s3.service.ts
Normal file
161
src/aws/aws-s3.service.ts
Normal file
@ -0,0 +1,161 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
@Injectable()
|
||||
export class AwsS3Service {
|
||||
private readonly logger = new Logger(AwsS3Service.name);
|
||||
private readonly s3Client: S3Client;
|
||||
private readonly bucketName: string;
|
||||
private readonly region: string;
|
||||
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
this.region = this.configService.get<string>('AWS_REGION') || 'us-east-1';
|
||||
this.bucketName = this.configService.get<string>('AWS_S3_BUCKET_NAME');
|
||||
|
||||
if (!this.bucketName) {
|
||||
throw new Error('AWS_S3_BUCKET_NAME environment variable is required');
|
||||
}
|
||||
|
||||
this.s3Client = new S3Client({
|
||||
region: this.region,
|
||||
credentials: {
|
||||
accessKeyId: this.configService.get<string>('AWS_ACCESS_KEY_ID'),
|
||||
secretAccessKey: this.configService.get<string>('AWS_SECRET_ACCESS_KEY'),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async uploadFile(
|
||||
file: Express.Multer.File,
|
||||
folder: string = 'uploads',
|
||||
organizationId?: string,
|
||||
): Promise<{ key: string; url: string }> {
|
||||
try {
|
||||
const fileExtension = file.originalname.split('.').pop();
|
||||
const fileName = `${uuidv4()}.${fileExtension}`;
|
||||
const key = organizationId
|
||||
? `${folder}/${organizationId}/${fileName}`
|
||||
: `${folder}/${fileName}`;
|
||||
|
||||
const command = new PutObjectCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: key,
|
||||
Body: file.buffer,
|
||||
ContentType: file.mimetype,
|
||||
Metadata: {
|
||||
originalName: file.originalname,
|
||||
uploadedAt: new Date().toISOString(),
|
||||
...(organizationId && { organizationId }),
|
||||
},
|
||||
});
|
||||
|
||||
await this.s3Client.send(command);
|
||||
|
||||
// Generate presigned URL for the uploaded file
|
||||
const presignedUrl = await this.getPresignedUrl(key);
|
||||
|
||||
this.logger.log(`File uploaded successfully: ${key}`);
|
||||
return { key, url: presignedUrl };
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to upload file: ${error.message}`);
|
||||
throw new Error(`Failed to upload file: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getPresignedUrl(key: string, expiresIn: number = 3600): Promise<string> {
|
||||
try {
|
||||
const command = new GetObjectCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: key,
|
||||
});
|
||||
|
||||
const presignedUrl = await getSignedUrl(this.s3Client, command, {
|
||||
expiresIn,
|
||||
});
|
||||
|
||||
return presignedUrl;
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to generate presigned URL: ${error.message}`);
|
||||
throw new Error(`Failed to generate presigned URL: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async deleteFile(key: string): Promise<void> {
|
||||
try {
|
||||
const command = new DeleteObjectCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: key,
|
||||
});
|
||||
|
||||
await this.s3Client.send(command);
|
||||
this.logger.log(`File deleted successfully: ${key}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to delete file: ${error.message}`);
|
||||
throw new Error(`Failed to delete file: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async uploadAvatar(
|
||||
file: Express.Multer.File,
|
||||
userId: string,
|
||||
organizationId?: string,
|
||||
): Promise<{ key: string; url: string }> {
|
||||
const folder = organizationId ? `avatars/${organizationId}` : 'avatars';
|
||||
const key = `${folder}/${userId}-${uuidv4()}.${file.originalname.split('.').pop()}`;
|
||||
|
||||
try {
|
||||
const command = new PutObjectCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: key,
|
||||
Body: file.buffer,
|
||||
ContentType: file.mimetype,
|
||||
Metadata: {
|
||||
userId,
|
||||
type: 'avatar',
|
||||
uploadedAt: new Date().toISOString(),
|
||||
...(organizationId && { organizationId }),
|
||||
},
|
||||
});
|
||||
|
||||
await this.s3Client.send(command);
|
||||
|
||||
const presignedUrl = await this.getPresignedUrl(key);
|
||||
|
||||
this.logger.log(`Avatar uploaded successfully: ${key}`);
|
||||
return { key, url: presignedUrl };
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to upload avatar: ${error.message}`);
|
||||
throw new Error(`Failed to upload avatar: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async uploadChatMedia(
|
||||
file: Express.Multer.File,
|
||||
chatRoomId: string,
|
||||
organizationId: string,
|
||||
): Promise<{ key: string; url: string; type: string }> {
|
||||
const mediaType = this.getMediaType(file.mimetype);
|
||||
const folder = `chat-media/${organizationId}/${chatRoomId}/${mediaType}`;
|
||||
|
||||
return this.uploadFile(file, folder, organizationId);
|
||||
}
|
||||
|
||||
private getMediaType(mimetype: string): string {
|
||||
if (mimetype.startsWith('image/')) return 'images';
|
||||
if (mimetype.startsWith('video/')) return 'videos';
|
||||
if (mimetype.startsWith('audio/')) return 'audio';
|
||||
if (mimetype.includes('pdf') || mimetype.includes('document')) return 'documents';
|
||||
return 'files';
|
||||
}
|
||||
|
||||
getBucketName(): string {
|
||||
return this.bucketName;
|
||||
}
|
||||
|
||||
getRegion(): string {
|
||||
return this.region;
|
||||
}
|
||||
}
|
10
src/aws/aws.module.ts
Normal file
10
src/aws/aws.module.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AwsS3Service } from './aws-s3.service';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
providers: [AwsS3Service],
|
||||
exports: [AwsS3Service],
|
||||
})
|
||||
export class AwsModule {}
|
Loading…
x
Reference in New Issue
Block a user