From aeb8b66375335e8c9d6cb9cb0d8d7da3d8b79628 Mon Sep 17 00:00:00 2001 From: Leonardo Bishop Date: Fri, 15 Mar 2024 20:23:41 +0000 Subject: Initial commit --- src/file/service/file.service.ts | 96 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/file/service/file.service.ts (limited to 'src/file/service/file.service.ts') diff --git a/src/file/service/file.service.ts b/src/file/service/file.service.ts new file mode 100644 index 0000000..24cb55d --- /dev/null +++ b/src/file/service/file.service.ts @@ -0,0 +1,96 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { FileMetadata } from '../entity/file.entity'; +import { FilePurpose } from '../entity/purpose.entity'; +import { DataSource, Repository } from 'typeorm'; +import { Session } from '../../session/entity/session.entity'; +import { StorageService } from 'src/storage/service/storage.service'; + +@Injectable() +export class FileService { + constructor( + @InjectRepository(FileMetadata) + private fileMetadataRepository: Repository, + + @InjectRepository(FilePurpose) + private filePurposeRepository: Repository, + + private readonly storageService: StorageService, + private readonly dataSource: DataSource, + ) {} + + async createFile( + b64Contents: string, + purpose: string, + validTo: Date, + session: Session, + ): Promise { + const filePurpose = await this.filePurposeRepository.findOneBy({ name: purpose }); + if (!filePurpose) { + throw new NotFoundException(`Unknown file purpose: ${filePurpose}`); + } + + const file = new FileMetadata(); + file.purpose = filePurpose; + file.session = session; + file.validUntil = validTo; + + const queryRunner = this.dataSource.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + try { + await this.fileMetadataRepository.save(file); + await this.storageService.createFile(b64Contents, file); + + await queryRunner.commitTransaction(); + } catch (err) { + await queryRunner.rollbackTransaction(); + + throw err; + } finally { + queryRunner.release(); + } + + return file; + } + + async markFileAsUsed(fileKey: string): Promise { + const update = await this.fileMetadataRepository + .createQueryBuilder() + .update({ + used: true, + }) + .where('validUntil > :date', { + date: new Date(Date.now()), + }) + .andWhere({ + key: fileKey, + used: false, + }) + .execute(); + + return update.affected > 0; + } + + async fetchFileContents(fileKey: string): Promise { + const file = await this.fileMetadataRepository.findOne({ + relations: { + contents: true, + }, + where: { + key: fileKey, + }, + }); + + return file?.contents?.b64Contents; + } + + async findManyValid(sessionToken: string): Promise { + return this.fileMetadataRepository + .createQueryBuilder('file') + .innerJoinAndSelect('file.session', 'session', 'session.token = :token', { token: sessionToken }) + .leftJoinAndSelect('file.purpose', 'purpose') + .where('file.used = :used', { used: false }) + .getMany(); + } +} -- cgit v1.2.3-70-g09d2