import { Injectable, NotFoundException, ForbiddenException, } from '@nestjs/common'; import { FilesRepository } from './files.repository'; import { StorageService } from '../../infrastructure/storage/storage.service'; import { CosStorageProvider } from '../../infrastructure/storage/cos-storage.provider'; import { CreateUploadUrlDto, CompleteUploadDto } from './dto'; @Injectable() export class FilesService { constructor( private readonly repository: FilesRepository, private readonly storage: StorageService, private readonly cos: CosStorageProvider, ) {} async requestUploadUrl(userId: string, dto: CreateUploadUrlDto) { return this.storage.createUploadUrl(userId, { filename: dto.filename, mimeType: dto.mimeType, sizeBytes: dto.sizeBytes, }); } async confirmUpload(userId: string, dto: CompleteUploadDto) { const info = await this.storage.verifyUpload(dto.objectKey); const parts = dto.objectKey.split('/'); const originalFilename = parts[parts.length - 1]; return this.repository.create({ userId, filename: originalFilename, mimeType: info.contentType, storagePath: dto.objectKey, objectKey: dto.objectKey, bucket: this.cos.getBucket(), sizeBytes: info.size, checksum: dto.checksum, }); } async getFile(userId: string, fileId: string) { const file = await this.repository.findById(fileId); if (!file) { throw new NotFoundException('文件不存在'); } if (file.userId !== userId) { throw new ForbiddenException('无权访问该文件'); } const downloadUrl = await this.storage.getDownloadUrl(file.objectKey!); return { file, downloadUrl }; } async deleteFile(userId: string, fileId: string) { const file = await this.repository.findById(fileId); if (!file) { throw new NotFoundException('文件不存在'); } if (file.userId !== userId) { throw new ForbiddenException('无权操作该文件'); } await this.storage.deleteObject(file.objectKey!); await this.repository.delete(fileId); } async findByUserId(userId: string) { return this.repository.findByUserId(userId); } }