Files
zod-backend/src/document/services/oci.service.ts
T

110 lines
4.7 KiB
TypeScript

import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { plainToInstance } from 'class-transformer';
import moment from 'moment';
import { Region, SimpleAuthenticationDetailsProvider } from 'oci-common';
import { ObjectStorageClient } from 'oci-objectstorage';
import { CreatePreauthenticatedRequestDetails } from 'oci-objectstorage/lib/model';
import path from 'path';
import { CacheService } from '~/common/modules/cache/services';
import { BUCKETS } from '../constants';
import { UploadDocumentRequestDto } from '../dtos/request';
import { UploadResponseDto } from '../dtos/response';
import { Document } from '../entities';
import { generateNewFileName } from '../utils';
const TWO = 2;
@Injectable()
export class OciService {
private readonly ociClient: ObjectStorageClient;
private readonly tenancyId: string = this.configService.getOrThrow('OCI_TENANCY_ID');
private readonly userId: string = this.configService.getOrThrow('OCI_USER_ID');
private readonly fingerprint: string = this.configService.getOrThrow('OCI_FINGERPRINT');
private readonly privateKey: string = this.configService.getOrThrow('OCI_PRIVATE_KEY');
private readonly passPhrase: string = this.configService.getOrThrow('OCI_PASSPHRASE');
private readonly namespace: string = this.configService.getOrThrow('OCI_NAMESPACE');
private readonly region: string = this.configService.getOrThrow('OCI_REGION');
private readonly logger = new Logger(OciService.name);
constructor(private configService: ConfigService, private readonly cacheService: CacheService) {
this.ociClient = new ObjectStorageClient({
authenticationDetailsProvider: new SimpleAuthenticationDetailsProvider(
this.tenancyId,
this.userId,
this.fingerprint,
Buffer.from(this.privateKey, 'base64').toString('utf-8'),
this.passPhrase,
Region.fromRegionId(this.region),
),
});
}
async uploadFile(file: Express.Multer.File, { documentType }: UploadDocumentRequestDto): Promise<UploadResponseDto> {
this.logger.log(`Uploading file with type ${documentType}`);
const bucketName = BUCKETS[documentType];
const objectName = generateNewFileName(file.originalname);
if (!bucketName) {
this.logger.error('Could not find bucket name for document type', documentType);
throw new BadRequestException('DOCUMENT.TYPE_NOT_SUPPORTED');
}
this.logger.debug(`Uploading file to bucket ${bucketName} with object name ${objectName}`);
await this.ociClient.putObject({
namespaceName: this.namespace,
bucketName,
putObjectBody: file.buffer,
contentLength: file.buffer.length,
objectName,
});
this.logger.log(`File uploaded successfully to bucket ${bucketName} with object name ${objectName}`);
return plainToInstance(UploadResponseDto, {
name: objectName,
extension: path.extname(file.originalname),
url: `https://objectstorage.${this.region}.oraclecloud.com/n/${this.namespace}/b/${bucketName}/o/${objectName}`,
documentType,
});
}
async generatePreSignedUrl(document?: Document): Promise<string | any> {
this.logger.log(`Generating pre-signed url for document ${document?.id}`);
if (!document) {
this.logger.error('Document not found, skipping pre-signed url generation');
return null;
}
const cachedUrl = await this.cacheService.get<string>(document.id);
if (cachedUrl) {
this.logger.debug(`Returning cached pre-signed url for document ${document.id}`);
return cachedUrl;
}
const bucketName = BUCKETS[document.documentType];
const objectName = document.name;
const expiration = moment().add(TWO, 'hours').toDate();
try {
this.logger.debug(`Generating pre-signed url for object ${objectName} in bucket ${bucketName}`);
const res = await this.ociClient.createPreauthenticatedRequest({
namespaceName: this.namespace,
bucketName,
createPreauthenticatedRequestDetails: {
name: objectName,
accessType: CreatePreauthenticatedRequestDetails.AccessType.AnyObjectRead,
timeExpires: expiration,
objectName,
},
retryConfiguration: { terminationStrategy: { shouldTerminate: () => true } },
});
this.logger.log(`Pre-signed url generated successfully for document ${document.id}`);
await this.cacheService.set(document.id, res.preauthenticatedRequest.fullPath + objectName, '1h');
this.logger.log(`Pre-signed url cached for document ${document.id}`);
return res.preauthenticatedRequest.fullPath + objectName;
} catch (error) {
this.logger.error(`Error generating pre-signed url: ${error}`);
return document.name;
}
}
}