Compare commits
24 Commits
main
...
anagrafica
Author | SHA1 | Date | |
---|---|---|---|
7970ccfc0e | |||
aa07f3d4f9 | |||
2c313a0dd0 | |||
577f781556 | |||
bfd25acd5b | |||
d707e14a8b | |||
d6ffa909aa | |||
0148082d0a | |||
b180968def | |||
60b1701d01 | |||
580de7d81b | |||
1b7c586b69 | |||
ef50d7075f | |||
3042e693be | |||
06d7e51f63 | |||
851153c8e1 | |||
2735fa4791 | |||
cc6fe98e20 | |||
58de1b1652 | |||
0d60b73816 | |||
9f35377481 | |||
a742b9dc5e | |||
8806114929 | |||
a8596c8b4d |
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,5 +1,8 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# compiled output
|
||||
dist
|
||||
tmp
|
||||
@ -40,3 +43,6 @@ Thumbs.db
|
||||
|
||||
.nx/cache
|
||||
.nx/workspace-data
|
||||
|
||||
# typeorm
|
||||
typeorm-model-generator-output/
|
||||
|
@ -1,3 +1,5 @@
|
||||
{
|
||||
"singleQuote": true
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"plugins": ["prettier-plugin-organize-imports"]
|
||||
}
|
||||
|
20
.vscode/launch.json
vendored
Normal file
20
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach to ebitemp-api",
|
||||
"port": 9229,
|
||||
"request": "attach",
|
||||
"restart": true,
|
||||
"skipFiles": [
|
||||
"<node_internals>/**",
|
||||
"${workspaceFolder}/node_modules/**/*.js"
|
||||
],
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"type": "node"
|
||||
}
|
||||
]
|
||||
}
|
22
apps/ebitemp-api/.tomg-config
Normal file
22
apps/ebitemp-api/.tomg-config
Normal file
@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"pluralizeNames": true,
|
||||
"noConfigs": true,
|
||||
"convertCaseFile": "none",
|
||||
"convertCaseEntity": "pascal",
|
||||
"convertCaseProperty": "camel",
|
||||
"convertEol": "LF",
|
||||
"propertyVisibility": "none",
|
||||
"lazy": false,
|
||||
"activeRecord": false,
|
||||
"generateConstructor": true,
|
||||
"customNamingStrategyPath": ".tomg-naming-strategy.js",
|
||||
"relationIds": false,
|
||||
"strictMode": "!",
|
||||
"skipSchema": true,
|
||||
"indexFile": false,
|
||||
"exportType": "named",
|
||||
"skipNonPrimaryKeyIndexes": true,
|
||||
"removeColumnsInRelation": false
|
||||
}
|
||||
]
|
39
apps/ebitemp-api/.tomg-naming-strategy.js
Normal file
39
apps/ebitemp-api/.tomg-naming-strategy.js
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @typedef {import('typeorm-model-generator').Column} Column
|
||||
* @typedef {import('typeorm-model-generator').Entity} Entity
|
||||
*/
|
||||
|
||||
/**
|
||||
* Customizes the entity name.
|
||||
* @param {string} oldEntityName - The default entity name.
|
||||
* @param {Entity} entity - The entity.
|
||||
* @returns {string} The new entity name.
|
||||
*/
|
||||
function entityName(oldEntityName, entity) {
|
||||
return oldEntityName + 'Entity';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the column name.
|
||||
* @param {string} oldColumnName - The default column name.
|
||||
* @param {Column} column - The column.
|
||||
* @returns {string} The new column name.
|
||||
*/
|
||||
function columnName(oldColumnName, column) {
|
||||
return oldColumnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the file name.
|
||||
* @param {string} oldFileName - The default file name.
|
||||
* @returns {string} The new file name.
|
||||
*/
|
||||
function fileName(oldFileName) {
|
||||
return oldFileName.replace('Entity', '.entity');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
entityName,
|
||||
columnName,
|
||||
fileName,
|
||||
};
|
@ -1,5 +1,16 @@
|
||||
import baseConfig from "../../eslint.config.mjs";
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default [
|
||||
...baseConfig
|
||||
];
|
||||
export default tseslint.config([
|
||||
...baseConfig,
|
||||
{
|
||||
files: ['src/**/*.ts', 'src/**/*.tsx'],
|
||||
extends: [tseslint.configs.recommendedTypeCheckedOnly],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common';
|
||||
import { AppService } from './app.service';
|
||||
import { Public } from '../modules/auth/strategies/jwt/jwt-auth.guard';
|
||||
|
||||
@Controller()
|
||||
@Public()
|
||||
@Controller({ version: VERSION_NEUTRAL })
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get()
|
||||
getData() {
|
||||
return this.appService.getData();
|
||||
async getData() {
|
||||
return await this.appService.getData();
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,35 @@ import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
import { AppAuthModule } from '../modules/auth/auth.module';
|
||||
import { AppClsModule } from '../modules/cls/cls.module';
|
||||
import { AppConfigModule } from '../modules/config/config.module';
|
||||
import { AppDatabaseModule } from '../modules/database/database.module';
|
||||
import { EnumifyModule } from '../modules/enumify/enumify.module';
|
||||
import { AppFileTransactionsModule } from '../modules/file-transactions/file-transactions.module';
|
||||
import { AppHealthModule } from '../modules/health/health.module';
|
||||
import { AppLoggerModule } from '../modules/logger/logger.module';
|
||||
import { AppRequestLoggingModule } from '../modules/request-logging/request-logging.module';
|
||||
import { AppScheduleModule } from '../modules/schedule/schedule.module';
|
||||
import { AppValidationModule } from '../modules/validation/validation.module';
|
||||
|
||||
import { AnagraficaModule } from '../features/anagrafica/anagrafica.module';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
imports: [
|
||||
AppConfigModule,
|
||||
AppLoggerModule,
|
||||
AppDatabaseModule,
|
||||
AppClsModule,
|
||||
AppHealthModule,
|
||||
AppFileTransactionsModule,
|
||||
AppScheduleModule,
|
||||
AppValidationModule,
|
||||
AppAuthModule,
|
||||
AppRequestLoggingModule,
|
||||
EnumifyModule,
|
||||
AnagraficaModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
})
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
getData(): { message: string } {
|
||||
private readonly logger = new Logger(AppService.name);
|
||||
|
||||
async getData() {
|
||||
return ({ message: 'Hello API' });
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { AnagraficaController } from './anagrafica.controller';
|
||||
import { AnagraficaService } from './anagrafica.service';
|
||||
|
||||
describe('AnagraficaController', () => {
|
||||
let controller: AnagraficaController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
providers: [AnagraficaService],
|
||||
controllers: [AnagraficaController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get(AnagraficaController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,28 @@
|
||||
import { Controller, Get, Param, UseInterceptors } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { ApiOkPaginatedResponse, ApiPaginationQuery, Paginate, PaginateQuery } from 'nestjs-paginate';
|
||||
import { SocioEntity } from '../../modules/database/connections/oceano';
|
||||
import { AnagraficaService } from './anagrafica.service';
|
||||
import { RequestLoggerInterceptor } from '../../modules/request-logging/request-logger.interceptor';
|
||||
|
||||
@UseInterceptors(RequestLoggerInterceptor)
|
||||
@ApiBearerAuth()
|
||||
@ApiTags('anagrafica')
|
||||
@Controller('anagrafiche')
|
||||
export class AnagraficaController {
|
||||
constructor(private anagraficaService: AnagraficaService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Find all Anagrafiche' })
|
||||
@ApiPaginationQuery(AnagraficaService.findPaginateConfig())
|
||||
@ApiOkPaginatedResponse(SocioEntity, AnagraficaService.findPaginateConfig())
|
||||
async getAnagrafiche(@Paginate() query: PaginateQuery) {
|
||||
return this.anagraficaService.getAnagrafiche(query);
|
||||
}
|
||||
|
||||
@Get('id/:id')
|
||||
@ApiOperation({ summary: 'Get one Anagrafica by id' })
|
||||
async getOneAnagraficaById(@Param('id') id: string) {
|
||||
return this.anagraficaService.getOneAnagraficaById(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { SocioEntity } from '../../modules/database/connections/oceano';
|
||||
import { OCEANO_DATASOURCE } from '../../modules/database/connections/oceano/database.constants';
|
||||
import { AnagraficaController } from './anagrafica.controller';
|
||||
import { AnagraficaService } from './anagrafica.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([SocioEntity], OCEANO_DATASOURCE)],
|
||||
controllers: [AnagraficaController],
|
||||
providers: [AnagraficaService],
|
||||
exports: [AnagraficaService],
|
||||
})
|
||||
export class AnagraficaModule {}
|
@ -0,0 +1,18 @@
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { AnagraficaService } from './anagrafica.service';
|
||||
|
||||
describe('AnagraficaService', () => {
|
||||
let service: AnagraficaService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
providers: [AnagraficaService],
|
||||
}).compile();
|
||||
|
||||
service = module.get(AnagraficaService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,42 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { paginate, PaginateConfig, PaginateQuery } from 'nestjs-paginate';
|
||||
import { Repository } from 'typeorm';
|
||||
import { SocioEntity } from '../../modules/database/connections/oceano';
|
||||
import { OCEANO_DATASOURCE } from '../../modules/database/connections/oceano/database.constants';
|
||||
|
||||
@Injectable()
|
||||
export class AnagraficaService {
|
||||
private readonly logger = new Logger(AnagraficaService.name);
|
||||
|
||||
static readonly findPaginateConfig = (): PaginateConfig<SocioEntity> => ({
|
||||
relations: {},
|
||||
sortableColumns: ['codiceSocio', 'idNucleo', 'idPersona'],
|
||||
searchableColumns: [],
|
||||
defaultSortBy: [['codiceSocio', 'ASC']],
|
||||
defaultLimit: 50,
|
||||
maxLimit: -1,
|
||||
filterableColumns: {},
|
||||
relativePath: true,
|
||||
where: {
|
||||
codiceGruppo: '6',
|
||||
},
|
||||
});
|
||||
|
||||
constructor(
|
||||
@InjectRepository(SocioEntity, OCEANO_DATASOURCE) private readonly sociRepository: Repository<SocioEntity>
|
||||
) {}
|
||||
|
||||
async getAnagrafiche(query: PaginateQuery) {
|
||||
const config = AnagraficaService.findPaginateConfig();
|
||||
query.limit ??= -1;
|
||||
|
||||
return await paginate(query, this.sociRepository, config);
|
||||
}
|
||||
|
||||
async getOneAnagraficaById(idAnagrafica: string) {
|
||||
return await this.sociRepository.findOne({
|
||||
where: { ...AnagraficaService.findPaginateConfig().where, codiceSocio: idAnagrafica },
|
||||
});
|
||||
}
|
||||
}
|
@ -1,19 +1,61 @@
|
||||
/**
|
||||
* This is not a production server yet!
|
||||
* This is only a minimal backend to get started.
|
||||
*/
|
||||
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { Logger, RequestMethod, VersioningType } from '@nestjs/common';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
|
||||
import { Logger as PinoLogger } from 'nestjs-pino';
|
||||
|
||||
import { DocumentBuilder, SwaggerDocumentOptions, SwaggerModule } from '@nestjs/swagger';
|
||||
import { flow } from 'lodash';
|
||||
import { AppModule } from './app/app.module';
|
||||
import { patchPublicDecoratorSupport } from './modules/auth/strategies/jwt/jwt-auth.guard';
|
||||
import { LocalConfig, localConfig } from './modules/config/local.config';
|
||||
import { patchTypeOrm } from './modules/database/utils/typeorm-patch';
|
||||
import { patchNestjsSwagger } from './modules/validation/utils/nestjs-swagger-patches';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
const globalPrefix = 'api';
|
||||
app.setGlobalPrefix(globalPrefix);
|
||||
const port = process.env.PORT || 3000;
|
||||
await patchTypeOrm();
|
||||
await patchNestjsSwagger();
|
||||
|
||||
const appOpts = (() => {
|
||||
const loggerOpts = { bufferLogs: true };
|
||||
return {
|
||||
forceCloseConnections: true,
|
||||
...loggerOpts,
|
||||
};
|
||||
})();
|
||||
const app = await NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter(appOpts));
|
||||
app.enableVersioning({
|
||||
type: VersioningType.URI,
|
||||
defaultVersion: '1'
|
||||
});
|
||||
app.enableShutdownHooks();
|
||||
|
||||
const config = app.get<LocalConfig>(localConfig.KEY);
|
||||
const port = config.port || 3000;
|
||||
|
||||
app.useLogger(app.get(PinoLogger));
|
||||
|
||||
const swaggerConfig = new DocumentBuilder().addBearerAuth().build();
|
||||
const swaggerOptions = {
|
||||
operationIdFactory: (controllerKey: string, methodKey: string) => {
|
||||
return `${controllerKey}_${methodKey}`;
|
||||
},
|
||||
} satisfies SwaggerDocumentOptions;
|
||||
const document = flow(
|
||||
() => SwaggerModule.createDocument(app, swaggerConfig, swaggerOptions),
|
||||
patchPublicDecoratorSupport
|
||||
)();
|
||||
|
||||
SwaggerModule.setup(`docs`, app, document, {
|
||||
swaggerOptions: {
|
||||
operationsSorter: 'alpha',
|
||||
displayOperationId: true,
|
||||
filter: true,
|
||||
persistAuthorization: true,
|
||||
},
|
||||
});
|
||||
|
||||
await app.listen(port);
|
||||
Logger.log(`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`);
|
||||
Logger.log(`🚀 Application is running on: http://localhost:${port}`);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
void bootstrap();
|
||||
|
31
apps/ebitemp-api/src/modules/auth/auth.config.ts
Normal file
31
apps/ebitemp-api/src/modules/auth/auth.config.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import { z } from 'zod';
|
||||
import coerceRecordTypes from '../config/utils/coerce-record-types';
|
||||
|
||||
export const authSchema = z.object({
|
||||
accessToken: z.object({
|
||||
secret: z.string(),
|
||||
expTimeInSecs: z.number().finite().nonnegative(),
|
||||
}),
|
||||
refreshToken: z.object({
|
||||
secret: z.string(),
|
||||
expTimeInSecs: z.number().finite().nonnegative(),
|
||||
}),
|
||||
});
|
||||
export type AuthConfig = z.infer<typeof authSchema>;
|
||||
|
||||
export const authConfig = registerAs('auth', () => {
|
||||
const env = coerceRecordTypes(process.env);
|
||||
|
||||
const config: AuthConfig = authSchema.strict().parse({
|
||||
accessToken: {
|
||||
secret: env['JWT_ACCESS_TOKEN_SECRET'],
|
||||
expTimeInSecs: env['JWT_ACCESS_TOKEN_EXPIRATION_TIME_IN_SECONDS'],
|
||||
},
|
||||
refreshToken: {
|
||||
secret: env['JWT_REFRESH_TOKEN_SECRET'],
|
||||
expTimeInSecs: env['JWT_REFRESH_TOKEN_EXPIRATION_TIME_IN_SECONDS'],
|
||||
}
|
||||
});
|
||||
return config;
|
||||
});
|
31
apps/ebitemp-api/src/modules/auth/auth.controller.ts
Normal file
31
apps/ebitemp-api/src/modules/auth/auth.controller.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { Body, Controller, HttpCode, HttpStatus, Post, UseGuards } from '@nestjs/common';
|
||||
import { ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { AccountsEntity } from '../database/connections/ebitemp-api/entities';
|
||||
import { LoginDto, LoginResDto } from './auth.dto';
|
||||
import { AuthService } from './auth.service';
|
||||
import { AuthenticatedUser } from './authenticated-user.decorator';
|
||||
import { Public } from './strategies/jwt/jwt-auth.guard';
|
||||
import { JwtRefreshGuard } from './strategies/jwt/jwt-refresh.guard';
|
||||
|
||||
@ApiBearerAuth()
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Public()
|
||||
@Post('login')
|
||||
async logIn(@Body() body: LoginDto): Promise<LoginResDto> {
|
||||
const { username, password } = body;
|
||||
const user = await this.authService.getAuthenticatedUser(username, password);
|
||||
return await this.authService.signJwts(user);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(JwtRefreshGuard)
|
||||
@Public(true)
|
||||
@Post('refresh')
|
||||
async refresh(@AuthenticatedUser() user: AccountsEntity): Promise<LoginResDto> {
|
||||
return await this.authService.signJwts(user);
|
||||
}
|
||||
}
|
19
apps/ebitemp-api/src/modules/auth/auth.dto.ts
Normal file
19
apps/ebitemp-api/src/modules/auth/auth.dto.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { createZodDto } from '@anatine/zod-nestjs';
|
||||
import { z } from 'zod';
|
||||
import { AccountsEntitySchema } from '../database/connections/ebitemp-api/entities';
|
||||
|
||||
export const loginSchema = z.object({
|
||||
username: AccountsEntitySchema.shape.username,
|
||||
password: z.string().nonempty(),
|
||||
});
|
||||
export type Login = z.infer<typeof loginSchema>;
|
||||
export class LoginDto extends createZodDto(loginSchema) {}
|
||||
|
||||
export const loginResSchema = z.object({
|
||||
accessToken: z.string().jwt(),
|
||||
accessTokenExp: z.string().datetime(),
|
||||
refreshToken: z.string().jwt(),
|
||||
refreshTokenExp: z.string().datetime()
|
||||
})
|
||||
export type LoginRes = z.infer<typeof loginResSchema>;
|
||||
export class LoginResDto extends createZodDto(loginResSchema) {}
|
36
apps/ebitemp-api/src/modules/auth/auth.module.ts
Normal file
36
apps/ebitemp-api/src/modules/auth/auth.module.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { APP_GUARD, Reflector } from '@nestjs/core';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AccountsEntity } from '../database/connections/ebitemp-api/entities';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { AuthService } from './auth.service';
|
||||
import { JwtAccessTokenAuthStrategy } from './strategies/jwt/jwt-access-token-auth.strategy';
|
||||
import { JwtAccessTokenModule } from './strategies/jwt/jwt-access-token.module';
|
||||
import { JwtAuthGuard } from './strategies/jwt/jwt-auth.guard';
|
||||
import { JwtRefreshTokenAuthStrategy } from './strategies/jwt/jwt-refresh-token-auth.strategy';
|
||||
import { JwtRefreshTokenModule } from './strategies/jwt/jwt-refresh-token.module';
|
||||
import { UsersAuthModule } from './users/users.module';
|
||||
import { EBITEMP_API_DATASOURCE } from '../database/connections/ebitemp-api/database.constants';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([AccountsEntity], EBITEMP_API_DATASOURCE),
|
||||
JwtAccessTokenModule,
|
||||
JwtRefreshTokenModule,
|
||||
PassportModule,
|
||||
UsersAuthModule,
|
||||
],
|
||||
controllers: [AuthController],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_GUARD,
|
||||
useFactory: (reflector) => new JwtAuthGuard(reflector),
|
||||
inject: [Reflector],
|
||||
},
|
||||
AuthService,
|
||||
JwtAccessTokenAuthStrategy,
|
||||
JwtRefreshTokenAuthStrategy,
|
||||
],
|
||||
})
|
||||
export class AppAuthModule {}
|
67
apps/ebitemp-api/src/modules/auth/auth.service.ts
Normal file
67
apps/ebitemp-api/src/modules/auth/auth.service.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { Inject, Injectable, Logger, UnauthorizedException } from '@nestjs/common';
|
||||
import { JwtService, JwtSignOptions } from '@nestjs/jwt';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import dayjs from 'dayjs';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { AccountsEntity } from '../database/connections/ebitemp-api/entities';
|
||||
import { TokenPayload } from './constants/token-payload.interface';
|
||||
import { ACCESS_TOKEN_JWT_SERVICE } from './strategies/jwt/jwt-access-token.module';
|
||||
import { REFRESH_TOKEN_JWT_SERVICE } from './strategies/jwt/jwt-refresh-token.module';
|
||||
import { UsersAuthService } from './users/users-auth.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
private readonly logger = new Logger(AuthService.name);
|
||||
|
||||
constructor(
|
||||
private readonly usersAuthService: UsersAuthService,
|
||||
@Inject(ACCESS_TOKEN_JWT_SERVICE) private readonly accessTokenJwtService: JwtService,
|
||||
@Inject(REFRESH_TOKEN_JWT_SERVICE) private readonly refreshTokenJwtService: JwtService
|
||||
) {}
|
||||
|
||||
public async signJwts(account: AccountsEntity) {
|
||||
const { token: accessToken, exp: accessTokenExp } = await this.getAccessToken(account);
|
||||
const { token: refreshToken, exp: refreshTokenExp } = await this.getRefreshToken(account);
|
||||
|
||||
return {
|
||||
accessToken: accessToken,
|
||||
accessTokenExp: dayjs.unix(accessTokenExp).toJSON(),
|
||||
refreshToken: refreshToken,
|
||||
refreshTokenExp: dayjs.unix(refreshTokenExp).toJSON(),
|
||||
};
|
||||
}
|
||||
|
||||
public async getAccessToken(account: AccountsEntity, options?: JwtSignOptions) {
|
||||
const payload: TokenPayload = { username: account.username, sub: account.id };
|
||||
const token = await this.accessTokenJwtService.signAsync(payload, options);
|
||||
const exp = this.accessTokenJwtService.decode(token).exp;
|
||||
return { token, exp };
|
||||
}
|
||||
|
||||
public async getRefreshToken(account: AccountsEntity, options?: JwtSignOptions) {
|
||||
const payload: TokenPayload = { username: account.username, sub: account.id };
|
||||
const token = await this.refreshTokenJwtService.signAsync(payload, options);
|
||||
await this.usersAuthService.setCurrentRefreshTokenHash(account.id, token);
|
||||
const exp = this.refreshTokenJwtService.decode(token).exp;
|
||||
return { token, exp };
|
||||
}
|
||||
|
||||
public async getAuthenticatedUser(username: string, password: string): Promise<AccountsEntity> {
|
||||
try {
|
||||
const account = await this.usersAuthService.getUserByUsername(username);
|
||||
if (!account) throw new UnauthorizedException(`Username not found`);
|
||||
await this.verifyPassword(password, account.password);
|
||||
return account;
|
||||
} catch (error) {
|
||||
throw new UnauthorizedException(`Wrong credentials`);
|
||||
}
|
||||
}
|
||||
|
||||
private async verifyPassword(plainTextPassword: string, hashedPassword: string | null) {
|
||||
const isPasswordMatching =
|
||||
hashedPassword && !isEmpty(hashedPassword) ? await bcrypt.compare(plainTextPassword, hashedPassword) : null;
|
||||
if (!isPasswordMatching) {
|
||||
throw new UnauthorizedException(`Wrong password`);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||
import { RequestWithUser } from './constants/request-with-user';
|
||||
|
||||
export const AuthenticatedUser = createParamDecorator((data: unknown, ctx: ExecutionContext) => {
|
||||
const request = ctx.switchToHttp().getRequest<RequestWithUser>();
|
||||
|
||||
return request.user;
|
||||
});
|
@ -0,0 +1,6 @@
|
||||
import { FastifyRequest } from "fastify";
|
||||
import { AccountsEntity } from "../../database/connections/ebitemp-api/entities";
|
||||
|
||||
export interface RequestWithUser extends FastifyRequest {
|
||||
user: AccountsEntity;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
export interface TokenPayload {
|
||||
username: string;
|
||||
sub: number;
|
||||
iat?: number;
|
||||
exp?: number;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
import { Inject, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { FastifyRequest } from 'fastify';
|
||||
import { ClsService } from 'nestjs-cls';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { AppClsStore } from '../../../cls/cls.interface';
|
||||
import { AuthConfig, authConfig } from '../../auth.config';
|
||||
import { TokenPayload } from '../../constants/token-payload.interface';
|
||||
import { UsersAuthService } from '../../users/users-auth.service';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAccessTokenAuthStrategy extends PassportStrategy(Strategy, 'jwt-access-token') {
|
||||
constructor(
|
||||
@Inject(authConfig.KEY) authConfig: AuthConfig,
|
||||
private readonly cls: ClsService<AppClsStore>,
|
||||
private readonly userAuthService: UsersAuthService
|
||||
) {
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
secretOrKey: authConfig.accessToken.secret,
|
||||
passReqToCallback: true,
|
||||
});
|
||||
}
|
||||
|
||||
async validate(request: FastifyRequest, payload: TokenPayload) {
|
||||
const account = await this.userAuthService.getUserById(payload.sub);
|
||||
if (!account) throw new UnauthorizedException('Access Token Guard');
|
||||
this.cls.set('account', account);
|
||||
return account;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { JwtService, JwtModule as NestJwtModule } from '@nestjs/jwt';
|
||||
import { authConfig, AuthConfig } from '../../auth.config';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
export const ACCESS_TOKEN_JWT_SERVICE = Symbol('ACCESS_TOKEN_JWT_SERVICE');
|
||||
const accessTokenJwtProvider = {
|
||||
provide: ACCESS_TOKEN_JWT_SERVICE,
|
||||
useFactory: (jwtService: JwtService) => jwtService,
|
||||
inject: [JwtService],
|
||||
};
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forFeature(authConfig),
|
||||
NestJwtModule.registerAsync({
|
||||
imports: [...authConfig.asProvider().imports],
|
||||
useFactory: async (authConfig: AuthConfig) => ({
|
||||
secret: authConfig.accessToken.secret,
|
||||
signOptions: {
|
||||
expiresIn: `${authConfig.accessToken.expTimeInSecs}s`,
|
||||
},
|
||||
}),
|
||||
inject: [authConfig.KEY],
|
||||
}),
|
||||
],
|
||||
providers: [accessTokenJwtProvider],
|
||||
exports: [ConfigModule, accessTokenJwtProvider],
|
||||
})
|
||||
export class JwtAccessTokenModule {}
|
@ -0,0 +1,39 @@
|
||||
import { applyDecorators, ExecutionContext, SetMetadata } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { OpenAPIObject } from '@nestjs/swagger';
|
||||
|
||||
export const IS_PUBLIC_KEY = 'isPublic';
|
||||
export const Public = (keepSecurity: boolean = false) => {
|
||||
const decorators = [SetMetadata(IS_PUBLIC_KEY, true)];
|
||||
if (!keepSecurity) decorators.push(SetMetadata('swagger/apiSecurity', ['public']));
|
||||
return applyDecorators(...decorators);
|
||||
};
|
||||
|
||||
export const patchPublicDecoratorSupport = (document: OpenAPIObject) => {
|
||||
Object.values(document.paths).forEach((path: any) => {
|
||||
Object.values(path).forEach((method: any) => {
|
||||
if (Array.isArray(method.security) && method.security.includes('public')) {
|
||||
method.security = [];
|
||||
}
|
||||
});
|
||||
});
|
||||
return document;
|
||||
};
|
||||
|
||||
export class JwtAuthGuard extends AuthGuard('jwt-access-token') {
|
||||
constructor(private reflector: Reflector) {
|
||||
super();
|
||||
}
|
||||
|
||||
canActivate(context: ExecutionContext) {
|
||||
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
if (isPublic) {
|
||||
return true;
|
||||
}
|
||||
return super.canActivate(context);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import { Inject, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { FastifyRequest } from 'fastify';
|
||||
import { ClsService } from 'nestjs-cls';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { AppClsStore } from '../../../cls/cls.interface';
|
||||
import { authConfig, AuthConfig } from '../../auth.config';
|
||||
import { TokenPayload } from '../../constants/token-payload.interface';
|
||||
import { UsersAuthService } from '../../users/users-auth.service';
|
||||
|
||||
@Injectable()
|
||||
export class JwtRefreshTokenAuthStrategy extends PassportStrategy(Strategy, 'jwt-refresh-token') {
|
||||
constructor(
|
||||
@Inject(authConfig.KEY) authConfig: AuthConfig,
|
||||
private readonly cls: ClsService<AppClsStore>,
|
||||
private readonly usersAuthService: UsersAuthService
|
||||
) {
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
secretOrKey: authConfig.refreshToken.secret,
|
||||
passReqToCallback: true,
|
||||
});
|
||||
}
|
||||
|
||||
async validate(request: FastifyRequest, payload: TokenPayload) {
|
||||
const refreshToken = (request.headers?.authorization as string | undefined)?.replace('Bearer', '')?.trim() ?? '';
|
||||
const account = await this.usersAuthService.getUserByIdAndRefreshTokenPair(payload.sub, refreshToken);
|
||||
if (!account) throw new UnauthorizedException('Refresh Token Guard');
|
||||
this.cls.set('account', account);
|
||||
return account;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { JwtService, JwtModule as NestJwtModule } from '@nestjs/jwt';
|
||||
import { authConfig, AuthConfig } from '../../auth.config';
|
||||
|
||||
export const REFRESH_TOKEN_JWT_SERVICE = Symbol('REFRESH_TOKEN_JWT_SERVICE');
|
||||
const refreshTokenJwtProvider = {
|
||||
provide: REFRESH_TOKEN_JWT_SERVICE,
|
||||
useFactory: (jwtService: JwtService) => jwtService,
|
||||
inject: [JwtService],
|
||||
};
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forFeature(authConfig),
|
||||
NestJwtModule.registerAsync({
|
||||
imports: [...authConfig.asProvider().imports],
|
||||
useFactory: async (authConfig: AuthConfig) => ({
|
||||
secret: authConfig.refreshToken.secret,
|
||||
signOptions: {
|
||||
expiresIn: `${authConfig.refreshToken.expTimeInSecs}s`,
|
||||
},
|
||||
}),
|
||||
inject: [authConfig.KEY],
|
||||
}),
|
||||
],
|
||||
providers: [refreshTokenJwtProvider],
|
||||
exports: [ConfigModule, refreshTokenJwtProvider],
|
||||
})
|
||||
export class JwtRefreshTokenModule {}
|
@ -0,0 +1,3 @@
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
|
||||
export class JwtRefreshGuard extends AuthGuard('jwt-refresh-token') {}
|
@ -0,0 +1,43 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import * as argon2 from 'argon2';
|
||||
import { Repository } from 'typeorm';
|
||||
import { AccountsEntity } from '../../database/connections/ebitemp-api/entities';
|
||||
import { EBITEMP_API_DATASOURCE } from '../../database/connections/ebitemp-api/database.constants';
|
||||
|
||||
@Injectable()
|
||||
export class UsersAuthService {
|
||||
constructor(
|
||||
@InjectRepository(AccountsEntity, EBITEMP_API_DATASOURCE)
|
||||
private readonly accountsRepository: Repository<AccountsEntity>
|
||||
) {}
|
||||
|
||||
async getUserById(accountId: number) {
|
||||
return await this.accountsRepository.findOne({
|
||||
relations: { profili: { ruolo: true } },
|
||||
where: { id: accountId },
|
||||
});
|
||||
}
|
||||
|
||||
async getUserByUsername(username: string) {
|
||||
return await this.accountsRepository.findOne({
|
||||
relations: { profili: { ruolo: true } },
|
||||
where: { username: username },
|
||||
});
|
||||
}
|
||||
|
||||
async getUserByIdAndRefreshTokenPair(accountId: number, refreshToken: string) {
|
||||
const accountById = await this.getUserById(accountId);
|
||||
if (!accountById?.ultimoHashRefreshToken) return null;
|
||||
|
||||
const isRefreshTokenMatching = await argon2.verify(accountById.ultimoHashRefreshToken, refreshToken);
|
||||
return isRefreshTokenMatching ? accountById : null;
|
||||
}
|
||||
|
||||
async setCurrentRefreshTokenHash(accountId: number, refreshToken: string | null) {
|
||||
const hash = refreshToken ? await argon2.hash(refreshToken) : null;
|
||||
await this.accountsRepository.update(accountId, {
|
||||
ultimoHashRefreshToken: hash,
|
||||
});
|
||||
}
|
||||
}
|
14
apps/ebitemp-api/src/modules/auth/users/users.module.ts
Normal file
14
apps/ebitemp-api/src/modules/auth/users/users.module.ts
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { UsersAuthService } from './users-auth.service';
|
||||
import { AccountsEntity } from '../../database/connections/ebitemp-api/entities';
|
||||
import { EBITEMP_API_DATASOURCE } from '../../database/connections/ebitemp-api/database.constants';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([AccountsEntity], EBITEMP_API_DATASOURCE)],
|
||||
controllers: [],
|
||||
providers: [UsersAuthService],
|
||||
exports: [UsersAuthService],
|
||||
})
|
||||
export class UsersAuthModule {}
|
6
apps/ebitemp-api/src/modules/cls/cls.interface.ts
Normal file
6
apps/ebitemp-api/src/modules/cls/cls.interface.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { ClsStore } from "nestjs-cls";
|
||||
import { AccountsEntity } from "../database/connections/ebitemp-api";
|
||||
|
||||
export interface AppClsStore extends ClsStore {
|
||||
account: AccountsEntity|null;
|
||||
}
|
16
apps/ebitemp-api/src/modules/cls/cls.module.ts
Normal file
16
apps/ebitemp-api/src/modules/cls/cls.module.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ClsModule } from 'nestjs-cls';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ClsModule.forRoot({
|
||||
global: true,
|
||||
middleware: {
|
||||
mount: true,
|
||||
},
|
||||
}),
|
||||
],
|
||||
providers: [],
|
||||
exports: [ClsModule],
|
||||
})
|
||||
export class AppClsModule {}
|
13
apps/ebitemp-api/src/modules/config/config.module.ts
Normal file
13
apps/ebitemp-api/src/modules/config/config.module.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { localConfig } from './local.config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [localConfig],
|
||||
}),
|
||||
],
|
||||
})
|
||||
export class AppConfigModule {}
|
19
apps/ebitemp-api/src/modules/config/local.config.ts
Normal file
19
apps/ebitemp-api/src/modules/config/local.config.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import coerceRecordTypes from './utils/coerce-record-types';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const localSchema = z.object({
|
||||
production: z.boolean(),
|
||||
port: z.number().optional(),
|
||||
});
|
||||
export type LocalConfig = z.infer<typeof localSchema>;
|
||||
|
||||
export const localConfig = registerAs('local', () => {
|
||||
const env = coerceRecordTypes(process.env);
|
||||
|
||||
const config: LocalConfig = localSchema.strict().parse({
|
||||
production: env['PRODUCTION'],
|
||||
port: env['PORT'],
|
||||
});
|
||||
return config;
|
||||
});
|
@ -0,0 +1,11 @@
|
||||
import { clone, each } from 'lodash';
|
||||
|
||||
export default (raw: Record<string, any>): Record<string, string | number | boolean | undefined> => {
|
||||
raw = clone(raw);
|
||||
return each(raw, (value, key) => {
|
||||
if (value === 'true') raw[key] = true;
|
||||
if (value === 'false') raw[key] = false;
|
||||
if (value === 'null') raw[key] = null;
|
||||
if (!isNaN(Number(value))) raw[key] = Number(value);
|
||||
});
|
||||
};
|
@ -0,0 +1,10 @@
|
||||
import coerceRecordTypes from '../../../config/utils/coerce-record-types';
|
||||
import { databaseConfigFactory, rawDatabaseSchema } from '../../utils/database-config';
|
||||
|
||||
const env = coerceRecordTypes(process.env);
|
||||
const envParsed = rawDatabaseSchema.strict().parse({
|
||||
connectionString: env['DATABASE_EBITEMPAPI_CONNECTION_STRING'],
|
||||
secure: env['DATABASE_EBITEMPAPI_SECURE'],
|
||||
});
|
||||
|
||||
export const databaseConfig = databaseConfigFactory(envParsed);
|
@ -0,0 +1 @@
|
||||
export const EBITEMP_API_DATASOURCE = "EbitempApi";
|
@ -0,0 +1,32 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { DatabaseConfig } from '../../utils/database-config';
|
||||
import { typeormTransactionalDataSourceFactory } from '../../utils/typeorm-data-source-factory';
|
||||
import { typeormEntitiesFromImport } from '../../utils/typeorm-import-entities';
|
||||
import { typeormModuleOptionsFactory } from '../../utils/typeorm-module-options-factory';
|
||||
import { databaseConfig } from './database.config';
|
||||
import { EBITEMP_API_DATASOURCE } from './database.constants';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forFeature(databaseConfig),
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: databaseConfig.asProvider().imports,
|
||||
name: EBITEMP_API_DATASOURCE,
|
||||
dataSourceFactory: typeormTransactionalDataSourceFactory(EBITEMP_API_DATASOURCE),
|
||||
useFactory: async (dbConfig: DatabaseConfig) => {
|
||||
const config = await typeormModuleOptionsFactory(
|
||||
dbConfig,
|
||||
await typeormEntitiesFromImport(await import('./index')),
|
||||
EBITEMP_API_DATASOURCE
|
||||
);
|
||||
return config;
|
||||
},
|
||||
inject: [databaseConfig.KEY],
|
||||
}),
|
||||
],
|
||||
providers: [],
|
||||
exports: [TypeOrmModule],
|
||||
})
|
||||
export class EbitempApiDatabaseModule {}
|
@ -0,0 +1,51 @@
|
||||
import { toZod } from 'tozod';
|
||||
import { Column, Entity, Index, OneToMany } from 'typeorm';
|
||||
import { z } from 'zod';
|
||||
import { ProfiliEntity, ProfiliEntitySchema } from './profili.entity';
|
||||
|
||||
@Index('pk_accounts', ['id'], { unique: true })
|
||||
@Entity('accounts')
|
||||
export class AccountsEntity {
|
||||
@Column('int', { primary: true, name: 'id' })
|
||||
id!: number;
|
||||
|
||||
@Column('varchar', { name: 'username', unique: true, length: 255 })
|
||||
username!: string;
|
||||
|
||||
@Column('varchar', { name: 'password', nullable: true, length: 255 })
|
||||
password!: string | null;
|
||||
|
||||
@Column('varchar', { name: 'nome', length: 255 })
|
||||
nome!: string;
|
||||
|
||||
@Column('date', { name: 'data_creazione' })
|
||||
dataCreazione!: Date;
|
||||
|
||||
@Column('date', { name: 'data_scadenza', nullable: true })
|
||||
dataScadenza!: Date | null;
|
||||
|
||||
@Column('varchar', {
|
||||
name: 'ultimo_hash_refresh_token',
|
||||
nullable: true,
|
||||
length: 1024,
|
||||
})
|
||||
ultimoHashRefreshToken!: string | null;
|
||||
|
||||
@OneToMany(() => ProfiliEntity, (profiliEntity) => profiliEntity.account)
|
||||
profili!: ProfiliEntity[];
|
||||
|
||||
constructor(init?: Partial<AccountsEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
export const AccountsEntitySchema: toZod<AccountsEntity> = z.late.object(() => ({
|
||||
id: z.number().finite(),
|
||||
username: z.string().nonempty(),
|
||||
password: z.string().nonempty().nullable(),
|
||||
nome: z.string().nonempty(),
|
||||
dataCreazione: z.date(),
|
||||
dataScadenza: z.date().nullable(),
|
||||
ultimoHashRefreshToken: z.string().nonempty().nullable(),
|
||||
profili: z.array(ProfiliEntitySchema),
|
||||
}));
|
@ -0,0 +1,25 @@
|
||||
import { Column, Entity, Index, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { ApiClientInvocazioniEntity } from './api_client_invocazioni.entity';
|
||||
|
||||
@Index('pk_api_client', ['id'], { unique: true })
|
||||
@Entity('api_client')
|
||||
export class ApiClientEntity {
|
||||
@PrimaryGeneratedColumn({ type: 'int', name: 'id' })
|
||||
id!: number;
|
||||
|
||||
@Column('varchar', { name: 'nome', nullable: true, length: 255 })
|
||||
nome!: string | null;
|
||||
|
||||
@Column('varchar', { name: 'descrizione', nullable: true, length: 255 })
|
||||
descrizione!: string | null;
|
||||
|
||||
@Column('varchar', { name: 'base_url', length: 2000 })
|
||||
baseUrl!: string;
|
||||
|
||||
@OneToMany(() => ApiClientInvocazioniEntity, (apiClientInvocazioniEntity) => apiClientInvocazioniEntity.client)
|
||||
invocazioni!: ApiClientInvocazioniEntity[];
|
||||
|
||||
constructor(init?: Partial<ApiClientEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { ApiClientEntity } from './api_client.entity';
|
||||
|
||||
@Index('pk_api_client_invocazioni', ['id'], { unique: true })
|
||||
@Entity('api_client_invocazioni')
|
||||
export class ApiClientInvocazioniEntity {
|
||||
@PrimaryGeneratedColumn({ type: 'int', name: 'id' })
|
||||
id!: number;
|
||||
|
||||
@Column('int', { name: 'id_client' })
|
||||
idClient!: number;
|
||||
|
||||
@Column('varchar', { name: 'percorso', length: 2000 })
|
||||
percorso!: string;
|
||||
|
||||
@Column('varchar', { name: 'metodo', length: 7 })
|
||||
metodo!: string;
|
||||
|
||||
@Column('datetime', { name: 'timestamp' })
|
||||
timestamp!: Date;
|
||||
|
||||
@Column('varchar', { name: 'richiesta', nullable: true })
|
||||
richiesta!: string | null;
|
||||
|
||||
@Column('varchar', { name: 'risposta' })
|
||||
risposta!: string;
|
||||
|
||||
@Column('varchar', { name: 'errori', nullable: true })
|
||||
errori!: string | null;
|
||||
|
||||
@Column('bit', { name: 'flag_errore' })
|
||||
flagErrore!: boolean;
|
||||
|
||||
@ManyToOne(() => ApiClientEntity, (apiClientEntity) => apiClientEntity.invocazioni)
|
||||
@JoinColumn([{ name: 'id_client', referencedColumnName: 'id' }])
|
||||
client!: ApiClientEntity;
|
||||
|
||||
constructor(init?: Partial<ApiClientInvocazioniEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { Column, Entity, Index, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { ApiEndpointInvocazioniEntity } from './api_endpoint_invocazioni.entity';
|
||||
|
||||
@Index('pk_api_endpoint', ['id'], { unique: true })
|
||||
@Entity('api_endpoint')
|
||||
export class ApiEndpointEntity {
|
||||
@PrimaryGeneratedColumn({ type: 'int', name: 'id' })
|
||||
id!: number;
|
||||
|
||||
@Column('varchar', { name: 'percorso', length: 2000 })
|
||||
percorso!: string;
|
||||
|
||||
@Column('varchar', { name: 'metodo', length: 7 })
|
||||
metodo!: string;
|
||||
|
||||
@OneToMany(
|
||||
() => ApiEndpointInvocazioniEntity,
|
||||
(apiEndpointInvocazioniEntity) => apiEndpointInvocazioniEntity.endpoint
|
||||
)
|
||||
invocazioni!: ApiEndpointInvocazioniEntity[];
|
||||
|
||||
constructor(init?: Partial<ApiEndpointEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { AccountsEntity } from './accounts.entity';
|
||||
import { ApiEndpointEntity } from './api_endpoint.entity';
|
||||
|
||||
@Index('pk_api_endpoint_invocazioni', ['id'], { unique: true })
|
||||
@Entity('api_endpoint_invocazioni')
|
||||
export class ApiEndpointInvocazioniEntity {
|
||||
@PrimaryGeneratedColumn({ type: 'int', name: 'id' })
|
||||
id!: number;
|
||||
|
||||
@Column('int', { name: 'id_account' })
|
||||
idAccount!: number;
|
||||
|
||||
@Column('int', { name: 'id_endpoint' })
|
||||
idEndpoint!: number;
|
||||
|
||||
@Column('datetime', { name: 'timestamp' })
|
||||
timestamp!: Date;
|
||||
|
||||
@Column('varchar', { name: 'richiesta' })
|
||||
richiesta!: string;
|
||||
|
||||
@Column('varchar', { name: 'risposta' })
|
||||
risposta!: string;
|
||||
|
||||
@Column('bit', { name: 'flag_errore' })
|
||||
flagErrore!: boolean;
|
||||
|
||||
@ManyToOne(() => ApiEndpointEntity, (apiEndpointEntity) => apiEndpointEntity.invocazioni)
|
||||
@JoinColumn([{ name: 'id_endpoint', referencedColumnName: 'id' }])
|
||||
endpoint!: ApiEndpointEntity;
|
||||
|
||||
@ManyToOne(() => AccountsEntity)
|
||||
@JoinColumn([{ name: 'id_account', referencedColumnName: 'id' }])
|
||||
account!: AccountsEntity;
|
||||
|
||||
constructor(init?: Partial<ApiEndpointInvocazioniEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
export * from './accounts.entity';
|
||||
export * from './api_client.entity';
|
||||
export * from './api_client_invocazioni.entity';
|
||||
export * from './api_endpoint.entity';
|
||||
export * from './api_endpoint_invocazioni.entity';
|
||||
export * from './profili.entity';
|
||||
export * from './ruoli.entity';
|
||||
export * from './tipi_jobs.entity';
|
@ -0,0 +1,38 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { AccountsEntity, AccountsEntitySchema } from './accounts.entity';
|
||||
import { RuoliEntity, RuoliEntitySchema } from './ruoli.entity';
|
||||
import { toZod } from 'tozod';
|
||||
import { z } from 'zod';
|
||||
|
||||
@Index('pk_profili', ['id'], { unique: true })
|
||||
@Entity('profili')
|
||||
export class ProfiliEntity {
|
||||
@Column('int', { primary: true, name: 'id' })
|
||||
id!: number;
|
||||
|
||||
@Column('int', { name: 'id_account', unique: true })
|
||||
idAccount!: number;
|
||||
|
||||
@Column('int', { name: 'id_ruolo', unique: true })
|
||||
idRuolo!: number;
|
||||
|
||||
@ManyToOne(() => AccountsEntity, (accountsEntity) => accountsEntity.profili)
|
||||
@JoinColumn([{ name: 'id_account', referencedColumnName: 'id' }])
|
||||
account!: AccountsEntity;
|
||||
|
||||
@ManyToOne(() => RuoliEntity, (ruoliEntity) => ruoliEntity.profili)
|
||||
@JoinColumn([{ name: 'id_ruolo', referencedColumnName: 'id' }])
|
||||
ruolo!: RuoliEntity;
|
||||
|
||||
constructor(init?: Partial<ProfiliEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
export const ProfiliEntitySchema: toZod<ProfiliEntity> = z.late.object(() => ({
|
||||
id: z.number().finite(),
|
||||
idAccount: AccountsEntitySchema.shape.id,
|
||||
idRuolo: RuoliEntitySchema.shape.id,
|
||||
account: AccountsEntitySchema,
|
||||
ruolo: RuoliEntitySchema,
|
||||
}));
|
@ -0,0 +1,31 @@
|
||||
import { Column, Entity, Index, OneToMany } from 'typeorm';
|
||||
import { ProfiliEntity, ProfiliEntitySchema } from './profili.entity';
|
||||
import { toZod } from 'tozod';
|
||||
import { z } from 'zod';
|
||||
|
||||
@Index('pk_ruoli', ['id'], { unique: true })
|
||||
@Entity('ruoli')
|
||||
export class RuoliEntity {
|
||||
@Column('int', { primary: true, name: 'id' })
|
||||
id!: number;
|
||||
|
||||
@Column('varchar', { name: 'nome', unique: true, length: 255 })
|
||||
nome!: string;
|
||||
|
||||
@Column('varchar', { name: 'descrizione', length: 255 })
|
||||
descrizione!: string;
|
||||
|
||||
@OneToMany(() => ProfiliEntity, (profiliEntity) => profiliEntity.ruolo)
|
||||
profili!: ProfiliEntity[];
|
||||
|
||||
constructor(init?: Partial<RuoliEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
export const RuoliEntitySchema: toZod<RuoliEntity> = z.late.object(() => ({
|
||||
id: z.number().finite(),
|
||||
nome: z.string().nonempty(),
|
||||
descrizione: z.string().nonempty(),
|
||||
profili: z.array(ProfiliEntitySchema),
|
||||
}));
|
@ -0,0 +1,49 @@
|
||||
import { Column, Entity, Index } from 'typeorm';
|
||||
import { Enum, Enumify } from '../../../../enumify/enumify';
|
||||
|
||||
export class InviaMailSeErrori {
|
||||
@Column('bit', { name: 'flag', default: () => '(0)' })
|
||||
flagAttivo!: boolean;
|
||||
|
||||
@Column('varchar', { name: 'oggetto', nullable: true, length: 255 })
|
||||
oggetto!: string | null;
|
||||
|
||||
@Column('varchar', { name: 'destinatari', nullable: true, length: 255 })
|
||||
destinatari!: string | null;
|
||||
|
||||
@Column('varchar', { name: 'cc', nullable: true, length: 255 })
|
||||
cc!: string | null;
|
||||
}
|
||||
|
||||
@Index('pk_tipi_jobs', ['id'], { unique: true })
|
||||
@Entity('tipi_jobs')
|
||||
export class TipiJobsEntity extends Enumify {
|
||||
static _ = TipiJobsEntity.closeEnum();
|
||||
|
||||
@Column('int', { primary: true, name: 'id' })
|
||||
id!: number;
|
||||
|
||||
@Column('varchar', { name: 'nome', length: 50 })
|
||||
nome!: string;
|
||||
|
||||
@Column('varchar', { name: 'descrizione', nullable: true, length: 255 })
|
||||
descrizione!: string | null;
|
||||
|
||||
@Column(() => InviaMailSeErrori, { prefix: 'invia_mail_se_errori'})
|
||||
inviaMailSeErrori!: InviaMailSeErrori;
|
||||
|
||||
@Column('bit', { name: 'flag_attivo', default: () => '(0)' })
|
||||
flagAttivo!: boolean;
|
||||
|
||||
@Column('varchar', { name: 'pattern_cron', length: 20 })
|
||||
patternCron!: string;
|
||||
|
||||
public constructor(
|
||||
id: number,
|
||||
nome: string,
|
||||
patternCron: string,
|
||||
) {
|
||||
super(id, nome);
|
||||
this.patternCron = patternCron;
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export * from './entities';
|
@ -0,0 +1,10 @@
|
||||
import coerceRecordTypes from '../../../config/utils/coerce-record-types';
|
||||
import { databaseConfigFactory, rawDatabaseSchema } from '../../utils/database-config';
|
||||
|
||||
const env = coerceRecordTypes(process.env);
|
||||
const envParsed = rawDatabaseSchema.strict().parse({
|
||||
connectionString: env['DATABASE_OCEANO_CONNECTION_STRING'],
|
||||
secure: env['DATABASE_OCEANO_SECURE'],
|
||||
});
|
||||
|
||||
export const databaseConfig = databaseConfigFactory(envParsed);
|
@ -0,0 +1 @@
|
||||
export const OCEANO_DATASOURCE = "Oceano";
|
@ -0,0 +1,32 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { DatabaseConfig } from '../../utils/database-config';
|
||||
import { typeormTransactionalDataSourceFactory } from '../../utils/typeorm-data-source-factory';
|
||||
import { typeormEntitiesFromImport } from '../../utils/typeorm-import-entities';
|
||||
import { typeormModuleOptionsFactory } from '../../utils/typeorm-module-options-factory';
|
||||
import { databaseConfig } from './database.config';
|
||||
import { OCEANO_DATASOURCE } from './database.constants';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forFeature(databaseConfig),
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: databaseConfig.asProvider().imports,
|
||||
name: OCEANO_DATASOURCE,
|
||||
dataSourceFactory: typeormTransactionalDataSourceFactory(OCEANO_DATASOURCE),
|
||||
useFactory: async (dbConfig: DatabaseConfig) => {
|
||||
const config = await typeormModuleOptionsFactory(
|
||||
dbConfig,
|
||||
await typeormEntitiesFromImport(await import('./index')),
|
||||
OCEANO_DATASOURCE
|
||||
);
|
||||
return config;
|
||||
},
|
||||
inject: [databaseConfig.KEY],
|
||||
}),
|
||||
],
|
||||
providers: [],
|
||||
exports: [TypeOrmModule],
|
||||
})
|
||||
export class OceanoDatabaseModule {}
|
@ -0,0 +1,20 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { ApiLuoghiEntity } from './API_Luoghi.entity';
|
||||
|
||||
@Index('nk_API_CAP_Luoghi', ['codice', 'cap'], { unique: true })
|
||||
@Entity('API_CAP_Luoghi')
|
||||
export class ApiCapLuoghiEntity {
|
||||
@Column('varchar', { primary: true, name: 'codice', length: 5 })
|
||||
codice!: string;
|
||||
|
||||
@Column('varchar', { primary: true, name: 'cap', length: 5 })
|
||||
cap!: string;
|
||||
|
||||
@ManyToOne(() => ApiLuoghiEntity)
|
||||
@JoinColumn([{ name: 'codice', referencedColumnName: 'codice' }])
|
||||
luogo!: ApiLuoghiEntity;
|
||||
|
||||
constructor(init?: Partial<ApiCapLuoghiEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
import { Column, Entity, Index, OneToMany } from 'typeorm';
|
||||
import { ApiCapLuoghiEntity } from './API_CAP_Luoghi.entity';
|
||||
import { SocioEntity } from './socio.entity';
|
||||
|
||||
@Index('PK_API_Luoghi', ['codice'], { unique: true })
|
||||
@Entity('API_Luoghi')
|
||||
export class ApiLuoghiEntity {
|
||||
@Column('varchar', { primary: true, name: 'codice', length: 5 })
|
||||
codice!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'comune', nullable: true, length: 255 })
|
||||
comune!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'sigla_provincia', nullable: true, length: 5 })
|
||||
siglaProvincia!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'provincia', nullable: true, length: 255 })
|
||||
provincia!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codice_regione', nullable: true, length: 5 })
|
||||
codiceRegione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'regione', nullable: true, length: 255 })
|
||||
regione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codice_stato', nullable: true, length: 5 })
|
||||
codiceStato!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'stato', nullable: true, length: 255 })
|
||||
stato!: string | null;
|
||||
|
||||
@Column('int', { name: 'flag_attivo', nullable: true })
|
||||
flagAttivo!: number | null;
|
||||
|
||||
constructor(init?: Partial<ApiLuoghiEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import { Column, Entity, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Entity('API_Luoghi_Estero')
|
||||
export class ApiLuoghiEsteroEntity {
|
||||
@PrimaryColumn('varchar', { name: 'codice', length: 5 })
|
||||
codice!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'codice_stato', length: 5 })
|
||||
codiceStato!: string;
|
||||
|
||||
constructor(init?: Partial<ApiLuoghiEsteroEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
|
||||
@Index('PK_allegati', ['codiceAllegato'], { unique: true })
|
||||
@Entity('allegati')
|
||||
export class AllegatiEntity {
|
||||
@Column('bigint', { primary: true, name: 'codiceAllegato' })
|
||||
codiceAllegato!: string;
|
||||
|
||||
@Column('int', { name: 'tipoOrigine', nullable: true })
|
||||
tipoOrigine!: number | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceOrigine', nullable: true })
|
||||
codiceOrigine!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'descrizioneAllegato',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
descrizioneAllegato!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataAllegato', nullable: true, length: 10 })
|
||||
dataAllegato!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'cartellaAllegato',
|
||||
nullable: true,
|
||||
length: 2048,
|
||||
})
|
||||
cartellaAllegato!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'nomeFileAllegato', nullable: true, length: 255 })
|
||||
nomeFileAllegato!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'noteAllegato', nullable: true })
|
||||
noteAllegato!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteCreazione', nullable: true })
|
||||
utenteCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataCreazione', nullable: true, length: 10 })
|
||||
dataCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraCreazione', nullable: true, length: 8 })
|
||||
oraCreazione!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteModifica', nullable: true })
|
||||
utenteModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataModifica', nullable: true, length: 10 })
|
||||
dataModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraModifica', nullable: true, length: 8 })
|
||||
oraModifica!: string | null;
|
||||
|
||||
@Column('int', { name: 'pubblicatoWEB', nullable: true })
|
||||
pubblicatoWeb!: number | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'trasferitoWEB',
|
||||
nullable: true,
|
||||
default: () => '(0)',
|
||||
})
|
||||
trasferitoWeb!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataPubblicazione',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
default: () => "''",
|
||||
})
|
||||
dataPubblicazione!: string | null;
|
||||
|
||||
@Column('bigint', {
|
||||
name: 'codiceProtocolloGenerico',
|
||||
nullable: true,
|
||||
default: () => '(0)',
|
||||
})
|
||||
codiceProtocolloGenerico!: string | null;
|
||||
|
||||
constructor(init?: Partial<AllegatiEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,492 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { EnteEntity } from './ente.entity';
|
||||
import { SocioContrattoEntity } from './socioContratto.entity';
|
||||
|
||||
@Index('PK_contratto', ['codiceContratto'], { unique: true })
|
||||
@Entity('contratto')
|
||||
export class ContrattoEntity {
|
||||
@Column('bigint', { primary: true, name: 'codiceContratto' })
|
||||
codiceContratto!: string;
|
||||
|
||||
@Column('bigint', { name: 'codiceEnte', nullable: true })
|
||||
codiceEnte!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'contratto', nullable: true, length: 255 })
|
||||
contratto!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataContratto', nullable: true, length: 10 })
|
||||
dataContratto!: string | null;
|
||||
|
||||
@Column('int', { name: 'rinnovoAutomatico', nullable: true })
|
||||
rinnovoAutomatico!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataDecorrenzaContratto',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataDecorrenzaContratto!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'codiceEconomicoEsolver',
|
||||
nullable: true,
|
||||
length: 30,
|
||||
})
|
||||
codiceEconomicoEsolver!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'codicePatrimonialeEsolver',
|
||||
nullable: true,
|
||||
length: 30,
|
||||
})
|
||||
codicePatrimonialeEsolver!: string | null;
|
||||
|
||||
@Column('int', { name: 'iscrizioneFamiliariObbligatoria', nullable: true })
|
||||
iscrizioneFamiliariObbligatoria!: number | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'inizioDecorrenzaNuoveAdesioniAderenti',
|
||||
nullable: true,
|
||||
})
|
||||
inizioDecorrenzaNuoveAdesioniAderenti!: number | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'inizioDecorrenzaNuoveAdesioniFamiliari',
|
||||
nullable: true,
|
||||
})
|
||||
inizioDecorrenzaNuoveAdesioniFamiliari!: number | null;
|
||||
|
||||
@Column('int', { name: 'cessazioneInfraAnnuale', nullable: true })
|
||||
cessazioneInfraAnnuale!: number | null;
|
||||
|
||||
@Column('int', { name: 'numeroGiorniRimborso', nullable: true })
|
||||
numeroGiorniRimborso!: number | null;
|
||||
|
||||
@Column('int', { name: 'rimborsoPersona', nullable: true })
|
||||
rimborsoPersona!: number | null;
|
||||
|
||||
@Column('int', { name: 'rimborsoFax', nullable: true })
|
||||
rimborsoFax!: number | null;
|
||||
|
||||
@Column('int', { name: 'rimborsoEmail', nullable: true })
|
||||
rimborsoEmail!: number | null;
|
||||
|
||||
@Column('int', { name: 'rimborsoPosta', nullable: true })
|
||||
rimborsoPosta!: number | null;
|
||||
|
||||
@Column('int', { name: 'rimborsoWeb', nullable: true })
|
||||
rimborsoWeb!: number | null;
|
||||
|
||||
@Column('bigint', { name: 'utentecreazione', nullable: true })
|
||||
utentecreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataCreazione', nullable: true, length: 10 })
|
||||
dataCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraCreazione', nullable: true, length: 8 })
|
||||
oraCreazione!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteModifica', nullable: true })
|
||||
utenteModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataModifica', nullable: true, length: 10 })
|
||||
dataModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraModifica', nullable: true, length: 8 })
|
||||
oraModifica!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'noteContratto', nullable: true })
|
||||
noteContratto!: string | null;
|
||||
|
||||
@Column('int', { name: 'versamentiTerzi', nullable: true })
|
||||
versamentiTerzi!: number | null;
|
||||
|
||||
@Column('int', { name: 'ignoraControlloPagamenti', nullable: true })
|
||||
ignoraControlloPagamenti!: number | null;
|
||||
|
||||
@Column('int', { name: 'anniRinnovo', nullable: true })
|
||||
anniRinnovo!: number | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceRivenditore', nullable: true })
|
||||
codiceRivenditore!: string | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'inizioDecorrenzaNuoveAdesioniNascita',
|
||||
nullable: true,
|
||||
})
|
||||
inizioDecorrenzaNuoveAdesioniNascita!: number | null;
|
||||
|
||||
@Column('int', { name: 'numeroGiorniNascita', nullable: true })
|
||||
numeroGiorniNascita!: number | null;
|
||||
|
||||
@Column('int', { name: 'mesiEsclusionePatologieAderenti', nullable: true })
|
||||
mesiEsclusionePatologieAderenti!: number | null;
|
||||
|
||||
@Column('int', { name: 'mesiEsclusionePatologieFamiliari', nullable: true })
|
||||
mesiEsclusionePatologieFamiliari!: number | null;
|
||||
|
||||
@Column('int', { name: 'coperturaPreesistenzeAderenti', nullable: true })
|
||||
coperturaPreesistenzeAderenti!: number | null;
|
||||
|
||||
@Column('int', { name: 'coperturaPreesistenzeFamiliari', nullable: true })
|
||||
coperturaPreesistenzeFamiliari!: number | null;
|
||||
|
||||
@Column('int', { name: 'adesioniFdaIndividuali', nullable: true })
|
||||
adesioniFdaIndividuali!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataAssunzioneAderenti',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataAssunzioneAderenti!: string | null;
|
||||
|
||||
@Column('int', { name: 'associazioniIndividuali', nullable: true })
|
||||
associazioniIndividuali!: number | null;
|
||||
|
||||
@Column('bigint', { name: 'categoria', nullable: true })
|
||||
categoria!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'email', nullable: true, length: 80 })
|
||||
email!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'fax', nullable: true, length: 80 })
|
||||
fax!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'telefono', nullable: true, length: 80 })
|
||||
telefono!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'sitoWeb', nullable: true, length: 80 })
|
||||
sitoWeb!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'riferimento', nullable: true, length: 80 })
|
||||
riferimento!: string | null;
|
||||
|
||||
@Column('int', { name: 'comunicazioniFax', nullable: true })
|
||||
comunicazioniFax!: number | null;
|
||||
|
||||
@Column('int', { name: 'comunicazioniEmail', nullable: true })
|
||||
comunicazioniEmail!: number | null;
|
||||
|
||||
@Column('int', { name: 'comunicazioniSito', nullable: true })
|
||||
comunicazioniSito!: number | null;
|
||||
|
||||
@Column('int', { name: 'comunicazioniPosta', nullable: true })
|
||||
comunicazioniPosta!: number | null;
|
||||
|
||||
@Column('int', { name: 'gestionePreventiviWEB', nullable: true })
|
||||
gestionePreventiviWeb!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'codiceDocumentoWEB',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
codiceDocumentoWeb!: string | null;
|
||||
|
||||
@Column('int', { name: 'numeroGiorniEffettuareRimborsi', nullable: true })
|
||||
numeroGiorniEffettuareRimborsi!: number | null;
|
||||
|
||||
@Column('int', { name: 'numeroGiorniIntegrazioneDocumenti', nullable: true })
|
||||
numeroGiorniIntegrazioneDocumenti!: number | null;
|
||||
|
||||
@Column('int', { name: 'gestioneIndividuali', nullable: true })
|
||||
gestioneIndividuali!: number | null;
|
||||
|
||||
@Column('int', { name: 'fondoPluriaziendale', nullable: true })
|
||||
fondoPluriaziendale!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'emailCertificata', nullable: true, length: 80 })
|
||||
emailCertificata!: string | null;
|
||||
|
||||
@Column('int', { name: 'comunicazioniEmailCertificata', nullable: true })
|
||||
comunicazioniEmailCertificata!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataAssunzioneFamiliari',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataAssunzioneFamiliari!: string | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'coperturaPreesistenzeAderentiNuoveAssunzioni',
|
||||
nullable: true,
|
||||
})
|
||||
coperturaPreesistenzeAderentiNuoveAssunzioni!: number | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'coperturaPreesistenzeFamiliariNuoveAssunzioni',
|
||||
nullable: true,
|
||||
})
|
||||
coperturaPreesistenzeFamiliariNuoveAssunzioni!: number | null;
|
||||
|
||||
@Column('int', { name: 'noCessazioneAutomaticaFineAnno', nullable: true })
|
||||
noCessazioneAutomaticaFineAnno!: number | null;
|
||||
|
||||
@Column('int', { name: 'contrattoRateSemestrali', nullable: true })
|
||||
contrattoRateSemestrali!: number | null;
|
||||
|
||||
@Column('decimal', {
|
||||
name: 'moraRitardoPagamenti',
|
||||
nullable: true,
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
})
|
||||
moraRitardoPagamenti!: number | null;
|
||||
|
||||
@Column('decimal', {
|
||||
name: 'quotaRichiestaFondo',
|
||||
nullable: true,
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
})
|
||||
quotaRichiestaFondo!: number | null;
|
||||
|
||||
@Column('int', { name: 'percQuotaRichiestaFondo', nullable: true })
|
||||
percQuotaRichiestaFondo!: number | null;
|
||||
|
||||
@Column('int', { name: 'scontoIndividuali', nullable: true })
|
||||
scontoIndividuali!: number | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'modalitaCalcoloDatiContributiviIndividuali',
|
||||
nullable: true,
|
||||
})
|
||||
modalitaCalcoloDatiContributiviIndividuali!: number | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceFiguraContratto', nullable: true })
|
||||
codiceFiguraContratto!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeModelloTesserini',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
nomeModelloTesserini!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeModelloLettera',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
nomeModelloLettera!: string | null;
|
||||
|
||||
@Column('int', { name: 'ignoraControlloPagamentiTitolare', nullable: true })
|
||||
ignoraControlloPagamentiTitolare!: number | null;
|
||||
|
||||
@Column('int', { name: 'ignoraControlloPagamentiAzienda', nullable: true })
|
||||
ignoraControlloPagamentiAzienda!: number | null;
|
||||
|
||||
@Column('bigint', { name: 'codicePromoter', nullable: true })
|
||||
codicePromoter!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceOriginePromoter', nullable: true })
|
||||
codiceOriginePromoter!: string | null;
|
||||
|
||||
@Column('int', { name: 'fornituraTesserino', nullable: true })
|
||||
fornituraTesserino!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataChiusuraContratto',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataChiusuraContratto!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeModelloLetteraRID',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
nomeModelloLetteraRid!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeModelloLetteraAdesione',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
nomeModelloLetteraAdesione!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeModelloLetteraAdeguamenti',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
nomeModelloLetteraAdeguamenti!: string | null;
|
||||
|
||||
@Column('int', { name: 'coopersalute', nullable: true })
|
||||
coopersalute!: number | null;
|
||||
|
||||
@Column('int', { name: 'forzaEstensioneTolleranza', nullable: true })
|
||||
forzaEstensioneTolleranza!: number | null;
|
||||
|
||||
@Column('int', { name: 'giorniEstensioneTolleranza', nullable: true })
|
||||
giorniEstensioneTolleranza!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeModelloLetteraSollecito',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
nomeModelloLetteraSollecito!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeModelloLetteraSollecito2',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
nomeModelloLetteraSollecito2!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeModelloLetteraNeonato',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
nomeModelloLetteraNeonato!: string | null;
|
||||
|
||||
@Column('int', { name: 'comunicazioniViaEmail', nullable: true })
|
||||
comunicazioniViaEmail!: number | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'modalitaCalcoloQuotaAssociativaFondo',
|
||||
default: () => '(0)',
|
||||
})
|
||||
modalitaCalcoloQuotaAssociativaFondo!: number;
|
||||
|
||||
@Column('int', {
|
||||
name: 'modalitaCalcoloQuotaAssociativaNumeroFondo',
|
||||
default: () => '(0)',
|
||||
})
|
||||
modalitaCalcoloQuotaAssociativaNumeroFondo!: number;
|
||||
|
||||
@Column('int', { name: 'quotaAssociativaFondo', default: () => '(0)' })
|
||||
quotaAssociativaFondo!: number;
|
||||
|
||||
@Column('int', { name: 'tipoAnamnesi', default: () => '(1)' })
|
||||
tipoAnamnesi!: number;
|
||||
|
||||
@Column('int', { name: 'primoCheck', default: () => '(1)' })
|
||||
primoCheck!: number;
|
||||
|
||||
@Column('int', { name: 'secondoCheck', default: () => '(1)' })
|
||||
secondoCheck!: number;
|
||||
|
||||
@Column('ntext', { name: 'testoPrimoCheck', default: () => "''" })
|
||||
testoPrimoCheck!: string;
|
||||
|
||||
@Column('ntext', { name: 'testoSecondoCheck', default: () => "''" })
|
||||
testoSecondoCheck!: string;
|
||||
|
||||
@Column('int', { name: 'calcolaQuotaWEB', default: () => '(1)' })
|
||||
calcolaQuotaWeb!: number;
|
||||
|
||||
@Column('int', { name: 'verificaEsistenzaOnline', default: () => '(1)' })
|
||||
verificaEsistenzaOnline!: number;
|
||||
|
||||
@Column('int', { name: 'titolareGiaAssociato', default: () => '(1)' })
|
||||
titolareGiaAssociato!: number;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'intestazionePrimaPaginaAdesione',
|
||||
default: () => "''",
|
||||
})
|
||||
intestazionePrimaPaginaAdesione!: string;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'intestazioneUltimaPaginaAdesione',
|
||||
default: () => "''",
|
||||
})
|
||||
intestazioneUltimaPaginaAdesione!: string;
|
||||
|
||||
@Column('int', { name: 'importaComeAssociati', default: () => '(1)' })
|
||||
importaComeAssociati!: number;
|
||||
|
||||
@Column('int', { name: 'importazioneAutomatica', default: () => '(1)' })
|
||||
importazioneAutomatica!: number;
|
||||
|
||||
@Column('int', { name: 'stampaModuloAdesione', default: () => '(1)' })
|
||||
stampaModuloAdesione!: number;
|
||||
|
||||
@Column('int', { name: 'terzoCheck', default: () => '(1)' })
|
||||
terzoCheck!: number;
|
||||
|
||||
@Column('ntext', { name: 'testoTerzoCheck', default: () => "''" })
|
||||
testoTerzoCheck!: string;
|
||||
|
||||
@Column('ntext', { name: 'testoEmailPreventivo', default: () => "''" })
|
||||
testoEmailPreventivo!: string;
|
||||
|
||||
@Column('ntext', { name: 'testoEmailAdesione', default: () => "''" })
|
||||
testoEmailAdesione!: string;
|
||||
|
||||
@Column('ntext', { name: 'oggettoEmailPreventivo', default: () => "''" })
|
||||
oggettoEmailPreventivo!: string;
|
||||
|
||||
@Column('ntext', { name: 'oggettoEmailAdesione', default: () => "''" })
|
||||
oggettoEmailAdesione!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeModelloLetteraStampaAdesione',
|
||||
length: 255,
|
||||
default: () => "''",
|
||||
})
|
||||
nomeModelloLetteraStampaAdesione!: string;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'oggettoSecondaNotificaScadenzaPreventivo',
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoSecondaNotificaScadenzaPreventivo!: string;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'oggettoPrimaNotificaScadenzaPreventivo',
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoPrimaNotificaScadenzaPreventivo!: string;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'testoSecondaNotificaScadenzaPreventivo',
|
||||
default: () => "''",
|
||||
})
|
||||
testoSecondaNotificaScadenzaPreventivo!: string;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'testoPrimaNotificaScadenzaPreventivo',
|
||||
default: () => "''",
|
||||
})
|
||||
testoPrimaNotificaScadenzaPreventivo!: string;
|
||||
|
||||
@Column('bigint', { name: 'codiceBancaContributi', default: () => '(0)' })
|
||||
codiceBancaContributi!: string;
|
||||
|
||||
@Column('bigint', { name: 'codiceBancaRimborsi', default: () => '(0)' })
|
||||
codiceBancaRimborsi!: string;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'testataCertificazione',
|
||||
nullable: true,
|
||||
default: () => "''",
|
||||
})
|
||||
testataCertificazione!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'codaCertificazione', default: () => "''" })
|
||||
codaCertificazione!: string;
|
||||
|
||||
@Column('ntext', { name: 'testataRiepilogoRimborsi', default: () => "''" })
|
||||
testataRiepilogoRimborsi!: string;
|
||||
|
||||
@Column('int', { name: 'adesioneInfraAnnuale', default: () => '(0)' })
|
||||
adesioneInfraAnnuale!: number;
|
||||
|
||||
@ManyToOne(() => EnteEntity, (enteEntity) => enteEntity.contratti)
|
||||
@JoinColumn([{ name: 'codiceEnte', referencedColumnName: 'codiceEnte' }])
|
||||
ente!: EnteEntity;
|
||||
|
||||
@OneToMany(() => SocioContrattoEntity, (socioContrattoEntity) => socioContrattoEntity.contratto)
|
||||
socioContratto!: SocioContrattoEntity[];
|
||||
|
||||
constructor(init?: Partial<ContrattoEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { ContrattoEntity } from './contratto.entity';
|
||||
import { GruppoEntity } from './gruppo.entity';
|
||||
|
||||
@Index('PK_ent', ['codiceEnte'], { unique: true })
|
||||
@Entity('ente')
|
||||
export class EnteEntity {
|
||||
@Column('bigint', { primary: true, name: 'codiceEnte' })
|
||||
codiceEnte!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'ragioneSociale', nullable: true, length: 255 })
|
||||
ragioneSociale!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'partitaIva', nullable: true, length: 25 })
|
||||
partitaIva!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codiceFiscale', nullable: true, length: 25 })
|
||||
codiceFiscale!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'noteEnte', nullable: true })
|
||||
noteEnte!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'codiceDivisioneEsolver',
|
||||
nullable: true,
|
||||
length: 25,
|
||||
})
|
||||
codiceDivisioneEsolver!: string | null;
|
||||
|
||||
@Column('int', { name: 'enteAttivo', nullable: true })
|
||||
enteAttivo!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'indirizzoEnte', nullable: true, length: 80 })
|
||||
indirizzoEnte!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'numeroCivicoEnte', nullable: true, length: 80 })
|
||||
numeroCivicoEnte!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'capEnte', nullable: true, length: 10 })
|
||||
capEnte!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'localitaEnte', nullable: true, length: 80 })
|
||||
localitaEnte!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteCreazione', nullable: true })
|
||||
utenteCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataCreazione', nullable: true, length: 10 })
|
||||
dataCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraCreazione', nullable: true, length: 8 })
|
||||
oraCreazione!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteModifica', nullable: true })
|
||||
utenteModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataModifica', nullable: true, length: 10 })
|
||||
dataModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraModifica', nullable: true, length: 8 })
|
||||
oraModifica!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceGruppo', nullable: true })
|
||||
codiceGruppo!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'statoEnte', nullable: true })
|
||||
statoEnte!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'provinciaEnte', nullable: true })
|
||||
provinciaEnte!: string | null;
|
||||
|
||||
@Column('int', { name: 'inOsservazione', nullable: true })
|
||||
inOsservazione!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'sitoInternet', nullable: true, length: 255 })
|
||||
sitoInternet!: string | null;
|
||||
|
||||
@ManyToOne(() => GruppoEntity, (gruppoEntity) => gruppoEntity.enti)
|
||||
gruppo!: ContrattoEntity;
|
||||
|
||||
@OneToMany(() => ContrattoEntity, (contrattoEntity) => contrattoEntity.ente)
|
||||
contratti!: ContrattoEntity[];
|
||||
|
||||
constructor(init?: Partial<EnteEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { SocioFormeAssistenzaEntity } from './socioFormeAssistenza.entity';
|
||||
|
||||
@Index('PK_formeAssistenza', ['codiceFda'], { unique: true })
|
||||
@Entity('formeAssistenza')
|
||||
export class FormeAssistenzaEntity {
|
||||
@Column('bigint', { name: 'codiceGruppo' })
|
||||
codiceGruppo!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'codiceFda' })
|
||||
codiceFda!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'descrizioneFda', nullable: true, length: 80 })
|
||||
descrizioneFda!: string | null;
|
||||
|
||||
@Column('int', { name: 'attivaFda', nullable: true })
|
||||
attivaFda!: number | null;
|
||||
|
||||
@Column('int', { name: 'fornituraTesserino', nullable: true })
|
||||
fornituraTesserino!: number | null;
|
||||
|
||||
@Column('ntext', { name: 'noteFda', nullable: true })
|
||||
noteFda!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteCreazione', nullable: true })
|
||||
utenteCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataCreazione', nullable: true, length: 10 })
|
||||
dataCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraCreazione', nullable: true, length: 8 })
|
||||
oraCreazione!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteModifica', nullable: true })
|
||||
utenteModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataModifica', nullable: true, length: 10 })
|
||||
dataModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraModifica', nullable: true, length: 8 })
|
||||
oraModifica!: string | null;
|
||||
|
||||
@Column('int', { name: 'attivaDiretta', nullable: true })
|
||||
attivaDiretta!: number | null;
|
||||
|
||||
@Column('int', { name: 'attivaIndiretta', nullable: true })
|
||||
attivaIndiretta!: number | null;
|
||||
|
||||
@Column('int', { name: 'anniAdesione', nullable: true })
|
||||
anniAdesione!: number | null;
|
||||
|
||||
@Column('int', { name: 'gestionePreventivo', nullable: true })
|
||||
gestionePreventivo!: number | null;
|
||||
|
||||
@Column('int', { name: 'interoNucleoFamiliare', nullable: true })
|
||||
interoNucleoFamiliare!: number | null;
|
||||
|
||||
@Column('int', { name: 'escludeDocRimborsi', nullable: true })
|
||||
escludeDocRimborsi!: number | null;
|
||||
|
||||
@Column('int', { name: 'struttureDirettaIncluse', nullable: true })
|
||||
struttureDirettaIncluse!: number | null;
|
||||
|
||||
@Column('int', { name: 'struttureIndirettaIncluse', nullable: true })
|
||||
struttureIndirettaIncluse!: number | null;
|
||||
|
||||
@Column('int', { name: 'categorieDirettaIncluse', nullable: true })
|
||||
categorieDirettaIncluse!: number | null;
|
||||
|
||||
@Column('int', { name: 'categorieIndirettaIncluse', nullable: true })
|
||||
categorieIndirettaIncluse!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'descrizioneTesserino',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
descrizioneTesserino!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceFdaOrigine', nullable: true })
|
||||
codiceFdaOrigine!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataInizioValidita',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataInizioValidita!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataFineValidita', nullable: true, length: 10 })
|
||||
dataFineValidita!: string | null;
|
||||
|
||||
@Column('int', { name: 'limiteMassimoAssistenza', nullable: true })
|
||||
limiteMassimoAssistenza!: number | null;
|
||||
|
||||
@Column('int', { name: 'limiteMinimoAssistenza', nullable: true })
|
||||
limiteMinimoAssistenza!: number | null;
|
||||
|
||||
@Column('int', { name: 'limiteEtaAderentiDa', nullable: true })
|
||||
limiteEtaAderentiDa!: number | null;
|
||||
|
||||
@Column('int', { name: 'limiteEtaFamiliariDa', nullable: true })
|
||||
limiteEtaFamiliariDa!: number | null;
|
||||
|
||||
@Column('int', { name: 'limiteEtaAderentiA', nullable: true })
|
||||
limiteEtaAderentiA!: number | null;
|
||||
|
||||
@Column('int', { name: 'limiteEtaFamiliariA', nullable: true })
|
||||
limiteEtaFamiliariA!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'descrizioneLettera',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
descrizioneLettera!: string | null;
|
||||
|
||||
@Column('int', { name: 'fdaOpzionale', nullable: true })
|
||||
fdaOpzionale!: number | null;
|
||||
|
||||
@Column('int', { name: 'giorniCarenzaTesserino', nullable: true })
|
||||
giorniCarenzaTesserino!: number | null;
|
||||
|
||||
@Column('ntext', { name: 'informazioni', nullable: true })
|
||||
informazioni!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'denominazioneRegolamento',
|
||||
nullable: true,
|
||||
length: 1024,
|
||||
default: () => "''",
|
||||
})
|
||||
denominazioneRegolamento!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataMassimaAdesione',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
default: () => "'9998-12-31'",
|
||||
})
|
||||
dataMassimaAdesione!: string | null;
|
||||
|
||||
@Column('int', { name: 'prioritaWeb', default: () => '(0)' })
|
||||
prioritaWeb!: number;
|
||||
|
||||
@Column('int', { name: 'attivaDirettaAreaRiservata', default: () => '(0)' })
|
||||
attivaDirettaAreaRiservata!: number;
|
||||
|
||||
@OneToMany(() => SocioFormeAssistenzaEntity, (socioFormeAssistenzaEntity) => socioFormeAssistenzaEntity.formaAssistenza)
|
||||
socioFormeAssistenza!: SocioFormeAssistenzaEntity[];
|
||||
|
||||
constructor(init?: Partial<FormeAssistenzaEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,660 @@
|
||||
import { Column, Entity, Index, OneToMany } from 'typeorm';
|
||||
import { EnteEntity } from './ente.entity';
|
||||
|
||||
@Index('PK_gruppo', ['codiceGruppo'], { unique: true })
|
||||
@Entity('gruppo')
|
||||
export class GruppoEntity {
|
||||
|
||||
|
||||
@Column('bigint', { primary: true, name: 'codiceGruppo' })
|
||||
codiceGruppo!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'gruppo', nullable: true, length: 80 })
|
||||
gruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'descrizioneGruppo',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
})
|
||||
descrizioneGruppo!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'noteGruppo', nullable: true })
|
||||
noteGruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'referenteGruppo', nullable: true, length: 80 })
|
||||
referenteGruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'telefonoReferente', nullable: true, length: 80 })
|
||||
telefonoReferente!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'cellulareReferente',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
cellulareReferente!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'emailReferente', nullable: true, length: 80 })
|
||||
emailReferente!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'indirizzoGruppo', nullable: true, length: 80 })
|
||||
indirizzoGruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'numeroCivicoGruppo',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
numeroCivicoGruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'capGruppo', nullable: true, length: 10 })
|
||||
capGruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'localitaGruppo', nullable: true, length: 80 })
|
||||
localitaGruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'telefono1Gruppo', nullable: true, length: 80 })
|
||||
telefono1Gruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'telefono2Gruppo', nullable: true, length: 80 })
|
||||
telefono2Gruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'faxGruppo', nullable: true, length: 80 })
|
||||
faxGruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'emailGruppo', nullable: true, length: 80 })
|
||||
emailGruppo!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'sitoWebGruppo', nullable: true, length: 80 })
|
||||
sitoWebGruppo!: string | null;
|
||||
|
||||
@Column('int', { name: 'gruppoAttivo', nullable: true })
|
||||
gruppoAttivo!: number | null;
|
||||
|
||||
@Column('int', { name: 'esolverAttivo', nullable: true })
|
||||
esolverAttivo!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'serverEsolver', nullable: true, length: 80 })
|
||||
serverEsolver!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'databaseEsolver', nullable: true, length: 80 })
|
||||
databaseEsolver!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'usernameEsolver', nullable: true, length: 80 })
|
||||
usernameEsolver!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'passwordEsolver', nullable: true, length: 80 })
|
||||
passwordEsolver!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'gruppoEsolver', nullable: true, length: 80 })
|
||||
gruppoEsolver!: string | null;
|
||||
|
||||
@Column('image', { name: 'logoGruppo', nullable: true })
|
||||
logoGruppo!: Buffer | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteCreazione', nullable: true })
|
||||
utenteCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataCreazione', nullable: true, length: 10 })
|
||||
dataCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraCreazione', nullable: true, length: 8 })
|
||||
oraCreazione!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteModifica', nullable: true })
|
||||
utenteModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataModifica', nullable: true, length: 10 })
|
||||
dataModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraModifica', nullable: true, length: 8 })
|
||||
oraModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'direttivaReport', nullable: true, length: 512 })
|
||||
direttivaReport!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'direttivaReportPers',
|
||||
nullable: true,
|
||||
length: 512,
|
||||
})
|
||||
direttivaReportPers!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'statoGruppo', nullable: true })
|
||||
statoGruppo!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'provinciaGruppo', nullable: true })
|
||||
provinciaGruppo!: string | null;
|
||||
|
||||
@Column('int', { name: 'fondo', nullable: true })
|
||||
fondo!: number | null;
|
||||
|
||||
@Column('decimal', {
|
||||
name: 'tassaIscrizione',
|
||||
nullable: true,
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
})
|
||||
tassaIscrizione!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codiceFiscale', nullable: true, length: 80 })
|
||||
codiceFiscale!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'serverFTP', nullable: true, length: 200 })
|
||||
serverFtp!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'usernameFTP', nullable: true, length: 200 })
|
||||
usernameFtp!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'passwordFTP', nullable: true, length: 200 })
|
||||
passwordFtp!: string | null;
|
||||
|
||||
@Column('decimal', {
|
||||
name: 'massimalePresaCarico',
|
||||
nullable: true,
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
})
|
||||
massimalePresaCarico!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'elencoLivello1', nullable: true, length: 80 })
|
||||
elencoLivello1!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'testoEmailPreventivo', nullable: true })
|
||||
testoEmailPreventivo!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'emailPreventivoMittente',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
emailPreventivoMittente!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'emailPreventivoNotifica',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
emailPreventivoNotifica!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'desPreventivoMittente',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
desPreventivoMittente!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'desPreventivoNotifica',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
desPreventivoNotifica!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceContrattoIndividuali', nullable: true })
|
||||
codiceContrattoIndividuali!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'codiceAziendaBollettini',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
codiceAziendaBollettini!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'rigaTesserino1', nullable: true, length: 80 })
|
||||
rigaTesserino1!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'rigaTesserino2', nullable: true, length: 80 })
|
||||
rigaTesserino2!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'rigaTesserino3', nullable: true, length: 80 })
|
||||
rigaTesserino3!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'cartellaCondivisa',
|
||||
nullable: true,
|
||||
length: 512,
|
||||
})
|
||||
cartellaCondivisa!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'serverSMTP', nullable: true, length: 80 })
|
||||
serverSmtp!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'usernameSMTP', nullable: true, length: 80 })
|
||||
usernameSmtp!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'passwordSMTP', nullable: true, length: 80 })
|
||||
passwordSmtp!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'emailIBAN', nullable: true, length: 255 })
|
||||
emailIban!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'emailFatture', nullable: true, length: 255 })
|
||||
emailFatture!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'emailRA', nullable: true, length: 255 })
|
||||
emailRa!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'emailAreaRiservataSoci',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
default: () => "''",
|
||||
})
|
||||
emailAreaRiservataSoci!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'desAreaRiservataSoci',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
default: () => "''",
|
||||
})
|
||||
desAreaRiservataSoci!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'usernameSMS',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
default: () => "''",
|
||||
})
|
||||
usernameSms!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'passwordSMS',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
default: () => "''",
|
||||
})
|
||||
passwordSms!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittenteSMS',
|
||||
nullable: true,
|
||||
length: 255,
|
||||
default: () => "''",
|
||||
})
|
||||
mittenteSms!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'sitoWebDati', length: 255, default: () => "''" })
|
||||
sitoWebDati!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'identificativoCreditore',
|
||||
length: 35,
|
||||
default: () => "''",
|
||||
})
|
||||
identificativoCreditore!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'SMSProtocollo',
|
||||
nullable: true,
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
smsProtocollo!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailBonifico',
|
||||
nullable: true,
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailBonifico!: string | null;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'emailBonifico',
|
||||
nullable: true,
|
||||
default: () => "''",
|
||||
})
|
||||
emailBonifico!: string | null;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'emailAssegno',
|
||||
nullable: true,
|
||||
default: () => "''",
|
||||
})
|
||||
emailAssegno!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailAssegno',
|
||||
nullable: true,
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailAssegno!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'SMSRimborsoBonifico',
|
||||
nullable: true,
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
smsRimborsoBonifico!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'SMSRimborsoAssegno',
|
||||
nullable: true,
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
smsRimborsoAssegno!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'emailPIC', nullable: true, length: 255 })
|
||||
emailPic!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'stelline', length: 10, default: () => "''" })
|
||||
stelline!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'mittentePIC', length: 400, default: () => "''" })
|
||||
mittentePic!: string;
|
||||
|
||||
@Column('ntext', { name: 'oggettoPIC', default: () => "''" })
|
||||
oggettoPic!: string;
|
||||
|
||||
@Column('ntext', { name: 'messaggioPIC', default: () => "''" })
|
||||
messaggioPic!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'nomeSupportoContrattoPosta',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
default: () => "''",
|
||||
})
|
||||
nomeSupportoContrattoPosta!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'codiceContrattoPosta',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
default: () => "''",
|
||||
})
|
||||
codiceContrattoPosta!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'passwordContrattoPosta',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
default: () => "''",
|
||||
})
|
||||
passwordContrattoPosta!: string | null;
|
||||
|
||||
@Column('bigint', {
|
||||
name: 'codiceSpedizione',
|
||||
nullable: true,
|
||||
default: () => '(0)',
|
||||
})
|
||||
codiceSpedizione!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailBonificoDomiciliato',
|
||||
nullable: true,
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailBonificoDomiciliato!: string | null;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'emailBonificoDomiciliato',
|
||||
nullable: true,
|
||||
default: () => "''",
|
||||
})
|
||||
emailBonificoDomiciliato!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'SMSRimborsoBonificoDomiciliato',
|
||||
nullable: true,
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
smsRimborsoBonificoDomiciliato!: string | null;
|
||||
|
||||
@Column('int', { name: 'notifichePush', default: () => '(0)' })
|
||||
notifichePush!: number;
|
||||
|
||||
@Column('int', { name: 'controlloCodiceFiscale', default: () => '(-1)' })
|
||||
controlloCodiceFiscale!: number;
|
||||
|
||||
@Column('ntext', { name: 'emailSuperamentoPIC', default: () => "''" })
|
||||
emailSuperamentoPic!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'SMSProtocolloNotificaEsplicita',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
smsProtocolloNotificaEsplicita!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittenteSportello',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
mittenteSportello!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailBonificoDomiciliatoSportello',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailBonificoDomiciliatoSportello!: string;
|
||||
|
||||
@Column('ntext', {
|
||||
name: 'emailBonificoDomiciliatoSportello',
|
||||
default: () => "''",
|
||||
})
|
||||
emailBonificoDomiciliatoSportello!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailBonificoSportello',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailBonificoSportello!: string;
|
||||
|
||||
@Column('ntext', { name: 'emailBonificoSportello', default: () => "''" })
|
||||
emailBonificoSportello!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailSospensioneSportello',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailSospensioneSportello!: string;
|
||||
|
||||
@Column('ntext', { name: 'emailSospensioneSportello', default: () => "''" })
|
||||
emailSospensioneSportello!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailRespingimentoSportello',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailRespingimentoSportello!: string;
|
||||
|
||||
@Column('ntext', { name: 'emailRespingimentoSportello', default: () => "''" })
|
||||
emailRespingimentoSportello!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailSospensione',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailSospensione!: string;
|
||||
|
||||
@Column('ntext', { name: 'emailSospensione', default: () => "''" })
|
||||
emailSospensione!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailRespingimento',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailRespingimento!: string;
|
||||
|
||||
@Column('ntext', { name: 'emailRespingimento', default: () => "''" })
|
||||
emailRespingimento!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittentePICdisdetta',
|
||||
nullable: true,
|
||||
length: 400,
|
||||
})
|
||||
mittentePiCdisdetta!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'oggettoPICdisdetta', nullable: true })
|
||||
oggettoPiCdisdetta!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'messaggioPICdisdetta', nullable: true })
|
||||
messaggioPiCdisdetta!: string | null;
|
||||
|
||||
@Column('int', { name: 'modalitaMassimaleBonifico', default: () => '(0)' })
|
||||
modalitaMassimaleBonifico!: number;
|
||||
|
||||
@Column('nvarchar', { name: 'portaSMTP', length: 10, default: () => "''" })
|
||||
portaSmtp!: string;
|
||||
|
||||
@Column('int', { name: 'useSSL', default: () => '(0)' })
|
||||
useSsl!: number;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'serverSMTPSpot',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
serverSmtpSpot!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'usernameSMTPSpot',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
usernameSmtpSpot!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'passwordSMTPSpot',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
passwordSmtpSpot!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'portaSMTPSpot',
|
||||
length: 10,
|
||||
default: () => "''",
|
||||
})
|
||||
portaSmtpSpot!: string;
|
||||
|
||||
@Column('int', { name: 'useSSLSpot', default: () => '(0)' })
|
||||
useSslSpot!: number;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'cartellaPubblicazioneLocale',
|
||||
length: 512,
|
||||
default: () => "''",
|
||||
})
|
||||
cartellaPubblicazioneLocale!: string;
|
||||
|
||||
@Column('int', { name: 'portaFTP', default: () => '(0)' })
|
||||
portaFtp!: number;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'cartellaAllegatiFTP',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
cartellaAllegatiFtp!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittentiEmailNotificaEmissioneRimborsoSocio',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
mittentiEmailNotificaEmissioneRimborsoSocio!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittentiEmailInvioAllegatiPraticaSocio',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
mittentiEmailInvioAllegatiPraticaSocio!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittentiEmailRichiestaDatiBancariSocio',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
mittentiEmailRichiestaDatiBancariSocio!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittentiEmailLettereRichiestaContributiRinnoviIndividuali',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
mittentiEmailLettereRichiestaContributiRinnoviIndividuali!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittentiEmailLettereSoci',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
mittentiEmailLettereSoci!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittentiEmailLettereStrutture',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
mittentiEmailLettereStrutture!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'mittentiEmailLettereContratti',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
mittentiEmailLettereContratti!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'emailNotificaCodiciFiscaliDoppiMittente',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
emailNotificaCodiciFiscaliDoppiMittente!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'emailNotificaCodiciFiscaliDoppiDestinatari',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
emailNotificaCodiciFiscaliDoppiDestinatari!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'emailNotificaCodiciFiscaliDoppiCc',
|
||||
nullable: true,
|
||||
length: 200,
|
||||
})
|
||||
emailNotificaCodiciFiscaliDoppiCc!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'oggettoEmailRichiestaDatiBancari',
|
||||
length: 200,
|
||||
default: () => "''",
|
||||
})
|
||||
oggettoEmailRichiestaDatiBancari!: string;
|
||||
|
||||
@Column('ntext', { name: 'emailRichiestaDatiBancari', default: () => "''" })
|
||||
emailRichiestaDatiBancari!: string;
|
||||
|
||||
@Column('int', {
|
||||
name: 'flagAllegaModuloIbanEmailRichiestaDatiBancari',
|
||||
nullable: true,
|
||||
})
|
||||
flagAllegaModuloIbanEmailRichiestaDatiBancari!: number | null;
|
||||
|
||||
@OneToMany(() => EnteEntity, (enteEntity) => enteEntity.gruppo)
|
||||
enti!: EnteEntity[];
|
||||
|
||||
constructor(init?: Partial<GruppoEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
export * from './API_CAP_Luoghi.entity';
|
||||
export * from './API_Luoghi.entity';
|
||||
export * from './API_Luoghi_Estero.entity';
|
||||
export * from './allegati.entity';
|
||||
export * from './contratto.entity';
|
||||
export * from './ente.entity';
|
||||
export * from './formeAssistenza.entity';
|
||||
export * from './gruppo.entity';
|
||||
export * from './missioni.entity';
|
||||
export * from './socio.entity';
|
||||
export * from './socioContratto.entity';
|
||||
export * from './socioFormeAssistenza.entity';
|
||||
export * from './sportelli.entity';
|
@ -0,0 +1,53 @@
|
||||
import { Column, Entity, Index } from 'typeorm';
|
||||
|
||||
@Index(
|
||||
'PK_Missioni_Data',
|
||||
[
|
||||
'codiceFiscale',
|
||||
'tipoDocumento',
|
||||
'idMissione',
|
||||
'idLettera',
|
||||
'idPratica',
|
||||
'idAgenzia',
|
||||
'dataInizio',
|
||||
'dataFine',
|
||||
'tipoContratto',
|
||||
],
|
||||
{ unique: true }
|
||||
)
|
||||
@Entity('missioni')
|
||||
export class MissioniEntity {
|
||||
@Column('nvarchar', { primary: true, name: 'codiceFiscale', length: 20 })
|
||||
codiceFiscale!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'tipoDocumento' })
|
||||
tipoDocumento!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'idMissione' })
|
||||
idMissione!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'idLettera' })
|
||||
idLettera!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'idPratica' })
|
||||
idPratica!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'idAgenzia' })
|
||||
idAgenzia!: string;
|
||||
|
||||
@Column('nvarchar', { primary: true, name: 'dataInizio', length: 10 })
|
||||
dataInizio!: string;
|
||||
|
||||
@Column('nvarchar', { primary: true, name: 'dataFine', length: 10 })
|
||||
dataFine!: string;
|
||||
|
||||
@Column('nvarchar', { primary: true, name: 'tipoContratto', length: 20 })
|
||||
tipoContratto!: string;
|
||||
|
||||
@Column('bigint', { name: 'progressivoRecord', default: () => '(0)' })
|
||||
progressivoRecord!: string;
|
||||
|
||||
constructor(init?: Partial<MissioniEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,651 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { ApiLuoghiEntity } from './API_Luoghi.entity';
|
||||
import { GruppoEntity } from './gruppo.entity';
|
||||
import { SocioContrattoEntity } from './socioContratto.entity';
|
||||
import { SocioFormeAssistenzaEntity } from './socioFormeAssistenza.entity';
|
||||
|
||||
@Index('PK_socio', ['codiceSocio'], { unique: true })
|
||||
@Entity('socio')
|
||||
export class SocioEntity {
|
||||
@Column('bigint', { name: 'codiceGruppo', nullable: true })
|
||||
codiceGruppo!: string | null;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'codiceSocio' })
|
||||
codiceSocio!: string;
|
||||
|
||||
@Column('bigint', { name: 'matricolaSocio', nullable: true })
|
||||
matricolaSocio!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'cognome', nullable: true, length: 80 })
|
||||
cognome!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'nome', nullable: true, length: 80 })
|
||||
nome!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataNascita', nullable: true, length: 10 })
|
||||
dataNascita!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codiceFiscale', nullable: true, length: 20 })
|
||||
codiceFiscale!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceContrattoOld', nullable: true })
|
||||
codiceContrattoOld!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'socio.codiceFiguraContrattoOld', nullable: true })
|
||||
socioCodiceFiguraContrattoOld!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceRivenditore', nullable: true })
|
||||
codiceRivenditore!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteCreazione', nullable: true })
|
||||
utenteCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataCreazione', nullable: true, length: 10 })
|
||||
dataCreazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraCreazione', nullable: true, length: 8 })
|
||||
oraCreazione!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'utenteModifica', nullable: true })
|
||||
utenteModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataModifica', nullable: true, length: 10 })
|
||||
dataModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'oraModifica', nullable: true, length: 8 })
|
||||
oraModifica!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'residenzaIndirizzo',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
residenzaIndirizzo!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'residenzaNumeroCivico',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
residenzaNumeroCivico!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'residenzaLocalita', nullable: true, length: 80 })
|
||||
residenzaLocalita!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'residenzaCAP', nullable: true, length: 10 })
|
||||
residenzaCap!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'residenzaProvincia', nullable: true })
|
||||
residenzaProvincia!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'residenzaStato', nullable: true })
|
||||
residenzaStato!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'domicilioIndirizzo',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
domicilioIndirizzo!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'domicilioNumeroCivico',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
domicilioNumeroCivico!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'domicilioLocalita', nullable: true, length: 80 })
|
||||
domicilioLocalita!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'domicilioCAP', nullable: true, length: 10 })
|
||||
domicilioCap!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'domicilioProvincia', nullable: true })
|
||||
domicilioProvincia!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'domicilioStato', nullable: true })
|
||||
domicilioStato!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'nascitaLocalita', nullable: true, length: 80 })
|
||||
nascitaLocalita!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'nascitaCAP', nullable: true, length: 10 })
|
||||
nascitaCap!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'nascitaProvincia', nullable: true })
|
||||
nascitaProvincia!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'nascitaStato', nullable: true })
|
||||
nascitaStato!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'telefono', nullable: true, length: 80 })
|
||||
telefono!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'cellulare', nullable: true, length: 80 })
|
||||
cellulare!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'email', nullable: true, length: 80 })
|
||||
email!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceSesso', nullable: true })
|
||||
codiceSesso!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceStatoCivile', nullable: true })
|
||||
codiceStatoCivile!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceProfessione', nullable: true })
|
||||
codiceProfessione!: string | null;
|
||||
|
||||
@Column('int', { name: 'consensoComunicazioneDati', nullable: true })
|
||||
consensoComunicazioneDati!: number | null;
|
||||
|
||||
@Column('int', { name: 'consensoDiffusioneDati', nullable: true })
|
||||
consensoDiffusioneDati!: number | null;
|
||||
|
||||
@Column('int', { name: 'riassicurato', nullable: true })
|
||||
riassicurato!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'fax', nullable: true, length: 80 })
|
||||
fax!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataIscrizione', nullable: true, length: 10 })
|
||||
dataIscrizione!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataRichiestaRecesso',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataRichiestaRecesso!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataRecesso', nullable: true, length: 10 })
|
||||
dataRecesso!: string | null;
|
||||
|
||||
@Column('int', { name: 'recessoAnnoSolareSuccessivo', nullable: true })
|
||||
recessoAnnoSolareSuccessivo!: number | null;
|
||||
|
||||
@Column('int', { name: 'capofamiglia', nullable: true })
|
||||
flagCapofamiglia!: number | null;
|
||||
|
||||
@Column('bigint', { name: 'livelloFamiliare', nullable: true })
|
||||
livelloFamiliare!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceCapofamiglia', nullable: true })
|
||||
codiceCapofamiglia!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codicePaese', nullable: true, length: 50 })
|
||||
codicePaese!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codiceCIN', nullable: true, length: 50 })
|
||||
codiceCin!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'checkDigitCIN', nullable: true, length: 50 })
|
||||
checkDigitCin!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'rifBancaEstero', nullable: true, length: 50 })
|
||||
rifBancaEstero!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'contoCorrente', nullable: true, length: 50 })
|
||||
contoCorrente!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codiceBIC', nullable: true, length: 50 })
|
||||
codiceBic!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codiceIBAN', nullable: true, length: 50 })
|
||||
codiceIban!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codiceABI', nullable: true, length: 50 })
|
||||
codiceAbi!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'codiceCAB', nullable: true, length: 10 })
|
||||
codiceCab!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataDecesso', nullable: true, length: 10 })
|
||||
dataDecesso!: string | null;
|
||||
|
||||
@Column('int', { name: 'modalitaSuddivisioneContributi', nullable: true })
|
||||
modalitaSuddivisioneContributi!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataEsclusione', nullable: true, length: 10 })
|
||||
dataEsclusione!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceMotivoEsclusione', nullable: true })
|
||||
codiceMotivoEsclusione!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'noteEsclusione', nullable: true })
|
||||
noteEsclusione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'usernameWEB', nullable: true, length: 80 })
|
||||
usernameWeb!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'passwordWEB', nullable: true, length: 80 })
|
||||
passwordWeb!: string | null;
|
||||
|
||||
@Column('int', { name: 'consensoNucleoFamiliare', nullable: true })
|
||||
consensoNucleoFamiliare!: number | null;
|
||||
|
||||
@Column('int', { name: 'webAccessoDisabilitato', nullable: true })
|
||||
webAccessoDisabilitato!: number | null;
|
||||
|
||||
@Column('int', { name: 'webModificaDati', nullable: true })
|
||||
webModificaDati!: number | null;
|
||||
|
||||
@Column('int', { name: 'webInfo', nullable: true })
|
||||
webInfo!: number | null;
|
||||
|
||||
@Column('int', { name: 'webStrutture', nullable: true })
|
||||
webStrutture!: number | null;
|
||||
|
||||
@Column('int', { name: 'webPratiche', nullable: true })
|
||||
webPratiche!: number | null;
|
||||
|
||||
@Column('int', { name: 'webCertificazione', nullable: true })
|
||||
webCertificazione!: number | null;
|
||||
|
||||
@Column('int', { name: 'webRimborsiBase', nullable: true })
|
||||
webRimborsiBase!: number | null;
|
||||
|
||||
@Column('int', { name: 'webRimborsiAvanzato', nullable: true })
|
||||
webRimborsiAvanzato!: number | null;
|
||||
|
||||
@Column('int', { name: 'webRichiestaPresaCarico', nullable: true })
|
||||
webRichiestaPresaCarico!: number | null;
|
||||
|
||||
@Column('int', { name: 'webServizioCup', nullable: true })
|
||||
webServizioCup!: number | null;
|
||||
|
||||
@Column('int', { name: 'webEmailUsername', nullable: true })
|
||||
webEmailUsername!: number | null;
|
||||
|
||||
@Column('bigint', { name: 'categoria1', nullable: true })
|
||||
categoria1!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'categoria2', nullable: true })
|
||||
categoria2!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'categoria3', nullable: true })
|
||||
categoria3!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'categoria4', nullable: true })
|
||||
categoria4!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'categoria5', nullable: true })
|
||||
categoria5!: string | null;
|
||||
|
||||
@Column('int', { name: 'socioEsterno', nullable: true })
|
||||
socioEsterno!: number | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceMutua', nullable: true })
|
||||
codiceMutua!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataInizioValidita',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataInizioValidita!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataFineValidita', nullable: true, length: 10 })
|
||||
dataFineValidita!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'idAssiBase', nullable: true })
|
||||
idAssiBase!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'protezioniAssiBase',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
protezioniAssiBase!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'gruppoAssiBase', nullable: true, length: 80 })
|
||||
gruppoAssiBase!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'noteAnagrafica', nullable: true })
|
||||
noteAnagrafica!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'tipoSocio', nullable: true })
|
||||
tipoSocio!: string | null;
|
||||
|
||||
@Column('int', { name: 'stampatoLibroSoci', default: () => '(0)' })
|
||||
stampatoLibroSoci!: number;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataStampaLibroSoci',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataStampaLibroSoci!: string | null;
|
||||
|
||||
@Column('int', { name: 'codiceModalitaPagamentoRimborsi', nullable: true })
|
||||
codiceModalitaPagamentoRimborsi!: number | null;
|
||||
|
||||
@Column('int', { name: 'codiceModalitaVersamentoContributi', nullable: true })
|
||||
codiceModalitaVersamentoContributi!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataAssunzione', nullable: true, length: 10 })
|
||||
dataAssunzione!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceMotivoRecesso', nullable: true })
|
||||
codiceMotivoRecesso!: string | null;
|
||||
|
||||
@Column('int', { name: 'codiceCanaleComunicazione', nullable: true })
|
||||
codiceCanaleComunicazione!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataRegistrazione', nullable: true, length: 10 })
|
||||
dataRegistrazione!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'noteAnamnesi', nullable: true })
|
||||
noteAnamnesi!: string | null;
|
||||
|
||||
@Column('bigint', {
|
||||
name: 'codiceModalitacessazioneContributiInfrannuale',
|
||||
nullable: true,
|
||||
})
|
||||
codiceModalitacessazioneContributiInfrannuale!: string | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'forzaCodiceModalitacessazioneContributiInfrannuale',
|
||||
nullable: true,
|
||||
})
|
||||
forzaCodiceModalitacessazioneContributiInfrannuale!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'matricolaAziendale',
|
||||
nullable: true,
|
||||
length: 80,
|
||||
})
|
||||
matricolaAziendale!: string | null;
|
||||
|
||||
@Column('int', { name: 'coniugeCarico', nullable: true })
|
||||
coniugeCarico!: number | null;
|
||||
|
||||
@Column('ntext', { name: 'noteProtezioni', nullable: true })
|
||||
noteProtezioni!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'idNucleo', nullable: true })
|
||||
idNucleo!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'idSocio', nullable: true })
|
||||
idSocio!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'idLibroSoci', nullable: true })
|
||||
idLibroSoci!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'idPersona', nullable: true })
|
||||
idPersona!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codicePromoter', nullable: true })
|
||||
codicePromoter!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'originePromoter', nullable: true })
|
||||
originePromoter!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'livelloFamiliareAnagrafica', nullable: true })
|
||||
livelloFamiliareAnagrafica!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceCapoFamigliaAnagrafica', nullable: true })
|
||||
codiceCapoFamigliaAnagrafica!: string | null;
|
||||
|
||||
@Column('int', { name: 'codiceModalitaVersamentoRID', nullable: true })
|
||||
codiceModalitaVersamentoRid!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataPossibileAmmissione',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataPossibileAmmissione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'banca', nullable: true, length: 255 })
|
||||
banca!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'agenziaBanca', nullable: true, length: 255 })
|
||||
agenziaBanca!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'intestazioneCC', nullable: true, length: 255 })
|
||||
intestazioneCc!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataRicezioneRichiestaRecesso',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
dataRicezioneRichiestaRecesso!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataUscitaNucleo', nullable: true, length: 10 })
|
||||
dataUscitaNucleo!: string | null;
|
||||
|
||||
@Column('int', { name: 'datiBancariDaAggiornare', nullable: true })
|
||||
datiBancariDaAggiornare!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'telefono2', nullable: true, length: 80 })
|
||||
telefono2!: string | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataModificaIban',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
default: () => "''",
|
||||
})
|
||||
dataModificaIban!: string | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'richiestoIBAN',
|
||||
nullable: true,
|
||||
default: () => '(0)',
|
||||
})
|
||||
richiestoIban!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataRichiestaIBAN',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
default: () => "''",
|
||||
})
|
||||
dataRichiestaIban!: string | null;
|
||||
|
||||
@Column('int', { name: 'comunicazioniViaEmail', nullable: true })
|
||||
comunicazioniViaEmail!: number | null;
|
||||
|
||||
@Column('int', { name: 'esitoUltimaValidazione', nullable: true })
|
||||
esitoUltimaValidazione!: number | null;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataOraUltimaValidazione',
|
||||
nullable: true,
|
||||
length: 50,
|
||||
})
|
||||
dataOraUltimaValidazione!: string | null;
|
||||
|
||||
@Column('ntext', { name: 'noteUltimaValidazione', nullable: true })
|
||||
noteUltimaValidazione!: string | null;
|
||||
|
||||
@Column('int', { name: 'stampareLibroSoci', default: () => '(0)' })
|
||||
stampareLibroSoci!: number;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataStampaCessazioneLibroSoci',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
default: () => "'9998-12-31'",
|
||||
})
|
||||
dataStampaCessazioneLibroSoci!: string | null;
|
||||
|
||||
@Column('int', {
|
||||
name: 'stampataCessazioneLibroSoci',
|
||||
nullable: true,
|
||||
default: () => '(0)',
|
||||
})
|
||||
stampataCessazioneLibroSoci!: number | null;
|
||||
|
||||
@Column('int', { name: 'adesioneWeb', default: () => '(0)' })
|
||||
adesioneWeb!: number;
|
||||
|
||||
@Column('int', { name: 'preeesistenzaContratto', default: () => '(0)' })
|
||||
preeesistenzaContratto!: number;
|
||||
|
||||
@Column('int', { name: 'preeesistenzaInclusa', default: () => '(0)' })
|
||||
preeesistenzaInclusa!: number;
|
||||
|
||||
@Column('nvarchar', { name: 'IBANRid', length: 50, default: () => "''" })
|
||||
ibanRid!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'intestatarioContoRid',
|
||||
length: 255,
|
||||
default: () => "''",
|
||||
})
|
||||
intestatarioContoRid!: string;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'dataMandato',
|
||||
length: 10,
|
||||
default: () => "'9998-12-31'",
|
||||
})
|
||||
dataMandato!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'idMandato', length: 10, default: () => "''" })
|
||||
idMandato!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'codiceSWIFT', length: 80, default: () => "''" })
|
||||
codiceSwift!: string;
|
||||
|
||||
@Column('decimal', {
|
||||
name: 'percentualeFamiliareACarico',
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
default: () => '(0)',
|
||||
})
|
||||
percentualeFamiliareACarico!: number;
|
||||
|
||||
@Column('int', { name: 'familiareMultiplo', default: () => '(0)' })
|
||||
familiareMultiplo!: number;
|
||||
|
||||
@Column('nvarchar', {
|
||||
name: 'origineAggiornamento',
|
||||
length: 20,
|
||||
default: () => "''",
|
||||
})
|
||||
origineAggiornamento!: string;
|
||||
|
||||
@Column('int', { name: 'consensoNewsletter', default: () => '(0)' })
|
||||
consensoNewsletter!: number;
|
||||
|
||||
@Column('int', {
|
||||
name: 'flagRichiestaVariazioneAnagrafica',
|
||||
default: () => '(0)',
|
||||
})
|
||||
flagRichiestaVariazioneAnagrafica!: number;
|
||||
|
||||
@Column('int', { name: 'flagPresenzaMorositaPrestiti', default: () => '(0)' })
|
||||
flagPresenzaMorositaPrestiti!: number;
|
||||
|
||||
@Column('int', { name: 'flagBloccoAmministrativo', default: () => '(0)' })
|
||||
flagBloccoAmministrativo!: number;
|
||||
|
||||
@Column('int', { name: 'codiceTitoloStudio', default: () => '(0)' })
|
||||
codiceTitoloStudio!: number;
|
||||
|
||||
@Column('varchar', {
|
||||
name: 'codiceLuogoDomicilio',
|
||||
nullable: true,
|
||||
length: 5,
|
||||
})
|
||||
codiceLuogoDomicilio!: string | null;
|
||||
|
||||
@Column('varchar', { name: 'codiceLuogoNascita', nullable: true, length: 5 })
|
||||
codiceLuogoNascita!: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
name: 'codiceLuogoResidenza',
|
||||
nullable: true,
|
||||
length: 5,
|
||||
})
|
||||
codiceLuogoResidenza!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'domicilioFrazione', nullable: true, length: 80 })
|
||||
domicilioFrazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'nascitaFrazione', nullable: true, length: 80 })
|
||||
nascitaFrazione!: string | null;
|
||||
|
||||
@Column('nvarchar', { name: 'residenzaFrazione', nullable: true, length: 80 })
|
||||
residenzaFrazione!: string | null;
|
||||
|
||||
@Column('varchar', { name: 'codicePartner', nullable: true, length: 255 })
|
||||
codicePartner!: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
name: 'documentoIdentitaCodice',
|
||||
nullable: true,
|
||||
length: 100,
|
||||
})
|
||||
documentoIdentitaCodice!: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
name: 'documentoIdentitaDataEmissione',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
documentoIdentitaDataEmissione!: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
name: 'documentoIdentitaDataScadenza',
|
||||
nullable: true,
|
||||
length: 10,
|
||||
})
|
||||
documentoIdentitaDataScadenza!: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
name: 'documentoIdentitaEnteRilascio',
|
||||
nullable: true,
|
||||
length: 100,
|
||||
})
|
||||
documentoIdentitaEnteRilascio!: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
name: 'documentoIdentitaComuneRilascio',
|
||||
nullable: true,
|
||||
length: 5,
|
||||
})
|
||||
documentoIdentitaCodiceLuogoComuneRilascio!: string | null;
|
||||
|
||||
@ManyToOne(() => SocioEntity, (socioEntity) => socioEntity.familiari)
|
||||
@JoinColumn([{ name: 'codiceCapofamiglia', referencedColumnName: 'codiceSocio' }])
|
||||
capofamiglia!: SocioEntity;
|
||||
|
||||
@OneToMany(() => SocioEntity, (socioEntity) => socioEntity.capofamiglia)
|
||||
familiari!: SocioEntity[];
|
||||
|
||||
@ManyToOne(() => GruppoEntity)
|
||||
@JoinColumn([{ name: 'codiceGruppo', referencedColumnName: 'codiceGruppo' }])
|
||||
gruppo!: GruppoEntity;
|
||||
|
||||
@ManyToOne(() => ApiLuoghiEntity)
|
||||
@JoinColumn([{ name: 'codiceLuogoNascita', referencedColumnName: 'codice' }])
|
||||
luogoNascita!: ApiLuoghiEntity;
|
||||
|
||||
@ManyToOne(() => ApiLuoghiEntity)
|
||||
@JoinColumn([{ name: 'codiceLuogoResidenza', referencedColumnName: 'codice' }])
|
||||
luogoResidenza!: ApiLuoghiEntity;
|
||||
|
||||
@ManyToOne(() => ApiLuoghiEntity)
|
||||
@JoinColumn([{ name: 'codiceLuogoDomicilio', referencedColumnName: 'codice' }])
|
||||
luogoDomicilio!: ApiLuoghiEntity;
|
||||
|
||||
@ManyToOne(() => ApiLuoghiEntity)
|
||||
@JoinColumn([{ name: 'documentoIdentitaComuneRilascio', referencedColumnName: 'codice' }])
|
||||
documentoIdentitaComuneRilascio!: ApiLuoghiEntity;
|
||||
|
||||
@OneToMany(() => SocioContrattoEntity, (socioContrattoEntity) => socioContrattoEntity.socio)
|
||||
socioContratto!: SocioContrattoEntity[];
|
||||
|
||||
@OneToMany(() => SocioFormeAssistenzaEntity, (socioFormeAssistenzaEntity) => socioFormeAssistenzaEntity.socio)
|
||||
socioFormeAssistenzas!: SocioFormeAssistenzaEntity[];
|
||||
|
||||
constructor(init?: Partial<SocioEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { ContrattoEntity } from './contratto.entity';
|
||||
import { SocioEntity } from './socio.entity';
|
||||
|
||||
@Index(
|
||||
'PK_socioContratto',
|
||||
['codiceSocio', 'codiceCapofamiglia', 'codiceContratto', 'dataInizio', 'dataFine', 'codiceFiguraContratto'],
|
||||
{ unique: true }
|
||||
)
|
||||
@Entity('socioContratto')
|
||||
export class SocioContrattoEntity {
|
||||
@Column('bigint', { primary: true, name: 'codiceSocio' })
|
||||
codiceSocio!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'codiceCapofamiglia' })
|
||||
codiceCapofamiglia!: string;
|
||||
|
||||
@Column('nvarchar', { primary: true, name: 'dataInizio', length: 10 })
|
||||
dataInizio!: string;
|
||||
|
||||
@Column('nvarchar', { primary: true, name: 'dataFine', length: 10 })
|
||||
dataFine!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'codiceContratto' })
|
||||
codiceContratto!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'contratto', length: 400 })
|
||||
nomeContratto!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'codiceFiguraContratto' })
|
||||
codiceFiguraContratto!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'figuraContratto', length: 400 })
|
||||
figuraContratto!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'note', length: 400 })
|
||||
note!: string;
|
||||
|
||||
@ManyToOne(() => SocioEntity, (socioEntity) => socioEntity.socioContratto)
|
||||
@JoinColumn([{ name: 'codiceSocio', referencedColumnName: 'codiceSocio' }])
|
||||
socio!: SocioEntity;
|
||||
|
||||
@ManyToOne(() => ContrattoEntity, (contrattoEntity) => contrattoEntity.socioContratto)
|
||||
@JoinColumn([{ name: 'codiceContratto', referencedColumnName: 'codiceContratto' }])
|
||||
contratto!: ContrattoEntity;
|
||||
|
||||
constructor(init?: Partial<SocioContrattoEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { FormeAssistenzaEntity } from './formeAssistenza.entity';
|
||||
import { SocioEntity } from './socio.entity';
|
||||
|
||||
@Index('PK_socioFormeAssistenza', ['codiceSocio', 'codiceFdA', 'dataInizio', 'dataFine', 'titolare'], { unique: true })
|
||||
@Entity('socioFormeAssistenza')
|
||||
export class SocioFormeAssistenzaEntity {
|
||||
@Column('bigint', { primary: true, name: 'codiceSocio' })
|
||||
codiceSocio!: string;
|
||||
|
||||
@Column('bigint', { primary: true, name: 'codiceFdA' })
|
||||
codiceFdA!: string;
|
||||
|
||||
@Column('nvarchar', { primary: true, name: 'dataInizio', length: 10 })
|
||||
dataInizio!: string;
|
||||
|
||||
@Column('nvarchar', { primary: true, name: 'dataFine', length: 10 })
|
||||
dataFine!: string;
|
||||
|
||||
@Column('int', { primary: true, name: 'titolare' })
|
||||
titolare!: number;
|
||||
|
||||
@Column('bigint', { name: 'codiceContratto', nullable: true })
|
||||
codiceContratto!: string | null;
|
||||
|
||||
@Column('bigint', { name: 'codiceFiguraContratto', nullable: true })
|
||||
codiceFiguraContratto!: string | null;
|
||||
|
||||
@Column('int', { name: 'forzaEtaContributi', nullable: true })
|
||||
forzaEtaContributi!: number | null;
|
||||
|
||||
@Column('nvarchar', { name: 'dataRicezione', nullable: true, length: 10 })
|
||||
dataRicezione!: string | null;
|
||||
|
||||
@ManyToOne(() => FormeAssistenzaEntity, (formeAssistenzaEntity) => formeAssistenzaEntity.socioFormeAssistenza)
|
||||
@JoinColumn([{ name: 'codiceFdA', referencedColumnName: 'codiceFda' }])
|
||||
formaAssistenza!: FormeAssistenzaEntity;
|
||||
|
||||
@ManyToOne(() => SocioEntity, (socioEntity) => socioEntity.socioFormeAssistenzas)
|
||||
@JoinColumn([{ name: 'codiceSocio', referencedColumnName: 'codiceSocio' }])
|
||||
socio!: SocioEntity;
|
||||
|
||||
constructor(init?: Partial<SocioFormeAssistenzaEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { Column, Entity, Index } from 'typeorm';
|
||||
|
||||
@Index('PK_sportelli', ['codiceSportello'], { unique: true })
|
||||
@Entity('sportelli')
|
||||
export class SportelliEntity {
|
||||
@Column('nvarchar', { primary: true, name: 'codiceSportello', length: 255 })
|
||||
codiceSportello!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'denominazione', length: 255 })
|
||||
denominazione!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'email', length: 255 })
|
||||
email!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'password', length: 255 })
|
||||
password!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'indirizzo', length: 200, default: () => "''" })
|
||||
indirizzo!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'citta', length: 200, default: () => "''" })
|
||||
citta!: string;
|
||||
|
||||
@Column('nvarchar', { name: 'provincia', length: 2, default: () => "''" })
|
||||
provincia!: string;
|
||||
|
||||
constructor(init?: Partial<SportelliEntity>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export * from './entities';
|
@ -0,0 +1 @@
|
||||
export const APP_DATASOURCES = Symbol('APP_DATASOURCES');
|
20
apps/ebitemp-api/src/modules/database/database.module.ts
Normal file
20
apps/ebitemp-api/src/modules/database/database.module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { EbitempApiDatabaseModule } from './connections/ebitemp-api/database.module';
|
||||
import { OceanoDatabaseModule } from './connections/oceano/database.module';
|
||||
import { APP_DATASOURCES } from './database.constants';
|
||||
import { dataSources } from './utils/typeorm-data-source-factory';
|
||||
|
||||
const dataSourcesProvider = {
|
||||
provide: APP_DATASOURCES,
|
||||
useValue: dataSources,
|
||||
};
|
||||
|
||||
const databaseModules = [EbitempApiDatabaseModule, OceanoDatabaseModule];
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [...databaseModules],
|
||||
providers: [dataSourcesProvider],
|
||||
exports: [dataSourcesProvider, ...databaseModules],
|
||||
})
|
||||
export class AppDatabaseModule {}
|
@ -0,0 +1,57 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import { ConnectionString } from 'connection-string';
|
||||
import { first } from 'lodash';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const databaseSchema = z.object({
|
||||
connectionString: z.string(),
|
||||
type: z.enum([
|
||||
'mysql',
|
||||
'postgres',
|
||||
'cockroachdb',
|
||||
'sap',
|
||||
'mariadb',
|
||||
'sqlite',
|
||||
'cordova',
|
||||
'react-native',
|
||||
'nativescript',
|
||||
'sqljs',
|
||||
'oracle',
|
||||
'mssql',
|
||||
'mongodb',
|
||||
'aurora-mysql',
|
||||
'aurora-postgres',
|
||||
'expo',
|
||||
'better-sqlite3',
|
||||
'capacitor',
|
||||
'spanner',
|
||||
]),
|
||||
host: z.string(),
|
||||
port: z.number().optional(),
|
||||
username: z.string(),
|
||||
password: z.string(),
|
||||
database: z.string(),
|
||||
secure: z.boolean(),
|
||||
});
|
||||
export type DatabaseConfig = z.TypeOf<typeof databaseSchema>;
|
||||
|
||||
export const rawDatabaseSchema = z.object({
|
||||
connectionString: z.string(),
|
||||
secure: z.boolean().default(true),
|
||||
});
|
||||
export type RawDatabaseConfigSchema = z.TypeOf<typeof rawDatabaseSchema>;
|
||||
|
||||
export const databaseConfigFactory = (opts: RawDatabaseConfigSchema) => registerAs('database', () => {
|
||||
const connectionString = new ConnectionString(opts.connectionString);
|
||||
const config: DatabaseConfig = databaseSchema.strict().parse({
|
||||
connectionString: connectionString.toString(),
|
||||
type: connectionString.protocol,
|
||||
host: first(connectionString.hosts)?.name,
|
||||
port: first(connectionString.hosts)?.port,
|
||||
username: connectionString.user,
|
||||
password: connectionString.password,
|
||||
database: first(connectionString.path),
|
||||
secure: opts.secure,
|
||||
});
|
||||
return config;
|
||||
});
|
@ -0,0 +1,17 @@
|
||||
import { DataSource, DataSourceOptions } from 'typeorm';
|
||||
|
||||
export const dataSources: DataSource[] = [];
|
||||
|
||||
export const typeormDataSourceFactory = (dataSources: DataSource[]) => async (options?: DataSourceOptions) => {
|
||||
const dataSource = await new DataSource(options!).initialize();
|
||||
dataSources.push(dataSource);
|
||||
return dataSource;
|
||||
};
|
||||
|
||||
export const typeormTransactionalDataSourceFactory =
|
||||
(name?: string) => async (options?: DataSourceOptions) => {
|
||||
const tt = await import('typeorm-transactional');
|
||||
const dataSource = tt.addTransactionalDataSource({ name: name, dataSource: new DataSource(options!) });
|
||||
dataSources.push(dataSource);
|
||||
return dataSource;
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
export const typeormEntitiesFromImport = async <T extends object>(entities: T) => {
|
||||
return (Object.keys(entities) as Array<keyof typeof entities>).map(
|
||||
(entity: keyof typeof entities) => entities[entity]
|
||||
);
|
||||
};
|
@ -0,0 +1,26 @@
|
||||
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
||||
import { DatabaseConfig } from './database-config';
|
||||
|
||||
export const typeormModuleOptionsFactory = async (
|
||||
databaseConfig: DatabaseConfig,
|
||||
entities: any[],
|
||||
name?: string
|
||||
): Promise<TypeOrmModuleOptions> => {
|
||||
return {
|
||||
name: name,
|
||||
type: databaseConfig.type as any,
|
||||
host: databaseConfig.host,
|
||||
port: databaseConfig.port,
|
||||
username: databaseConfig.username,
|
||||
password: databaseConfig.password,
|
||||
database: databaseConfig.database,
|
||||
entities: entities,
|
||||
synchronize: false,
|
||||
logging: process.env['NODE_ENV'] !== 'production',
|
||||
namingStrategy: new SnakeNamingStrategy(),
|
||||
options: {
|
||||
...(!databaseConfig.secure ? { trustServerCertificate: true } : {}),
|
||||
},
|
||||
};
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
|
||||
export async function patchTypeOrm() {
|
||||
(await import('typeorm-transactional')).initializeTransactionalContext();
|
||||
(await import('typeorm-scoped')).patchSelectQueryBuilder();
|
||||
};
|
@ -0,0 +1,105 @@
|
||||
import { Inject, Injectable, OnApplicationBootstrap } from '@nestjs/common';
|
||||
import { differenceBy, get } from 'lodash';
|
||||
import { DataSource, QueryFailedError } from 'typeorm';
|
||||
import { APP_DATASOURCES } from '../database/database.constants';
|
||||
import { Enumify, registeredEnums } from './enumify';
|
||||
import { EnumifyConfig, enumifyConfig } from './enumify.config';
|
||||
|
||||
@Injectable()
|
||||
export class EnumifyUpdateFromDatabaseService implements OnApplicationBootstrap {
|
||||
constructor(
|
||||
@Inject(APP_DATASOURCES) private readonly datasources: DataSource[],
|
||||
@Inject(enumifyConfig.KEY) private readonly config: EnumifyConfig
|
||||
) {}
|
||||
|
||||
async onApplicationBootstrap() {
|
||||
try {
|
||||
const enumUpdateFromDbOnStart = this.config.shouldUpdateEnumFromDbOnStartup;
|
||||
if (!enumUpdateFromDbOnStart) return;
|
||||
|
||||
const errors = [];
|
||||
|
||||
for (const dataSource of this.datasources) {
|
||||
const logging = dataSource.options.logging;
|
||||
dataSource.setOptions({ logging: false });
|
||||
for (const _registeredEnum of get(registeredEnums, dataSource.name, [])) {
|
||||
const registeredEnum = _registeredEnum as typeof Enumify;
|
||||
|
||||
const repo = dataSource.getRepository(registeredEnum);
|
||||
|
||||
const enumValues = registeredEnum.enumValues;
|
||||
let dbValues: Enumify[];
|
||||
try {
|
||||
dbValues = await repo.find();
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof QueryFailedError &&
|
||||
err.message === `Error: Invalid object name '${repo.metadata.tableName}'.`
|
||||
) {
|
||||
errors.push(
|
||||
`[${dataSource.name}] ${registeredEnum.name}: Table present in code but missing on database: ${enumValues}`
|
||||
);
|
||||
}
|
||||
if (err instanceof QueryFailedError && err.message.startsWith('Error: Invalid column name')) {
|
||||
errors.push(`[${dataSource.name}] ${registeredEnum.name}: [${repo.metadata.tableName}] ${err.message}`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const differenceByDbValues = differenceBy(dbValues, enumValues, (x) => (x.id, x.nome));
|
||||
const differenceByEnumValues = differenceBy(enumValues, dbValues, (x) => (x.id, x.nome));
|
||||
if (differenceByDbValues.length > 0) {
|
||||
errors.push(
|
||||
`[${dataSource.name}] ${
|
||||
registeredEnum.name
|
||||
}: Values present on database but missing in code: ${differenceBy(
|
||||
dbValues,
|
||||
enumValues,
|
||||
(x) => (x.id, x.nome)
|
||||
)}`
|
||||
);
|
||||
}
|
||||
if (differenceByEnumValues.length > 0) {
|
||||
errors.push(
|
||||
`[${dataSource.name}] ${
|
||||
registeredEnum.name
|
||||
}: Values present in code but missing in database: ${differenceBy(
|
||||
enumValues,
|
||||
dbValues,
|
||||
(x) => (x.id, x.nome)
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
for (const dbValue of dbValues) {
|
||||
const valueOfByName = registeredEnum.fromKey(dbValue.nome!);
|
||||
const keyOfByCode = registeredEnum.fromValue(dbValue.id!);
|
||||
if (valueOfByName != null && dbValue.id != valueOfByName?.id) {
|
||||
errors.push(
|
||||
`[${dataSource.name}] ${registeredEnum.name}: Different values between database (${dbValue.id}, ${dbValue.nome}) and code (${valueOfByName.id}, ${valueOfByName.nome})`
|
||||
);
|
||||
} else if (keyOfByCode != null && dbValue.nome != keyOfByCode?.nome) {
|
||||
errors.push(
|
||||
`[${dataSource.name}] ${registeredEnum.name}: Different values between database (${dbValue.id}, ${dbValue.nome}) and code (${keyOfByCode.id}, ${keyOfByCode.nome})`
|
||||
);
|
||||
} else if (valueOfByName != null || keyOfByCode != null) {
|
||||
const enumValue = (valueOfByName ?? keyOfByCode)!;
|
||||
Object.assign(enumValue, dbValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
dataSource.setOptions({ logging: logging });
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
throw new Error(errors.join('\n\t* '));
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
console.warn(err.message, EnumifyUpdateFromDatabaseService.name);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
apps/ebitemp-api/src/modules/enumify/enumify.config.ts
Normal file
17
apps/ebitemp-api/src/modules/enumify/enumify.config.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import coerceRecordTypes from '../config/utils/coerce-record-types';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const enumifySchema = z.object({
|
||||
shouldUpdateEnumFromDbOnStartup: z.boolean().default(true),
|
||||
});
|
||||
export type EnumifyConfig = z.infer<typeof enumifySchema>;
|
||||
|
||||
export const enumifyConfig = registerAs('enumify', () => {
|
||||
const env = coerceRecordTypes(process.env);
|
||||
|
||||
const config: EnumifyConfig = enumifySchema.strict().parse({
|
||||
shouldUpdateEnumFromDbOnStartup: env['ENUM_UPDATE_FROM_DB_ON_START']
|
||||
});
|
||||
return config;
|
||||
});
|
12
apps/ebitemp-api/src/modules/enumify/enumify.module.ts
Normal file
12
apps/ebitemp-api/src/modules/enumify/enumify.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Module, Global } from '@nestjs/common';
|
||||
import { EnumifyUpdateFromDatabaseService } from './enumify-update-from-database.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { enumifyConfig } from './enumify.config';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [ConfigModule.forFeature(enumifyConfig)],
|
||||
providers: [EnumifyUpdateFromDatabaseService],
|
||||
exports: [EnumifyUpdateFromDatabaseService],
|
||||
})
|
||||
export class EnumifyModule {}
|
74
apps/ebitemp-api/src/modules/enumify/enumify.ts
Normal file
74
apps/ebitemp-api/src/modules/enumify/enumify.ts
Normal file
@ -0,0 +1,74 @@
|
||||
// Based on https://github.com/rauschma/enumify
|
||||
// Original license: MIT License - Copyright (c) 2020 Axel Rauschmayer
|
||||
|
||||
export const registeredEnums: Record<string, typeof Enumify[]> = {};
|
||||
export function Enum(schema: string) {
|
||||
return function (target: typeof Enumify) {
|
||||
registeredEnums[schema] ??= [];
|
||||
registeredEnums[schema].push(target);
|
||||
};
|
||||
}
|
||||
|
||||
export class Enumify {
|
||||
static enumKeys: Array<string>;
|
||||
static enumValues: Array<Enumify>;
|
||||
|
||||
public readonly id?: number;
|
||||
public readonly nome?: string;
|
||||
|
||||
static closeEnum() {
|
||||
const enumKeys: Array<string> = [];
|
||||
const enumValues: Array<Enumify> = [];
|
||||
|
||||
for (const [key, value] of Object.entries(this)) {
|
||||
value.nome ??= key;
|
||||
value.id ??= enumValues.length;
|
||||
|
||||
if (value.id == null || value.id === '') {
|
||||
throw new Error(`${this.name}.id`);
|
||||
}
|
||||
if (value.nome == null || value.nome === '') {
|
||||
throw new Error(`${this.name}.nome`);
|
||||
}
|
||||
|
||||
enumKeys.push(value.nome);
|
||||
enumValues.push(value);
|
||||
}
|
||||
this.enumKeys = enumKeys;
|
||||
this.enumValues = enumValues;
|
||||
}
|
||||
|
||||
static fromKey(key: string): undefined | Enumify {
|
||||
if (this.enumKeys == undefined) {
|
||||
throw new Error(`Did you forget to call static _ = ${this.name}.closeEnum() after setup?`);
|
||||
}
|
||||
|
||||
const index = this.enumKeys.findIndex((enumKey) => enumKey.toUpperCase() === key.toString().toUpperCase());
|
||||
if (index >= 0) {
|
||||
return this.enumValues[index];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static fromValue(value: number): undefined | Enumify {
|
||||
if (this.enumValues == undefined) {
|
||||
throw new Error(`Did you forget to call static _ = ${this.name}.closeEnum() after setup?`);
|
||||
}
|
||||
|
||||
const index = this.enumValues.map((x) => x.id).indexOf(value);
|
||||
if (index >= 0) {
|
||||
const key = this.enumKeys[index];
|
||||
return this.fromKey(key);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected constructor(id?: number, nome?: string) {
|
||||
this.id = id;
|
||||
this.nome = nome;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `(${this.id}, ${this.nome})`;
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import fs from 'node:fs';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import path from 'node:path';
|
||||
import { FileTransactionsService } from './file-transactions.service';
|
||||
import {
|
||||
copyFilesToFolderOrFail,
|
||||
deleteFiles,
|
||||
renameFiles,
|
||||
renameFilesOrFail,
|
||||
} from './file-utils';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
export class FileTransaction {
|
||||
public static readonly TO_ADD_SUFFIX = 'toAdd';
|
||||
public static readonly TO_DELETE_SUFFIX = 'toDelete';
|
||||
|
||||
private readonly manager: FileTransactionsService;
|
||||
private readonly logger: Logger;
|
||||
|
||||
public readonly transactionId: string;
|
||||
private readonly ts: Date;
|
||||
public readonly filesToAdd: { src: string; dest: string }[];
|
||||
public readonly filesToDelete: string[];
|
||||
|
||||
constructor(
|
||||
manager: FileTransactionsService,
|
||||
opts: Partial<{
|
||||
transactionId: string;
|
||||
filesToAdd: { src: string; dest: string }[];
|
||||
filesToDelete: string[];
|
||||
logger: Logger;
|
||||
}>
|
||||
) {
|
||||
this.manager = manager;
|
||||
this.logger = opts.logger ?? new Logger(FileTransaction.name);
|
||||
this.filesToAdd = opts.filesToAdd ?? [];
|
||||
this.filesToDelete = opts.filesToDelete ?? [];
|
||||
this.transactionId = opts.transactionId ?? randomUUID().split('-').pop() as string;
|
||||
this.ts = new Date();
|
||||
}
|
||||
|
||||
async addFile(src: string, dest: string) {
|
||||
const destFolderName = path.dirname(dest);
|
||||
const destFileName = path.basename(dest);
|
||||
const destFileNameWithSuffix = `${destFileName}.${this.transactionId}.${FileTransaction.TO_ADD_SUFFIX}`;
|
||||
const destFilePathWithSuffix = path.join(
|
||||
destFolderName,
|
||||
destFileNameWithSuffix
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`Adding file '${destFilePathWithSuffix}' in fileTransaction '${
|
||||
this.transactionId
|
||||
}' (started at ${dayjs(this.ts).format('YYYY-MM-DD HH:mm:ss')})`
|
||||
);
|
||||
this.filesToAdd.push({ src: src, dest: destFilePathWithSuffix });
|
||||
|
||||
if (fs.existsSync(dest)) {
|
||||
await this.deleteFile(dest);
|
||||
}
|
||||
|
||||
await copyFilesToFolderOrFail(this.logger, destFolderName, {
|
||||
srcpath: src,
|
||||
name: destFileNameWithSuffix,
|
||||
});
|
||||
await deleteFiles(this.logger, src);
|
||||
this.manager.persist(this);
|
||||
}
|
||||
|
||||
async deleteFile(src: string) {
|
||||
const destFolderName = path.dirname(src);
|
||||
const destFileName = path.basename(src);
|
||||
const destFileNameWithSuffix = `${destFileName}.${this.transactionId}.${FileTransaction.TO_DELETE_SUFFIX}`;
|
||||
const destFilePathWithSuffix = path.join(
|
||||
destFolderName,
|
||||
destFileNameWithSuffix
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`Deleting file '${destFilePathWithSuffix}' in fileTransaction '${
|
||||
this.transactionId
|
||||
}' (started at ${dayjs(this.ts).format('YYYY-MM-DD HH:mm:ss')})`
|
||||
);
|
||||
this.filesToDelete.push(destFilePathWithSuffix);
|
||||
await renameFilesOrFail(this.logger, { src, dest: destFilePathWithSuffix });
|
||||
this.manager.persist(this);
|
||||
}
|
||||
|
||||
async commitTransaction() {
|
||||
this.logger.log(
|
||||
`Committing fileTransaction '${this.transactionId}' (started at ${dayjs(
|
||||
this.ts
|
||||
).format('YYYY-MM-DD HH:mm:ss')})`
|
||||
);
|
||||
await renameFiles(
|
||||
this.logger,
|
||||
...this.filesToAdd.map((fileToAdd) => ({
|
||||
src: fileToAdd.dest,
|
||||
dest: fileToAdd.dest.replace(
|
||||
`.${this.transactionId}.${FileTransaction.TO_ADD_SUFFIX}`,
|
||||
''
|
||||
),
|
||||
}))
|
||||
);
|
||||
await deleteFiles(this.logger, ...this.filesToDelete);
|
||||
this.manager.unregister(this);
|
||||
}
|
||||
|
||||
async rollbackTransaction() {
|
||||
this.logger.log(
|
||||
`Rollbacking fileTransaction '${this.transactionId}' (started at ${dayjs(
|
||||
this.ts
|
||||
).format('YYYY-MM-DD HH:mm:ss')})`
|
||||
);
|
||||
|
||||
await renameFiles(
|
||||
this.logger,
|
||||
...this.filesToAdd.map((fileToMove) => ({
|
||||
src: fileToMove.dest,
|
||||
dest: fileToMove.src,
|
||||
}))
|
||||
);
|
||||
|
||||
await renameFiles(
|
||||
this.logger,
|
||||
...this.filesToDelete.map((fileToRestore) => ({
|
||||
src: fileToRestore,
|
||||
dest: fileToRestore.replace(
|
||||
`.${this.transactionId}.${FileTransaction.TO_DELETE_SUFFIX}`,
|
||||
''
|
||||
),
|
||||
}))
|
||||
);
|
||||
this.manager.unregister(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { KeyvModule } from '../keyv/keyv.module';
|
||||
import { FileTransactionsService } from './file-transactions.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [KeyvModule],
|
||||
providers: [FileTransactionsService],
|
||||
exports: [FileTransactionsService],
|
||||
})
|
||||
export class AppFileTransactionsModule {}
|
@ -0,0 +1,54 @@
|
||||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||
import { FileTransaction } from './file-transaction';
|
||||
import { createKeyv, Keyv } from '@keyv/redis';
|
||||
import { parse, stringify } from 'flatted';
|
||||
import { KeyvService } from '../keyv/keyv.service';
|
||||
|
||||
const FILE_TRANSACTIONS_KEY = `FILE_TRANSACTIONS_KEY`;
|
||||
|
||||
@Injectable()
|
||||
export class FileTransactionsService implements OnModuleInit {
|
||||
private readonly logger = new Logger(FileTransactionsService.name);
|
||||
private readonly map: Record<string, FileTransaction> = {};
|
||||
|
||||
private readonly keyv: Keyv;
|
||||
|
||||
constructor(readonly keyvService: KeyvService) {
|
||||
this.keyv = this.keyvService.create({
|
||||
namespace: FileTransactionsService.name,
|
||||
});
|
||||
}
|
||||
|
||||
register(logger?: Logger) {
|
||||
const tx = new FileTransaction(this, { logger });
|
||||
this.persist(tx);
|
||||
return tx;
|
||||
}
|
||||
|
||||
persist(tx: FileTransaction) {
|
||||
this.map[tx.transactionId] = tx;
|
||||
this.keyv.set(FILE_TRANSACTIONS_KEY, this.map);
|
||||
}
|
||||
|
||||
unregister(tx: FileTransaction) {
|
||||
delete this.map[tx.transactionId];
|
||||
this.keyv.set(FILE_TRANSACTIONS_KEY, this.map);
|
||||
}
|
||||
|
||||
async onModuleInit() {
|
||||
this.logger.log('Checking for dangling file transactions...');
|
||||
const dangling = await this.keyv.get<Set<FileTransaction>>(
|
||||
FILE_TRANSACTIONS_KEY
|
||||
);
|
||||
|
||||
if (dangling) {
|
||||
for (const danglingTx of Object.values(dangling)) {
|
||||
const tx = new FileTransaction(this, {
|
||||
...danglingTx,
|
||||
logger: this.logger,
|
||||
});
|
||||
await tx.rollbackTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
apps/ebitemp-api/src/modules/file-transactions/file-utils.ts
Normal file
106
apps/ebitemp-api/src/modules/file-transactions/file-utils.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { promises as fs } from 'node:fs';
|
||||
import path from 'path';
|
||||
|
||||
interface File {
|
||||
srcpath: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const copyFilesToFolder = (logger: Logger, destFolder: string, ...files: File[]) =>
|
||||
_copyFilesToFolder(logger, destFolder, false, ...files);
|
||||
export const copyFilesToFolderOrFail = (logger: Logger, destFolder: string, ...files: File[]) =>
|
||||
_copyFilesToFolder(logger, destFolder, true, ...files);
|
||||
export const deleteFolder = (logger: Logger, folder: string) => _deleteFolder(logger, false, folder);
|
||||
export const deleteFolderOrFail = (logger: Logger, folder: string) => _deleteFolder(logger, true, folder);
|
||||
export const deleteFiles = (logger: Logger, ...files: string[]) => _deleteFiles(logger, false, ...files);
|
||||
export const deleteFilesOrFail = (logger: Logger, ...files: string[]) => _deleteFiles(logger, true, ...files);
|
||||
export const renameFiles = (logger: Logger, ...files: Array<{ src: string; dest: string }>) =>
|
||||
_renameFiles(logger, false, ...files);
|
||||
export const renameFilesOrFail = (logger: Logger, ...files: Array<{ src: string; dest: string }>) =>
|
||||
_renameFiles(logger, true, ...files);
|
||||
|
||||
export const normalizeWin32PathToPosix = (filepath: string): string =>
|
||||
path.win32.normalize(filepath).split(path.win32.sep).join(path.posix.sep);
|
||||
|
||||
const _copyFilesToFolder = async (
|
||||
logger: Logger,
|
||||
destFolder: string,
|
||||
throwsOnError = false,
|
||||
...files: File[]
|
||||
): Promise<void> => {
|
||||
await fs.mkdir(destFolder, { recursive: true });
|
||||
|
||||
for (const file of files) {
|
||||
try {
|
||||
const destpath = path.join(destFolder, file.name);
|
||||
await fs.copyFile(file.srcpath, destpath);
|
||||
logger.debug(`Copying file '${file.srcpath}' to '${destpath}'`);
|
||||
} catch (err: any) {
|
||||
const msg = `Could not copy '${file.srcpath}' to '${destFolder}'. Inner exception: ${err.message}`;
|
||||
if (throwsOnError) {
|
||||
logger.error(msg);
|
||||
err.message = msg;
|
||||
throw err;
|
||||
}
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _deleteFolder = async (logger: Logger, throwsOnError = false, folder: string): Promise<void> => {
|
||||
try {
|
||||
await fs.rmdir(folder, { recursive: true });
|
||||
logger.debug(`Deleting folder '${folder}'`);
|
||||
} catch (err: any) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return;
|
||||
}
|
||||
const msg = `Could not delete '${folder}'. Inner exception: ${err.message}`;
|
||||
if (throwsOnError) {
|
||||
logger.error(msg);
|
||||
throw err;
|
||||
}
|
||||
logger.warn(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const _deleteFiles = async (logger: Logger, throwsOnError = false, ...files: string[]): Promise<void> => {
|
||||
for (const file of files) {
|
||||
try {
|
||||
await fs.unlink(file);
|
||||
logger.debug(`Deleting file '${file}'`);
|
||||
} catch (err: any) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return;
|
||||
}
|
||||
const msg = `Could not delete '${file}'. Inner exception: ${err.message}`;
|
||||
if (throwsOnError) {
|
||||
logger.error(msg);
|
||||
throw err;
|
||||
}
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _renameFiles = async (
|
||||
logger: Logger,
|
||||
throwsOnError = false,
|
||||
...files: Array<{ src: string; dest: string }>
|
||||
): Promise<void> => {
|
||||
for (const file of files) {
|
||||
try {
|
||||
await fs.rename(file.src, file.dest);
|
||||
logger.debug(`Renaming file '${file.src}' to '${file.dest}'`);
|
||||
} catch (err: any) {
|
||||
const msg = `Could not rename '${file.src}' to '${file.dest}'. Inner exception: ${err.message}`;
|
||||
if (throwsOnError) {
|
||||
logger.error(msg);
|
||||
err.message = msg;
|
||||
throw err;
|
||||
}
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
};
|
30
apps/ebitemp-api/src/modules/health/health.controller.ts
Normal file
30
apps/ebitemp-api/src/modules/health/health.controller.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common';
|
||||
import {
|
||||
DiskHealthIndicator,
|
||||
HealthCheck,
|
||||
HealthCheckService,
|
||||
MemoryHealthIndicator,
|
||||
TypeOrmHealthIndicator,
|
||||
} from '@nestjs/terminus';
|
||||
import { Public } from '../auth/strategies/jwt/jwt-auth.guard';
|
||||
|
||||
@Public()
|
||||
@Controller({ path: 'health', version: VERSION_NEUTRAL })
|
||||
export class HealthController {
|
||||
constructor(
|
||||
private readonly health: HealthCheckService,
|
||||
private readonly db: TypeOrmHealthIndicator,
|
||||
private readonly disk: DiskHealthIndicator,
|
||||
private readonly memory: MemoryHealthIndicator
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@HealthCheck()
|
||||
check() {
|
||||
return this.health.check([
|
||||
() => this.db.pingCheck('database'),
|
||||
() => this.disk.checkStorage('storage', { path: '/', thresholdPercent: 0.5 }), // Threshold at 50% space occupied in path,
|
||||
() => this.memory.checkHeap('memory', 150 * 1024 * 1024), // Threshold at 150MB memory occupied by process
|
||||
]);
|
||||
}
|
||||
}
|
11
apps/ebitemp-api/src/modules/health/health.module.ts
Normal file
11
apps/ebitemp-api/src/modules/health/health.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TerminusModule } from '@nestjs/terminus';
|
||||
import { HealthController } from './health.controller';
|
||||
|
||||
@Module({
|
||||
imports: [TerminusModule.forRoot({
|
||||
errorLogStyle: 'pretty',
|
||||
})],
|
||||
controllers: [HealthController],
|
||||
})
|
||||
export class AppHealthModule {}
|
17
apps/ebitemp-api/src/modules/keyv/keyv.config.ts
Normal file
17
apps/ebitemp-api/src/modules/keyv/keyv.config.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import coerceRecordTypes from '../config/utils/coerce-record-types';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const keyvSchema = z.object({
|
||||
redis: z.string(),
|
||||
});
|
||||
export type KeyvConfig = z.infer<typeof keyvSchema>;
|
||||
|
||||
export const keyvConfig = registerAs('keyv', () => {
|
||||
const env = coerceRecordTypes(process.env);
|
||||
|
||||
const config: KeyvConfig = keyvSchema.strict().parse({
|
||||
redis: env['REDIS_CONNECTION_STRING'],
|
||||
});
|
||||
return config;
|
||||
});
|
11
apps/ebitemp-api/src/modules/keyv/keyv.module.ts
Normal file
11
apps/ebitemp-api/src/modules/keyv/keyv.module.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { keyvConfig } from './keyv.config';
|
||||
import { KeyvService } from './keyv.service';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule.forFeature(keyvConfig)],
|
||||
providers: [KeyvService],
|
||||
exports: [KeyvService],
|
||||
})
|
||||
export class KeyvModule {}
|
16
apps/ebitemp-api/src/modules/keyv/keyv.service.ts
Normal file
16
apps/ebitemp-api/src/modules/keyv/keyv.service.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { createKeyv, KeyvRedisOptions } from '@keyv/redis';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { parse, stringify } from 'flatted';
|
||||
import { keyvConfig, KeyvConfig } from './keyv.config';
|
||||
|
||||
@Injectable()
|
||||
export class KeyvService {
|
||||
constructor(@Inject(keyvConfig.KEY) private readonly config: KeyvConfig) {}
|
||||
|
||||
create(options?: KeyvRedisOptions) {
|
||||
const keyv = createKeyv(this.config.redis, options);
|
||||
keyv.serialize = stringify;
|
||||
keyv.deserialize = parse;
|
||||
return keyv;
|
||||
}
|
||||
}
|
21
apps/ebitemp-api/src/modules/logger/logger.config.ts
Normal file
21
apps/ebitemp-api/src/modules/logger/logger.config.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import coerceRecordTypes from '../config/utils/coerce-record-types';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const loggerSchema = z.object({
|
||||
seqServerHost: z.string(),
|
||||
seqServerPort: z.number().finite().positive(),
|
||||
seqApiKey: z.string(),
|
||||
});
|
||||
export type LoggerConfig = z.infer<typeof loggerSchema>;
|
||||
|
||||
export const loggerConfig = registerAs('logger', () => {
|
||||
const env = coerceRecordTypes(process.env);
|
||||
|
||||
const config: LoggerConfig = loggerSchema.strict().parse({
|
||||
seqServerHost: env['SEQ_SERVER_HOST'],
|
||||
seqServerPort: env['SEQ_SERVER_PORT'],
|
||||
seqApiKey: env['SEQ_API_KEY'],
|
||||
});
|
||||
return config;
|
||||
});
|
59
apps/ebitemp-api/src/modules/logger/logger.module.ts
Normal file
59
apps/ebitemp-api/src/modules/logger/logger.module.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { NestApplication } from '@nestjs/core';
|
||||
import { LoggerModule } from 'nestjs-pino';
|
||||
import { LoggerConfig, loggerConfig } from './logger.config';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forFeature(loggerConfig),
|
||||
LoggerModule.forRootAsync({
|
||||
imports: loggerConfig.asProvider().imports,
|
||||
useFactory: (loggerConfig: LoggerConfig) => ({
|
||||
pinoHttp: {
|
||||
autoLogging: true,
|
||||
quietReqLogger: true,
|
||||
quietResLogger: true,
|
||||
level: 'trace',
|
||||
useLevel: 'trace',
|
||||
mixin() {
|
||||
return { context: NestApplication.name };
|
||||
},
|
||||
customSuccessMessage: (req, res) => { return `${req.method} ${req.url}: ${res.statusCode} request succedeed` },
|
||||
customErrorMessage: (req, res) => { return `${req.method} ${req.url}: ${res.statusCode} request errored` },
|
||||
name: 'ebitemp-api',
|
||||
transport: {
|
||||
targets: [
|
||||
...(process.env['NODE_ENV'] !== 'production'
|
||||
? [
|
||||
{
|
||||
target: 'pino-pretty',
|
||||
level: 'debug',
|
||||
options: {
|
||||
colorize: true,
|
||||
messageFormat: '[{context}] {msg}',
|
||||
ignore: 'pid,hostname,context',
|
||||
translateTime: 'SYS:yyyy-mm-dd HH:MM:ss o',
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
target: '@autotelic/pino-seq-transport',
|
||||
level: 'trace',
|
||||
options: {
|
||||
loggerOpts: {
|
||||
serverUrl: `${loggerConfig.seqServerHost}:${loggerConfig.seqServerPort}`,
|
||||
apiKey: loggerConfig.seqApiKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
inject: [loggerConfig.KEY],
|
||||
}),
|
||||
],
|
||||
})
|
||||
export class AppLoggerModule {}
|
@ -0,0 +1,17 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ApiClientEntity, ApiClientInvocazioniEntity } from '../../database/connections/ebitemp-api';
|
||||
import { EBITEMP_API_DATASOURCE } from '../../database/connections/ebitemp-api/database.constants';
|
||||
import { KeyvModule } from '../../keyv/keyv.module';
|
||||
import { ClientsService } from './clients.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [
|
||||
KeyvModule,
|
||||
TypeOrmModule.forFeature([ApiClientEntity, ApiClientInvocazioniEntity], EBITEMP_API_DATASOURCE),
|
||||
],
|
||||
providers: [ClientsService],
|
||||
exports: [ClientsService],
|
||||
})
|
||||
export class ClientsModule {}
|
@ -0,0 +1,86 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { isError } from '@stdlib/assert';
|
||||
import AsyncLock from 'async-lock';
|
||||
import { Keyv } from 'cacheable';
|
||||
import { isObject } from 'lodash';
|
||||
import { Repository } from 'typeorm';
|
||||
import { runInTransaction } from 'typeorm-transactional';
|
||||
import { ApiClientEntity, ApiClientInvocazioniEntity } from '../../database/connections/ebitemp-api';
|
||||
import { EBITEMP_API_DATASOURCE } from '../../database/connections/ebitemp-api/database.constants';
|
||||
import { KeyvService } from '../../keyv/keyv.service';
|
||||
|
||||
@Injectable()
|
||||
export class ClientsService {
|
||||
private readonly logger = new Logger(ClientsService.name);
|
||||
private readonly lock = new AsyncLock();
|
||||
|
||||
private readonly keyv: Keyv;
|
||||
|
||||
constructor(
|
||||
keyvService: KeyvService,
|
||||
@InjectRepository(ApiClientEntity, EBITEMP_API_DATASOURCE)
|
||||
private readonly clientRepository: Repository<ApiClientEntity>,
|
||||
@InjectRepository(ApiClientInvocazioniEntity, EBITEMP_API_DATASOURCE)
|
||||
private readonly clientInvocazioniRepository: Repository<ApiClientInvocazioniEntity>
|
||||
) {
|
||||
this.keyv = keyvService.create({
|
||||
namespace: ClientsService.name,
|
||||
});
|
||||
}
|
||||
|
||||
async insertOne(
|
||||
baseUrl: string,
|
||||
path: string,
|
||||
method: string,
|
||||
requestBody: any,
|
||||
responseBody: any,
|
||||
hasFailed: boolean,
|
||||
errors: string | null
|
||||
) {
|
||||
try {
|
||||
return await runInTransaction(
|
||||
async () => {
|
||||
const client = await this.getClient(baseUrl);
|
||||
if (!client) return;
|
||||
|
||||
const payload = JSON.stringify(requestBody);
|
||||
const response = isObject(responseBody) ? JSON.stringify(responseBody) : responseBody;
|
||||
|
||||
const invocazione = this.clientInvocazioniRepository.create({
|
||||
idClient: client.id,
|
||||
percorso: path,
|
||||
metodo: method,
|
||||
timestamp: new Date(),
|
||||
richiesta: payload,
|
||||
risposta: response,
|
||||
errori: errors,
|
||||
flagErrore: hasFailed,
|
||||
});
|
||||
|
||||
await this.clientInvocazioniRepository.insert(invocazione);
|
||||
return invocazione;
|
||||
},
|
||||
{ connectionName: EBITEMP_API_DATASOURCE }
|
||||
);
|
||||
} catch (err) {
|
||||
if (!isError(err)) throw err;
|
||||
this.logger.error(`Unexpected error: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
private async getClient(baseUrl: string) {
|
||||
const key = `client:baseUrl#${baseUrl}`;
|
||||
|
||||
return await this.lock.acquire(key, async () => {
|
||||
let client = await this.keyv.get<ApiClientEntity>(key);
|
||||
const isInCache = client != null;
|
||||
if (!isInCache) {
|
||||
client ??= (await this.clientRepository.findOne({ where: { baseUrl: baseUrl } })) ?? undefined;
|
||||
if (client) this.keyv.set(key, client);
|
||||
}
|
||||
return client;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ApiEndpointEntity, ApiEndpointInvocazioniEntity } from '../../database/connections/ebitemp-api';
|
||||
import { EBITEMP_API_DATASOURCE } from '../../database/connections/ebitemp-api/database.constants';
|
||||
import { KeyvModule } from '../../keyv/keyv.module';
|
||||
import { EndpointsService } from './endpoints.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [
|
||||
KeyvModule,
|
||||
TypeOrmModule.forFeature([ApiEndpointEntity, ApiEndpointInvocazioniEntity], EBITEMP_API_DATASOURCE),
|
||||
],
|
||||
providers: [EndpointsService],
|
||||
exports: [EndpointsService],
|
||||
})
|
||||
export class EndpointsModule {}
|
@ -0,0 +1,84 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import AsyncLock from 'async-lock';
|
||||
import { Keyv } from 'cacheable';
|
||||
import { Repository } from 'typeorm';
|
||||
import { runInTransaction } from 'typeorm-transactional';
|
||||
import { AccountsEntity, ApiEndpointEntity, ApiEndpointInvocazioniEntity } from '../../database/connections/ebitemp-api';
|
||||
import { EBITEMP_API_DATASOURCE } from '../../database/connections/ebitemp-api/database.constants';
|
||||
import { KeyvService } from '../../keyv/keyv.service';
|
||||
import { RequestLog } from '../request-logger.interceptor';
|
||||
import { isError } from '@stdlib/assert';
|
||||
|
||||
@Injectable()
|
||||
export class EndpointsService {
|
||||
private readonly logger = new Logger(EndpointsService.name);
|
||||
private readonly lock = new AsyncLock();
|
||||
|
||||
private readonly keyv: Keyv;
|
||||
|
||||
constructor(
|
||||
keyvService: KeyvService,
|
||||
@InjectRepository(ApiEndpointEntity, EBITEMP_API_DATASOURCE)
|
||||
private readonly endpointRepository: Repository<ApiEndpointEntity>,
|
||||
@InjectRepository(ApiEndpointInvocazioniEntity, EBITEMP_API_DATASOURCE)
|
||||
private readonly endpointInvocazioniRepository: Repository<ApiEndpointInvocazioniEntity>
|
||||
) {
|
||||
this.keyv = keyvService.create({
|
||||
namespace: EndpointsService.name,
|
||||
});
|
||||
}
|
||||
|
||||
async insertOne(
|
||||
user: AccountsEntity,
|
||||
route: string,
|
||||
method: string,
|
||||
requestLog: RequestLog,
|
||||
responseLog: any,
|
||||
hasFailed: boolean
|
||||
) {
|
||||
try {
|
||||
return await runInTransaction(
|
||||
async () => {
|
||||
const endpoint = await this.getEndpoint(route, method);
|
||||
if (!endpoint) return;
|
||||
|
||||
const payload = JSON.stringify(requestLog);
|
||||
const response = JSON.stringify(responseLog);
|
||||
|
||||
const invocazione = this.endpointInvocazioniRepository.create({
|
||||
idAccount: user.id,
|
||||
idEndpoint: endpoint.id,
|
||||
timestamp: new Date(),
|
||||
richiesta: payload,
|
||||
risposta: response,
|
||||
flagErrore: hasFailed,
|
||||
});
|
||||
|
||||
await this.endpointInvocazioniRepository.insert(invocazione);
|
||||
return invocazione;
|
||||
},
|
||||
{ connectionName: EBITEMP_API_DATASOURCE }
|
||||
);
|
||||
} catch (err) {
|
||||
if (!isError(err)) throw err;
|
||||
this.logger.error(`Unexpected error: ${err.message}`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
private async getEndpoint(route: string, method: string) {
|
||||
const key = `endpoint:route,method#${route},${method}`;
|
||||
|
||||
return await this.lock.acquire(key, async () => {
|
||||
let endpoint = await this.keyv.get<ApiEndpointEntity>(key);
|
||||
const isInCache = endpoint != null;
|
||||
if (!isInCache) {
|
||||
endpoint ??=
|
||||
(await this.endpointRepository.findOne({ where: { percorso: route, metodo: method } })) ?? undefined;
|
||||
if (endpoint) this.keyv.set(key, endpoint);
|
||||
}
|
||||
return endpoint;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
import { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common';
|
||||
import { omit } from 'lodash';
|
||||
import { Observable } from 'rxjs';
|
||||
import { catchError, concatMap } from 'rxjs/operators';
|
||||
import { EndpointsService } from './endpoints/endpoints.service';
|
||||
import { RequestWithUser } from '../auth/constants/request-with-user';
|
||||
|
||||
export type RequestLog = {
|
||||
url: string;
|
||||
idAccount: string;
|
||||
params: object;
|
||||
query: object;
|
||||
body: object;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class RequestLoggerInterceptor implements NestInterceptor {
|
||||
private readonly logger = new Logger(RequestLoggerInterceptor.name);
|
||||
|
||||
constructor(private readonly endpointsService: EndpointsService) {}
|
||||
|
||||
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
|
||||
const request: RequestWithUser = context.switchToHttp().getRequest();
|
||||
|
||||
const user = request.user;
|
||||
const route = request.routeOptions.url ?? '/';
|
||||
const method = request.method as string;
|
||||
|
||||
request.params = { ...(request.params as object ?? {}), route, method };
|
||||
|
||||
const requestLog = {
|
||||
url: request.url,
|
||||
idAccount: `${user.id}`,
|
||||
params: omit((request.params as object), ['user', 'route', 'method']),
|
||||
query: omit((request.query as object), ['__context']),
|
||||
body: request.body as object,
|
||||
};
|
||||
|
||||
return next.handle().pipe(
|
||||
concatMap(async (res: any) => {
|
||||
await this.endpointsService.insertOne(user, route, method, requestLog, res, false);
|
||||
return res;
|
||||
}),
|
||||
catchError(async (err: any) => {
|
||||
const getExceptionResponse = (exception: any): any => {
|
||||
if (typeof exception.response === 'object') {
|
||||
const { error, message, ...rest } = exception.response;
|
||||
return {
|
||||
error,
|
||||
message,
|
||||
...rest,
|
||||
};
|
||||
}
|
||||
return {
|
||||
error: exception.name,
|
||||
message: exception.message,
|
||||
};
|
||||
};
|
||||
|
||||
const res = getExceptionResponse(err);
|
||||
|
||||
await this.endpointsService.insertOne(user, route, method, requestLog, res, true);
|
||||
throw err;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||
import { ClientsModule } from './clients/clients.module';
|
||||
import { EndpointsModule } from './endpoints/endpoints.module';
|
||||
import { RequestLoggerInterceptor } from './request-logger.interceptor';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [EndpointsModule, ClientsModule],
|
||||
providers: [],
|
||||
exports: [EndpointsModule, ClientsModule],
|
||||
})
|
||||
export class AppRequestLoggingModule {}
|
13
apps/ebitemp-api/src/modules/schedule/schedule.module.ts
Normal file
13
apps/ebitemp-api/src/modules/schedule/schedule.module.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ScheduleModule } from '@nestjs/schedule';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { TipiJobsEntity } from '../database/connections/ebitemp-api/entities';
|
||||
import { SchedulerService } from './schedule.service';
|
||||
import { EBITEMP_API_DATASOURCE } from '../database/connections/ebitemp-api/database.constants';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([TipiJobsEntity], EBITEMP_API_DATASOURCE), ScheduleModule.forRoot()],
|
||||
providers: [SchedulerService],
|
||||
exports: [],
|
||||
})
|
||||
export class AppScheduleModule {}
|
56
apps/ebitemp-api/src/modules/schedule/schedule.service.ts
Normal file
56
apps/ebitemp-api/src/modules/schedule/schedule.service.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { isError } from '@stdlib/assert';
|
||||
import { CronJob, CronTime } from 'cron';
|
||||
import { Repository } from 'typeorm';
|
||||
import { EBITEMP_API_DATASOURCE } from '../database/connections/ebitemp-api/database.constants';
|
||||
import { TipiJobsEntity } from '../database/connections/ebitemp-api/entities/tipi_jobs.entity';
|
||||
|
||||
@Injectable()
|
||||
export class SchedulerService {
|
||||
private readonly logger = new Logger(SchedulerService.name);
|
||||
|
||||
private static readonly TIME_ZONE = 'Europe/Rome';
|
||||
|
||||
constructor(
|
||||
private readonly schedulerRegistry: SchedulerRegistry,
|
||||
@InjectRepository(TipiJobsEntity, EBITEMP_API_DATASOURCE)
|
||||
private readonly tipiJobsRepository: Repository<TipiJobsEntity>
|
||||
) {}
|
||||
|
||||
async onApplicationBootstrap() {
|
||||
try {
|
||||
const jobs = this.schedulerRegistry.getCronJobs();
|
||||
const jobTypes = await this.tipiJobsRepository.find();
|
||||
|
||||
for (const [jobName, job] of jobs) {
|
||||
this.rescheduleJobAccordingToJobType(jobTypes, jobName, job);
|
||||
}
|
||||
} catch (err) {
|
||||
if (!isError(err)) throw err;
|
||||
this.logger.error(err.message);
|
||||
this.logger.warn(`Error while retrieving scheduled jobs on database. Skipping jobs.`);
|
||||
}
|
||||
}
|
||||
|
||||
private rescheduleJobAccordingToJobType(jobTypes: TipiJobsEntity[], jobName: string, job: CronJob) {
|
||||
const jobType = jobTypes.find((jobType) => jobType.nome == jobName);
|
||||
|
||||
if (!jobType) {
|
||||
this.logger.warn(`Job type for job '${jobName}' not found on database. Skipping job.`);
|
||||
this.schedulerRegistry.deleteCronJob(jobName);
|
||||
return;
|
||||
}
|
||||
|
||||
const jobTime = new CronTime(jobType.patternCron, SchedulerService.TIME_ZONE);
|
||||
job.setTime(jobTime);
|
||||
job.start();
|
||||
|
||||
this.logger.log(
|
||||
`Job type id '${jobType.id}' found for job '${jobName}' [isActive: ${jobType.flagAttivo}, cronPattern: ${
|
||||
jobType.patternCron
|
||||
}]. Upcoming date => ${job.nextDate()}`
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
|
||||
export async function patchNestjsSwagger() {
|
||||
(await import('@anatine/zod-nestjs')).patchNestjsSwagger();
|
||||
};
|
12
apps/ebitemp-api/src/modules/validation/validation.module.ts
Normal file
12
apps/ebitemp-api/src/modules/validation/validation.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
|
||||
import { ZodValidationPipe } from './zod.pipe';
|
||||
import { ZodSerializerInterceptor } from './zod.serializer';
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
{ provide: APP_PIPE, useClass: ZodValidationPipe },
|
||||
{ provide: APP_INTERCEPTOR, useClass: ZodSerializerInterceptor },
|
||||
],
|
||||
})
|
||||
export class AppValidationModule {}
|
36
apps/ebitemp-api/src/modules/validation/zod.pipe.ts
Normal file
36
apps/ebitemp-api/src/modules/validation/zod.pipe.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { ZodDtoStatic } from '@anatine/zod-nestjs';
|
||||
import { HTTP_ERRORS_BY_CODE } from '@anatine/zod-nestjs/src/lib/http-errors';
|
||||
|
||||
import { ArgumentMetadata, HttpStatus, Injectable, Optional, PipeTransform } from '@nestjs/common';
|
||||
|
||||
export interface ZodValidationPipeOptions {
|
||||
errorHttpStatusCode?: keyof typeof HTTP_ERRORS_BY_CODE;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ZodValidationPipe implements PipeTransform {
|
||||
private readonly errorHttpStatusCode: keyof typeof HTTP_ERRORS_BY_CODE;
|
||||
|
||||
constructor(@Optional() options?: ZodValidationPipeOptions) {
|
||||
this.errorHttpStatusCode = options?.errorHttpStatusCode || HttpStatus.BAD_REQUEST;
|
||||
}
|
||||
|
||||
public transform(value: unknown, metadata: ArgumentMetadata): unknown {
|
||||
const zodSchema = (metadata?.metatype as ZodDtoStatic)?.zodSchema;
|
||||
|
||||
if (zodSchema) {
|
||||
const parseResult = zodSchema.safeParse(value);
|
||||
|
||||
if (!parseResult.success) {
|
||||
const { error } = parseResult;
|
||||
const message = error.errors.map((error) => `${error.path.join('.')}: ${error.message}`);
|
||||
|
||||
throw new HTTP_ERRORS_BY_CODE[this.errorHttpStatusCode](message);
|
||||
}
|
||||
|
||||
return parseResult.data;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user