Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File and Report module #263

Merged
merged 18 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/nestjs-file/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@concepta/nestjs-exception": "^5.0.0-alpha.3",
"@concepta/nestjs-typeorm-ext": "^5.0.0-alpha.3",
"@concepta/ts-common": "^5.0.0-alpha.3",
"@concepta/ts-core": "^5.0.0-alpha.3",
"@concepta/typeorm-common": "^5.0.0-alpha.3",
"@nestjs/common": "^10.4.1",
"@nestjs/config": "^3.2.3",
Expand Down
6 changes: 3 additions & 3 deletions packages/nestjs-file/src/__fixtures__/aws-storage.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FileInterface } from '@concepta/ts-common';
import { FileCreatableInterface } from '@concepta/ts-common';
import { FileStorageServiceInterface } from '../interfaces/file-storage-service.interface';
import {
AWS_KEY_FIXTURE,
Expand All @@ -9,11 +9,11 @@ import {
export class AwsStorageService implements FileStorageServiceInterface {
KEY: string = AWS_KEY_FIXTURE;

getUploadUrl(_file: FileInterface): string {
getUploadUrl(_file: FileCreatableInterface): string {
return UPLOAD_URL_FIXTURE;
}

getDownloadUrl(_file: FileInterface): string {
getDownloadUrl(_file: FileCreatableInterface): string {
// make a call to aws to get signed download url
return DOWNLOAD_URL_FIXTURE;
}
Expand Down
16 changes: 7 additions & 9 deletions packages/nestjs-file/src/exceptions/file-create.exception.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { HttpStatus } from '@nestjs/common';
import { RuntimeException } from '@concepta/nestjs-exception';
import {
RuntimeException,
RuntimeExceptionOptions,
} from '@concepta/nestjs-exception';

export class FileCreateException extends RuntimeException {
constructor(
message = 'Error while trying to create a file',
originalError: unknown,
) {
constructor(options?: RuntimeExceptionOptions) {
super({
message,
originalError,
httpStatus: HttpStatus.INTERNAL_SERVER_ERROR,
message: 'Error while trying to create a file',
...options,
});

this.errorCode = 'FILE_CREATE_ERROR';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { HttpStatus } from '@nestjs/common';
import {
RuntimeException,
RuntimeExceptionOptions,
} from '@concepta/nestjs-exception';

export class FileDownloadUrlMissingException extends RuntimeException {
constructor(options?: RuntimeExceptionOptions) {
super({
message: 'Error trying to generate signed download url',
httpStatus: HttpStatus.BAD_REQUEST,
...options,
});

this.errorCode = 'FILE_DOWNLOAD_URL_ERROR';
}
}
17 changes: 17 additions & 0 deletions packages/nestjs-file/src/exceptions/file-name-missing.exception.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { HttpStatus } from '@nestjs/common';
import {
RuntimeException,
RuntimeExceptionOptions,
} from '@concepta/nestjs-exception';

export class FilenameMissingException extends RuntimeException {
constructor(options?: RuntimeExceptionOptions) {
super({
message: 'Filename is missing.',
httpStatus: HttpStatus.BAD_REQUEST,
...options,
});

this.errorCode = 'FILENAME_MISSING_ERROR';
}
}
10 changes: 7 additions & 3 deletions packages/nestjs-file/src/exceptions/file-query.exception.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { HttpStatus } from '@nestjs/common';
import { RuntimeException } from '@concepta/nestjs-exception';
import {
RuntimeException,
RuntimeExceptionOptions,
} from '@concepta/nestjs-exception';

export class FileQueryException extends RuntimeException {
constructor(message = 'Error while trying to do a query to file') {
constructor(options?: RuntimeExceptionOptions) {
super({
message,
message: 'Error while trying to do a query to file',
httpStatus: HttpStatus.INTERNAL_SERVER_ERROR,
...options,
});

this.errorCode = 'FILE_QUERY_ERROR';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { HttpStatus } from '@nestjs/common';
import {
RuntimeException,
RuntimeExceptionOptions,
} from '@concepta/nestjs-exception';

export class FileServiceKeyMissingException extends RuntimeException {
constructor(options?: RuntimeExceptionOptions) {
super({
message: 'Service key is missing.',
httpStatus: HttpStatus.BAD_REQUEST,
...options,
});

this.errorCode = 'SERVICE_KEY_MISSING_ERROR';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { HttpStatus } from '@nestjs/common';
import {
RuntimeException,
RuntimeExceptionOptions,
} from '@concepta/nestjs-exception';

export class FileUploadUrlMissingException extends RuntimeException {
constructor(options?: RuntimeExceptionOptions) {
super({
message: 'Error trying to generate signed upload url',
httpStatus: HttpStatus.BAD_REQUEST,
...options,
});

this.errorCode = 'FILE_UPLOAD_URL_ERROR';
}
}
13 changes: 10 additions & 3 deletions packages/nestjs-file/src/file.module-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { FileService } from './services/file.service';
import { FileStrategyService } from './services/file-strategy.service';

import { fileDefaultConfig } from './config/file-default.config';
import { FileMutateService } from './services/file-mutate.service';
import { FileLookupService } from './services/file-lookup.service';

const RAW_OPTIONS_TOKEN = Symbol('__FILE_MODULE_RAW_OPTIONS_TOKEN__');

Expand All @@ -43,7 +45,7 @@ function definitionTransform(
definition: DynamicModule,
extras: FileOptionsExtrasInterface,
): DynamicModule {
const { providers = [] } = definition;
const { providers = [], imports = [] } = definition;
const { global = false, entities } = extras;

if (!entities) {
Expand All @@ -53,16 +55,17 @@ function definitionTransform(
return {
...definition,
global,
imports: createFileImports({ entities }),
imports: createFileImports({ imports, entities }),
providers: createFileProviders({ providers }),
exports: [ConfigModule, RAW_OPTIONS_TOKEN, ...createFileExports()],
};
}

export function createFileImports(
options: FileEntitiesOptionsInterface,
options: Pick<DynamicModule, 'imports'> & FileEntitiesOptionsInterface,
): DynamicModule['imports'] {
return [
...(options.imports ?? []),
ConfigModule.forFeature(fileDefaultConfig),
TypeOrmExtModule.forFeature(options.entities),
];
Expand All @@ -82,6 +85,10 @@ export function createFileProviders(options: {
...(options.providers ?? []),
createFileSettingsProvider(options.overrides),
createStrategyServiceProvider(options.overrides),
// TODO: move to be overwrittable
FileMutateService,
// TODO: move to be overwrittable
FileLookupService,
FileStrategyService,
FileService,
];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { FileCreatableInterface, FileInterface } from '@concepta/ts-common';
import { LookupIdInterface, ReferenceId } from '@concepta/ts-core';
import { QueryOptionsInterface } from '@concepta/typeorm-common';

export interface FileLookupServiceInterface
extends LookupIdInterface<ReferenceId, FileInterface, QueryOptionsInterface> {
getUniqueFile(
org: Pick<FileCreatableInterface, 'serviceKey' | 'fileName'>,
queryOptions?: QueryOptionsInterface,
): Promise<FileInterface | null>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { FileCreatableInterface } from '@concepta/ts-common';
import { CreateOneInterface } from '@concepta/ts-core';
import { FileEntityInterface } from './file-entity.interface';

export interface FileMutateServiceInterface
extends CreateOneInterface<FileCreatableInterface, FileEntityInterface> {}
7 changes: 4 additions & 3 deletions packages/nestjs-file/src/interfaces/file-service.interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FileInterface } from '@concepta/ts-common';
import { FileCreatableInterface, FileInterface } from '@concepta/ts-common';
import { ReferenceIdInterface } from '@concepta/ts-core';

export interface FileServiceInterface {
push(file: Omit<FileInterface, 'id'>): Promise<FileInterface>;
fetch(file: Omit<FileInterface, 'serviceKey'>): Promise<FileInterface>;
push(file: FileCreatableInterface): Promise<FileInterface>;
fetch(file: ReferenceIdInterface): Promise<FileInterface>;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { FileInterface } from '@concepta/ts-common';
import { FileCreatableInterface } from '@concepta/ts-common';
import { FileStorageServiceInterface } from './file-storage-service.interface';

export interface FileStrategyServiceInterface {
getUploadUrl(file: FileInterface): Promise<string>;
getDownloadUrl(file: FileInterface): Promise<string>;
resolveStorageService(file: FileInterface): FileStorageServiceInterface;
getUploadUrl(file: FileCreatableInterface): Promise<string>;
getDownloadUrl(file: FileCreatableInterface): Promise<string>;
resolveStorageService(
file: FileCreatableInterface,
): FileStorageServiceInterface;
}
47 changes: 47 additions & 0 deletions packages/nestjs-file/src/services/file-lookup.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { InjectDynamicRepository } from '@concepta/nestjs-typeorm-ext';
import { LookupService, QueryOptionsInterface } from '@concepta/typeorm-common';
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';

import { FILE_MODULE_FILE_ENTITY_KEY } from '../file.constants';
import { FileEntityInterface } from '../interfaces/file-entity.interface';
import { FileLookupServiceInterface } from '../interfaces/file-lookup-service.interface';
import { FileInterface } from '@concepta/ts-common';
import { FileServiceKeyMissingException } from '../exceptions/file-service-key-missing.exception';
import { FilenameMissingException } from '../exceptions/file-name-missing.exception';

/**
* File lookup service
*/
@Injectable()
export class FileLookupService
extends LookupService<FileEntityInterface>
implements FileLookupServiceInterface
{
constructor(
@InjectDynamicRepository(FILE_MODULE_FILE_ENTITY_KEY)
repo: Repository<FileEntityInterface>,
) {
super(repo);
}
async getUniqueFile(
file: Pick<FileInterface, 'serviceKey' | 'fileName'>,
queryOptions?: QueryOptionsInterface,
) {
if (!file.serviceKey) {
throw new FileServiceKeyMissingException();
}
if (!file.fileName) {
throw new FilenameMissingException();
}
return this.findOne(
{
where: {
serviceKey: file.serviceKey,
fileName: file.fileName,
},
},
queryOptions,
);
}
}
38 changes: 38 additions & 0 deletions packages/nestjs-file/src/services/file-mutate.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { MutateService } from '@concepta/typeorm-common';
import { InjectDynamicRepository } from '@concepta/nestjs-typeorm-ext';
import { FileCreatableInterface } from '@concepta/ts-common';
import { FileEntityInterface } from '../interfaces/file-entity.interface';

import { FileCreateDto } from '../dto/file-create.dto';
import { FileMutateServiceInterface } from '../interfaces/file-mutate-service.interface';
import { FILE_MODULE_FILE_ENTITY_KEY } from '../file.constants';

/**
* File mutate service
*/
@Injectable()
export class FileMutateService
extends MutateService<
FileEntityInterface,
FileCreatableInterface,
FileCreatableInterface
>
implements FileMutateServiceInterface
{
protected createDto = FileCreateDto;
protected updateDto = FileCreateDto;

/**
* Constructor
*
* @param repo - instance of the file repo
*/
constructor(
@InjectDynamicRepository(FILE_MODULE_FILE_ENTITY_KEY)
repo: Repository<FileEntityInterface>,
) {
super(repo);
}
}
17 changes: 15 additions & 2 deletions packages/nestjs-file/src/services/file-strategy.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { FileCreatableInterface } from '@concepta/ts-common';
import { FileStrategyServiceInterface } from '../interfaces/file-strategy-service.interface';
import { FileStorageServiceInterface } from '../interfaces/file-storage-service.interface';
import { FileStorageServiceNotFoundException } from '../exceptions/file-storage-service-not-found.exception';
import { FileDownloadUrlMissingException } from '../exceptions/file-download-url-missing.exception';

export class FileStrategyService implements FileStrategyServiceInterface {
private readonly storageServices: FileStorageServiceInterface[] = [];
Expand All @@ -11,11 +12,23 @@ export class FileStrategyService implements FileStrategyServiceInterface {
}

async getUploadUrl(file: FileCreatableInterface): Promise<string> {
return this.resolveStorageService(file).getUploadUrl(file);
try {
return this.resolveStorageService(file).getUploadUrl(file);
} catch (err) {
throw new FileDownloadUrlMissingException({
originalError: err,
});
}
}

async getDownloadUrl(file: FileCreatableInterface): Promise<string> {
return this.resolveStorageService(file).getDownloadUrl(file);
try {
return this.resolveStorageService(file).getDownloadUrl(file);
} catch (err) {
throw new FileDownloadUrlMissingException({
originalError: err,
});
}
}

resolveStorageService(
Expand Down
Loading
Loading