Update code via agent code generation

This commit is contained in:
Automated Action 2025-06-21 17:58:03 +00:00
parent a0aec8bfae
commit 939a1edbf6
3 changed files with 173 additions and 0 deletions

View File

@ -50,6 +50,8 @@
"uuid": "^9.0.0", "uuid": "^9.0.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"firebase-admin": "^11.10.1", "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", "reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1" "rxjs": "^7.8.1"
}, },

161
src/aws/aws-s3.service.ts Normal file
View 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
View 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 {}