diff --git a/.github/workflows/tests-pipeline.yml b/.github/workflows/tests-pipeline.yml index bbcdc07..a341d39 100644 --- a/.github/workflows/tests-pipeline.yml +++ b/.github/workflows/tests-pipeline.yml @@ -43,13 +43,16 @@ jobs: run: | echo "DATABASE_URL=postgresql://${{ secrets.POSTGRES_USER }}:${{ secrets.POSTGRES_PASSWORD }}@localhost:5432/${{ secrets.POSTGRES_DB }}?schema=${{ secrets.POSTGRES_SCHEMA }}" >> $GITHUB_ENV - - name: Setting up docker compose - run: docker compose up -d + # - name: Setting up docker compose + # run: docker compose up -d - - name: Setting up prisma postgresql database - run: | - pnpm run prisma:core:schema:generate - pnpm run prisma:core:schema:migrate + # - name: Setting up prisma postgresql database + # run: | + # pnpm run prisma:core:schema:generate + # pnpm run prisma:core:schema:migrate + + - name: Run core-setup script + run: pnpm run core-setup --action=migrate,generate - name: Run E2E Tests run: pnpm run test:e2e diff --git a/.vscode/settings.json b/.vscode/settings.json index 0e24cc5..3ab69b2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,8 +14,12 @@ "commitlint", "conventionalcommits", "CQRS", + "encrypter", + "Encrypter", "github", "GITHUB", + "hasher", + "Hasher", "instanceof", "italo", "keyof", diff --git a/libs/core-rest-api/adapters/src/auth/auth.module.ts b/libs/core-rest-api/adapters/src/auth/auth.module.ts index 0227ee3..b986ba2 100644 --- a/libs/core-rest-api/adapters/src/auth/auth.module.ts +++ b/libs/core-rest-api/adapters/src/auth/auth.module.ts @@ -1,33 +1,42 @@ import { Module } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; +import { APP_GUARD } from '@nestjs/core'; import { JwtModule } from '@nestjs/jwt'; import { PassportModule } from '@nestjs/passport'; import { Env } from '../env/env'; import { EnvService } from '../env/env.service'; +import { JwtAuthGuard } from './jwt-auth.guard'; import { JwtStrategy } from './jwt.strategy'; - @Module({ imports: [ PassportModule, JwtModule.registerAsync({ inject: [ConfigService], global: true, - useFactory(config: ConfigService){ - const privateKey = config.get('JWT_PRIVATE_KEY', {infer: true}); - const publicKey = config.get('JWT_PUBLIC_KEY', {infer: true}); + useFactory(config: ConfigService) { + const privateKey = config.get('JWT_PRIVATE_KEY', { infer: true }); + const publicKey = config.get('JWT_PUBLIC_KEY', { infer: true }); return { signOptions: { - algorithm: 'RS256', expiresIn: '1h' + algorithm: 'RS256', + expiresIn: '1h', }, privateKey: Buffer.from(privateKey, 'base64'), - publicKey: Buffer.from(publicKey, 'base64') - } - } - }) + publicKey: Buffer.from(publicKey, 'base64'), + }; + }, + }), + ], + providers: [ + JwtStrategy, + EnvService, + { + provide: APP_GUARD, + useClass: JwtAuthGuard, + }, ], - providers: [JwtStrategy, EnvService] }) -export class AuthModule{} +export class AuthModule {} diff --git a/libs/core-rest-api/adapters/src/auth/jwt-auth.guard.ts b/libs/core-rest-api/adapters/src/auth/jwt-auth.guard.ts index f7dc63d..1cd25ac 100644 --- a/libs/core-rest-api/adapters/src/auth/jwt-auth.guard.ts +++ b/libs/core-rest-api/adapters/src/auth/jwt-auth.guard.ts @@ -1,3 +1,35 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; +import { IS_PUBLIC_KEY } from './public'; -export class JwtAuthGuard extends AuthGuard('jwt'){} +@Injectable() +export class JwtAuthGuard extends AuthGuard('jwt') { + constructor(private reflector: Reflector) { + super(); + } + + override canActivate(context: ExecutionContext) { + console.log('[JWT-GUARD] - Verifying if route is public'); + + const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ + context.getHandler(), + context.getClass(), + ]); + + if (!isPublic) { + return super.canActivate(context); + } + + return true; + } + + override handleRequest(err: unknown, user: any) { + if (err || !user) { + throw new UnauthorizedException('Invalid JWT token'); + } + + return user; + } +} diff --git a/libs/core-rest-api/adapters/src/auth/jwt.strategy.ts b/libs/core-rest-api/adapters/src/auth/jwt.strategy.ts index 22b1972..2ced125 100644 --- a/libs/core-rest-api/adapters/src/auth/jwt.strategy.ts +++ b/libs/core-rest-api/adapters/src/auth/jwt.strategy.ts @@ -5,26 +5,28 @@ import { z } from 'zod'; import { EnvService } from '../env/env.service'; const tokenPayloadSchema = z.object({ - sub: z.string().uuid() -}) + id: z.string().uuid(), + name: z.string(), + email: z.string().email(), +}); -export type TokenPayload = z.infer +export type TokenPayload = z.infer; @Injectable() -export class JwtStrategy extends PassportStrategy(Strategy){ - constructor(config: EnvService){ - const publicKey = config.get('JWT_PUBLIC_KEY') - console.log('JwtStrategy') +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor(config: EnvService) { + const publicKey = config.get('JWT_PUBLIC_KEY'); super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: Buffer.from(publicKey, 'base64'), - algorithms: ['RS256'] - }) + algorithms: ['RS256'], + }); } + async validate(payload: TokenPayload) { - console.log('jwtStrategy validate') + console.log('jwtStrategy validate'); - return tokenPayloadSchema.parse(payload) + return tokenPayloadSchema.parse(payload); } } diff --git a/libs/core-rest-api/adapters/src/auth/public.ts b/libs/core-rest-api/adapters/src/auth/public.ts new file mode 100644 index 0000000..b3845e1 --- /dev/null +++ b/libs/core-rest-api/adapters/src/auth/public.ts @@ -0,0 +1,4 @@ +import { SetMetadata } from '@nestjs/common'; + +export const IS_PUBLIC_KEY = 'isPublic'; +export const Public = () => SetMetadata(IS_PUBLIC_KEY, true); diff --git a/libs/core-rest-api/adapters/src/controllers/api/api.module.ts b/libs/core-rest-api/adapters/src/controllers/api/api.module.ts index f08fe1c..f2fcd3f 100644 --- a/libs/core-rest-api/adapters/src/controllers/api/api.module.ts +++ b/libs/core-rest-api/adapters/src/controllers/api/api.module.ts @@ -1,3 +1,4 @@ +import { BcryptHasherService } from '@clinicControl/core-rest-api/core/src/shared/cryptography/use-cases/bcrypt-hasher.service'; import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AuthModule } from '../../auth/auth.module'; @@ -6,21 +7,30 @@ import { PostgreSqlPrismaOrmService } from '../../database/infra/prisma/prisma.s import { DatabaseRepositoriesModule } from '../../database/repositories/repositories.module'; import { envSchema } from '../../env/env'; import { EnvModule } from '../../env/env.module'; -import { CreatePsychologistController } from './use-case/create-psychologist/create-psychologist.controller'; -import { NestjsCreatePsychologistService } from './use-case/create-psychologist/nestjs-create-psychologist.service'; + +import { AuthenticatePsychologistController } from './use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller'; +import { CreatePsychologistController } from './use-cases/psychologist/create-psychologist/create-psychologist.controller'; + +import { NestjsAuthenticatePsychologistService } from './use-cases/psychologist/authenticate-psychologist/nestjs-authenticate-psychologist.service'; +import { NestjsCreatePsychologistService } from './use-cases/psychologist/create-psychologist/nestjs-create-psychologist.service'; @Module({ imports: [ - DatabaseRepositoriesModule, - EnvModule, - AuthModule, - CryptographyModule, ConfigModule.forRoot({ validate: (env) => envSchema.parse(env), isGlobal: true, }), + DatabaseRepositoriesModule, + EnvModule, + AuthModule, + CryptographyModule, + ], + controllers: [CreatePsychologistController, AuthenticatePsychologistController], + providers: [ + BcryptHasherService, + PostgreSqlPrismaOrmService, + NestjsCreatePsychologistService, + NestjsAuthenticatePsychologistService, ], - controllers: [CreatePsychologistController], - providers: [PostgreSqlPrismaOrmService, NestjsCreatePsychologistService], }) export class ApiModule {} diff --git a/libs/core-rest-api/adapters/src/controllers/api/decorators/current-user.decorator.ts b/libs/core-rest-api/adapters/src/controllers/api/decorators/current-user.decorator.ts new file mode 100644 index 0000000..3241d73 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/decorators/current-user.decorator.ts @@ -0,0 +1,18 @@ +/* + @see https://docs.nestjs.com/fundamentals/execution-context + + - Como é um decorator ele começa com a letra maiúscula + - O decorator CurrentUser é um decorator de parâmetro de método e não de classe, por isso usamos createParamDecorator + - O decorator CurrentUser recebe dois parâmetros: + - O primeiro é o nome do parâmetro que queremos injetar, mas como não queremos injetar nenhum parâmetro, passamos um underscore + - O segundo é o contexto da requisição +*/ + +import { ExecutionContext, createParamDecorator } from '@nestjs/common'; +import { TokenPayload } from '../../../auth/jwt.strategy'; + +export const CurrentUser = createParamDecorator((_: never, context: ExecutionContext) => { + const request = context.switchToHttp().getRequest(); // usamos o switchToHttp para ter acesso ao request da requisição, e getRequest() para pegar o request (o request é um objeto que tem várias informações da requisição) + + return request.user as TokenPayload; +}); diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller.ts new file mode 100644 index 0000000..2d313c9 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller.ts @@ -0,0 +1,39 @@ +import { Body, Controller, Post } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; + +import { AuthenticatePsychologistDto } from '@clinicControl/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist-dto'; +import { Encrypter } from '@clinicControl/core-rest-api/core/src/shared/cryptography/repository/encrypter-repository'; +import { GlobalAppHttpException } from '@clinicControl/core-rest-api/core/src/shared/errors/globalAppHttpException'; + +import { Public } from '../../../../../auth/public'; +import { AuthenticatePsychologistControllerResponse } from './authenticate-psychologist.interface'; +import { NestjsAuthenticatePsychologistService } from './nestjs-authenticate-psychologist.service'; + +@ApiTags() +@Controller({ + path: 'psychologist', +}) +export class AuthenticatePsychologistController { + constructor( + private AuthenticatePsychologistService: NestjsAuthenticatePsychologistService, + private jwtEncrypter: Encrypter + ) {} + + @Post('login') + @Public() + async execute( + @Body() psychologistLoginDto: AuthenticatePsychologistDto + ): Promise { + try { + const { id, name, email } = await this.AuthenticatePsychologistService.execute( + psychologistLoginDto + ); + + const access_token = await this.jwtEncrypter.encrypt({ id, name, email }); + + return { user: { id, name, email }, access_token }; + } catch (error: unknown) { + throw new GlobalAppHttpException(error); + } + } +} diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.e2e-spec.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.e2e-spec.ts new file mode 100644 index 0000000..3c6cbb2 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.e2e-spec.ts @@ -0,0 +1,79 @@ +import request from 'supertest'; + +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; + +import { fakerPT_BR as faker } from '@faker-js/faker'; +import { hash } from 'bcryptjs'; + +import { DatabaseRepositoriesModule } from '@clinicControl/core-rest-api/adapters/src/database/repositories/repositories.module'; +import { PsychologistFactory } from '../../../../../../tests/factories/make-psychologist'; +import { ApiModule } from '../../../api.module'; + +describe('[E2E] - Authenticate Psychologist', () => { + let app: INestApplication; + let psychologistFactory: PsychologistFactory; + + beforeAll(async () => { + const moduleRef = await Test.createTestingModule({ + imports: [ApiModule, DatabaseRepositoriesModule], + providers: [PsychologistFactory], + }).compile(); + + app = moduleRef.createNestApplication(); + + psychologistFactory = moduleRef.get(PsychologistFactory); + + await app.init(); + }); + + it('[POST] - Should successfully authenticate a psychologist', async () => { + const password = faker.internet.password({ length: 8 }); + const newPsychologist = await psychologistFactory.makePrismaPsychologist({ + password: await hash(password, 8), + }); + + const response = await request(app.getHttpServer()).post('/psychologist/login').send({ + email: newPsychologist.email, + password, + }); + + expect(response.statusCode).toBe(201); + expect(response.body).toEqual({ + user: { + id: newPsychologist.id, + name: newPsychologist.name, + email: newPsychologist.email, + }, + access_token: expect.any(String), + }); + }); + + it('[POST] - Should return an error 401 when trying to authenticate with wrong password', async () => { + const password = faker.internet.password({ length: 8 }); + const newPsychologist = await psychologistFactory.makePrismaPsychologist({ + password: await hash(password, 8), + email: 'new_user_entrie@email.com', + }); + + const response = await request(app.getHttpServer()) + .post('/psychologist/login') + .send({ + email: newPsychologist.email, + password: faker.internet.password({ length: 3 }), + }); + + expect(response.statusCode).toBe(401); + }); + + it('[POST] - Should return an error 401 when trying to authenticate with wrong password', async () => { + const password = faker.internet.password({ length: 8 }); + + const response = await request(app.getHttpServer()).post('/psychologist/login').send({ + email: 'user_not_exist@email.com', + password, + }); + + expect(response.statusCode).toBe(401); + }); +}); diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.interface.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.interface.ts new file mode 100644 index 0000000..fba5130 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.interface.ts @@ -0,0 +1,8 @@ +export interface AuthenticatePsychologistControllerResponse { + user: { + id: string; + name: string; + email: string; + }; + access_token: string; +} diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/docs.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/docs.ts similarity index 100% rename from libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/docs.ts rename to libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/docs.ts diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/nestjs-authenticate-psychologist.service.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/nestjs-authenticate-psychologist.service.ts new file mode 100644 index 0000000..5dd1c92 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/nestjs-authenticate-psychologist.service.ts @@ -0,0 +1,10 @@ +import { PsychologistDatabaseRepository } from '@clinicControl/core-rest-api/core/src/domains/psychologist/repositories/database-repository'; +import { AuthenticatePsychologistService } from '@clinicControl/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist.service'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class NestjsAuthenticatePsychologistService extends AuthenticatePsychologistService { + constructor(psychologistDatabaseRepository: PsychologistDatabaseRepository) { + super(psychologistDatabaseRepository); + } +} diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/create-psychologist.controller.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/create-psychologist.controller.ts similarity index 84% rename from libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/create-psychologist.controller.ts rename to libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/create-psychologist.controller.ts index 7215d05..459c11c 100644 --- a/libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/create-psychologist.controller.ts +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/create-psychologist.controller.ts @@ -1,11 +1,12 @@ // eslint-disable-next-line @nx/enforce-module-boundaries +import { Public } from '@clinicControl/core-rest-api/adapters/src/auth/public'; import { CreatePsychologistDto } from '@clinicControl/core-rest-api/core/src/domains/psychologist/use-cases/create-psychologist/create-psychologist-dto'; import { GlobalAppHttpException } from '@clinicControl/core-rest-api/core/src/shared/errors/globalAppHttpException'; import { applicationValidateOrReject } from '@clinicControl/core-rest-api/core/src/shared/validators/validate-or-reject'; import { Body, Controller, Post, UseGuards } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { plainToInstance } from 'class-transformer'; -import { ApiKeyGuard } from '../../guards/api-key.guard'; +import { ApiKeyGuard } from '../../../guards/api-key.guard'; import { NestjsCreatePsychologistService } from './nestjs-create-psychologist.service'; @ApiTags() @@ -13,12 +14,11 @@ import { NestjsCreatePsychologistService } from './nestjs-create-psychologist.se path: 'psychologist', }) export class CreatePsychologistController { - constructor( - private createPsychologistService: NestjsCreatePsychologistService - ) {} + constructor(private createPsychologistService: NestjsCreatePsychologistService) {} @Post('create') @UseGuards(ApiKeyGuard) + @Public() async execute( @Body() createPsychologistDto: CreatePsychologistDto ): Promise { diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/create-psychologist.e2e-spec.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/create-psychologist.e2e-spec.ts similarity index 91% rename from libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/create-psychologist.e2e-spec.ts rename to libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/create-psychologist.e2e-spec.ts index a925ac7..b521cc2 100644 --- a/libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/create-psychologist.e2e-spec.ts +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/create-psychologist.e2e-spec.ts @@ -3,9 +3,9 @@ import request from 'supertest'; import { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; -import { makePsychologist } from '../../../../../tests/factories/make-psychologist'; -import { PostgreSqlPrismaOrmService } from '../../../../database/infra/prisma/prisma.service'; -import { ApiModule } from '../../api.module'; +import { makePsychologist } from '../../../../../../tests/factories/make-psychologist'; +import { PostgreSqlPrismaOrmService } from '../../../../../database/infra/prisma/prisma.service'; +import { ApiModule } from '../../../api.module'; describe('[E2E] - Create Psychologist Account', () => { let app: INestApplication; diff --git a/libs/core-rest-api/adapters/src/controllers/consumers(to-do)/consumers.controller.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/docs.ts similarity index 100% rename from libs/core-rest-api/adapters/src/controllers/consumers(to-do)/consumers.controller.ts rename to libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/docs.ts diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/nestjs-create-psychologist.service.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/nestjs-create-psychologist.service.ts similarity index 100% rename from libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/nestjs-create-psychologist.service.ts rename to libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/create-psychologist/nestjs-create-psychologist.service.ts diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/client.http b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/psychologist-client.http similarity index 83% rename from libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/client.http rename to libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/psychologist-client.http index 0011c1e..facd699 100644 --- a/libs/core-rest-api/adapters/src/controllers/api/use-case/create-psychologist/client.http +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/psychologist-client.http @@ -1,6 +1,8 @@ @baseUrl = http://localhost:3333/core @authToken = {{loginauthenticate.response.body.access_token}} +### Create New User + # @name create_psychologist POST http://localhost:3333/core/psychologist/create HTTP/1.1 Content-Type: application/json @@ -14,19 +16,15 @@ api-key: api-key "plan": "PREMIUM" } -### +### Authenticate User # @name loginauthenticate POST http://localhost:3333/core/psychologist/login HTTP/1.1 Content-Type: application/json -api-key: api-key { - "name": "Novo Usuario", "email": "novo_usuario@gmail.com", - "password": "01212012", - "role": "PSYCHOLOGIST", - "plan": "PREMIUM" + "password": "01212012" } ### @@ -34,5 +32,4 @@ api-key: api-key # @name me GET http://localhost:3333/core/psychologist/me HTTP/1.1 Content-Type: application/json -api-key: api-key Authorization: Bearer {{authToken}} diff --git a/libs/core-rest-api/adapters/src/controllers/consumers(to-do)/consumers.module.ts b/libs/core-rest-api/adapters/src/controllers/consumers(to-do)/consumers.module.ts deleted file mode 100644 index e69de29..0000000 diff --git a/libs/core-rest-api/adapters/src/cryptography/bcrypt-hasher.ts b/libs/core-rest-api/adapters/src/cryptography/bcrypt-hasher.ts deleted file mode 100644 index 1d15674..0000000 --- a/libs/core-rest-api/adapters/src/cryptography/bcrypt-hasher.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { compare, hash } from 'bcryptjs'; - -import { HashComparer } from '@clinicControl/core-rest-api/core/src/shared/cryptography/hash-comparer'; -import { HashGenerator } from '@clinicControl/core-rest-api/core/src/shared/cryptography/hash-generator'; - -export class BcryptHasher implements HashGenerator, HashComparer { - private HASH_SALT_LENGTH = 8; - - hash(plain: string): Promise { - return hash(plain, this.HASH_SALT_LENGTH); - } - - compare(plain: string, hash: string): Promise { - return compare(plain, hash); - } -} diff --git a/libs/core-rest-api/adapters/src/cryptography/cryptography.module.ts b/libs/core-rest-api/adapters/src/cryptography/cryptography.module.ts index f27a2cf..a3c282f 100644 --- a/libs/core-rest-api/adapters/src/cryptography/cryptography.module.ts +++ b/libs/core-rest-api/adapters/src/cryptography/cryptography.module.ts @@ -1,17 +1,10 @@ import { Module } from '@nestjs/common'; -import { Encrypter } from '@clinicControl/core-rest-api/core/src/shared/cryptography/encrypter'; -import { HashComparer } from '@clinicControl/core-rest-api/core/src/shared/cryptography/hash-comparer'; -import { HashGenerator } from '@clinicControl/core-rest-api/core/src/shared/cryptography/hash-generator'; -import { BcryptHasher } from './bcrypt-hasher'; +import { Encrypter } from '@clinicControl/core-rest-api/core/src/shared/cryptography/repository/encrypter-repository'; import { JwtEncrypter } from './jwt-encrypter'; @Module({ - providers: [ - { provide: Encrypter, useClass: JwtEncrypter }, - { provide: HashComparer, useClass: BcryptHasher }, - { provide: HashGenerator, useClass: BcryptHasher }, - ], - exports: [Encrypter, HashComparer, HashGenerator], + providers: [{ provide: Encrypter, useClass: JwtEncrypter }], + exports: [Encrypter], }) export class CryptographyModule {} diff --git a/libs/core-rest-api/adapters/src/cryptography/jwt-encrypter.ts b/libs/core-rest-api/adapters/src/cryptography/jwt-encrypter.ts index 824a2b1..36533cf 100644 --- a/libs/core-rest-api/adapters/src/cryptography/jwt-encrypter.ts +++ b/libs/core-rest-api/adapters/src/cryptography/jwt-encrypter.ts @@ -1,4 +1,4 @@ -import { Encrypter } from '@clinicControl/core-rest-api/core/src/shared/cryptography/encrypter'; +import { Encrypter } from '@clinicControl/core-rest-api/core/src/shared/cryptography/repository/encrypter-repository'; import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; diff --git a/libs/core-rest-api/adapters/src/database/repositories/psychologist/postgresql-prisma-orm-repository.ts b/libs/core-rest-api/adapters/src/database/repositories/psychologist/postgresql-prisma-orm-repository.ts index a293171..b3af8fb 100644 --- a/libs/core-rest-api/adapters/src/database/repositories/psychologist/postgresql-prisma-orm-repository.ts +++ b/libs/core-rest-api/adapters/src/database/repositories/psychologist/postgresql-prisma-orm-repository.ts @@ -2,7 +2,6 @@ import { PsychologistEntity } from '@clinicControl/core-rest-api/core/src/domain import { PsychologistDatabaseRepository } from '@clinicControl/core-rest-api/core/src/domains/psychologist/repositories/database-repository'; import { CreatePsychologistDto } from '@clinicControl/core-rest-api/core/src/domains/psychologist/use-cases/create-psychologist/create-psychologist-dto'; import { UpdatePsychologistDto } from '@clinicControl/core-rest-api/core/src/domains/psychologist/use-cases/update-psychologist/update-psychologist-dto'; -import { HashGenerator } from '@clinicControl/core-rest-api/core/src/shared/cryptography/hash-generator'; import { PSYCHOLOGIST_ERROR_MESSAGES } from '@clinicControl/core-rest-api/core/src/shared/errors/error-messages'; import { ConflictException, Injectable } from '@nestjs/common'; import { PostgreSqlPrismaOrmService } from '../../../database/infra/prisma/prisma.service'; @@ -12,10 +11,7 @@ import { PostgresqlPrismaPsychologistMapper } from '../../mappers/postgresql-pri export class PostgresqlPrismaOrmPsychologistRepository implements PsychologistDatabaseRepository { - constructor( - private postgreSqlPrismaOrmService: PostgreSqlPrismaOrmService, - private hashGenerator: HashGenerator - ) {} + constructor(private postgreSqlPrismaOrmService: PostgreSqlPrismaOrmService) {} async createPsychologist( psychologist: CreatePsychologistDto @@ -28,12 +24,8 @@ export class PostgresqlPrismaOrmPsychologistRepository ); } - const hashedPassword = await this.hashGenerator.hash(psychologist.password); - - const toPrismaEntity = PostgresqlPrismaPsychologistMapper.toPrismaCreate({ - ...psychologist, - password: hashedPassword, - }); + const toPrismaEntity = + PostgresqlPrismaPsychologistMapper.toPrismaCreate(psychologist); const newPsychologist = await this.postgreSqlPrismaOrmService['psychologist'].create( toPrismaEntity diff --git a/libs/core-rest-api/adapters/src/database/repositories/repositories.module.ts b/libs/core-rest-api/adapters/src/database/repositories/repositories.module.ts index 1d79e6e..c239db2 100644 --- a/libs/core-rest-api/adapters/src/database/repositories/repositories.module.ts +++ b/libs/core-rest-api/adapters/src/database/repositories/repositories.module.ts @@ -1,11 +1,10 @@ import { PsychologistDatabaseRepository } from '@clinicControl/core-rest-api/core/src/domains/psychologist/repositories/database-repository'; import { Module } from '@nestjs/common'; -import { CryptographyModule } from '../../cryptography/cryptography.module'; import { PostgreSqlPrismaOrmService } from '../infra/prisma/prisma.service'; import { PostgresqlPrismaOrmPsychologistRepository } from './psychologist/postgresql-prisma-orm-repository'; @Module({ - imports: [CryptographyModule], + imports: [], controllers: [], providers: [ PostgreSqlPrismaOrmService, diff --git a/libs/core-rest-api/adapters/src/env/env.ts b/libs/core-rest-api/adapters/src/env/env.ts index 80538c2..14f1870 100644 --- a/libs/core-rest-api/adapters/src/env/env.ts +++ b/libs/core-rest-api/adapters/src/env/env.ts @@ -7,16 +7,16 @@ export const envSchema = z.object({ PORT: z.coerce.number().optional().default(3333), // Auth - JWT_PRIVATE_KEY: z.string(), - JWT_PUBLIC_KEY: z.string(), + JWT_PRIVATE_KEY: z.string().min(1, 'JWT_PRIVATE_KEY cannot be empty'), + JWT_PUBLIC_KEY: z.string().min(1, 'JWT_PUBLIC_KEY cannot be empty'), // ########## Database ########## - POSTGRES_USER: z.string(), - POSTGRES_PASSWORD: z.string(), - POSTGRES_DB: z.string(), - POSTGRES_HOST: z.string(), + POSTGRES_USER: z.string().min(1, 'POSTGRES_USER cannot be empty'), + POSTGRES_PASSWORD: z.string().min(1, 'POSTGRES_PASSWORD cannot be empty'), + POSTGRES_DB: z.string().min(1, 'POSTGRES_DB cannot be empty'), + POSTGRES_HOST: z.string().min(1, 'POSTGRES_HOST cannot be empty'), POSTGRES_PORT: z.coerce.number().optional().default(5432), - POSTGRES_SCHEMA: z.string(), + POSTGRES_SCHEMA: z.string().min(1, 'POSTGRES_SCHEMA cannot be empty'), }); export type Env = z.infer; diff --git a/libs/core-rest-api/adapters/src/events(to-do)/repositories.module.ts b/libs/core-rest-api/adapters/src/events(to-do)/repositories.module.ts deleted file mode 100644 index e69de29..0000000 diff --git a/libs/core-rest-api/adapters/tests/factories/make-psychologist.ts b/libs/core-rest-api/adapters/tests/factories/make-psychologist.ts index 8040de3..b621b54 100644 --- a/libs/core-rest-api/adapters/tests/factories/make-psychologist.ts +++ b/libs/core-rest-api/adapters/tests/factories/make-psychologist.ts @@ -36,7 +36,7 @@ export class PsychologistFactory { constructor(private postgreSqlPrismaOrmService: PostgreSqlPrismaOrmService) {} async makePrismaPsychologist( - psychologist: CreatePsychologistDto + psychologist: Partial = {} ): Promise { const newPrismaPsychologist = makePsychologist(psychologist); diff --git a/libs/core-rest-api/adapters/tsconfig.lib.json b/libs/core-rest-api/adapters/tsconfig.lib.json index 46cbaf4..3fe47bd 100644 --- a/libs/core-rest-api/adapters/tsconfig.lib.json +++ b/libs/core-rest-api/adapters/tsconfig.lib.json @@ -2,7 +2,6 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "../../../dist/out-tsc", - "declaration": true, "types": ["node"], "target": "es2021", "strictNullChecks": true, diff --git a/libs/core-rest-api/core/ajest.config.ts b/libs/core-rest-api/core/ajest.config.ts deleted file mode 100644 index e90d3b0..0000000 --- a/libs/core-rest-api/core/ajest.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'core-rest-api-core', - preset: '../../../jest.preset.js', - testEnvironment: 'node', - transform: { - '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], - }, - moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '../../../coverage/libs/core-rest-api/core', -}; diff --git a/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist-dto.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist-dto.ts new file mode 100644 index 0000000..2ace65a --- /dev/null +++ b/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist-dto.ts @@ -0,0 +1,9 @@ +import { IsString } from 'class-validator'; + +export class AuthenticatePsychologistDto { + @IsString() + email!: string; + + @IsString() + password!: string; +} diff --git a/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist.service.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist.service.ts new file mode 100644 index 0000000..35273bc --- /dev/null +++ b/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist.service.ts @@ -0,0 +1,38 @@ +import { PSYCHOLOGIST_ERROR_MESSAGES } from '@clinicControl/core-rest-api/core/src/shared/errors/error-messages'; +import { UnauthorizedException } from '@nestjs/common'; +import { BcryptHasherService } from '../../../../shared/cryptography/use-cases/bcrypt-hasher.service'; +import { PsychologistEntity } from '../../entities/psychologist/entity'; +import { PsychologistDatabaseRepository } from '../../repositories/database-repository'; +import { AuthenticatePsychologistDto } from './authenticate-psychologist-dto'; + +export class AuthenticatePsychologistService { + private hasherService: BcryptHasherService = new BcryptHasherService(); + + constructor(private psychologistDatabaseRepository: PsychologistDatabaseRepository) {} + + async execute( + psychologistLoginDto: AuthenticatePsychologistDto + ): Promise { + const psychologist = + await this.psychologistDatabaseRepository.findPsychologistByEmail( + psychologistLoginDto.email + ); + + if (!psychologist) { + throw new UnauthorizedException( + PSYCHOLOGIST_ERROR_MESSAGES['PSYCHOLOGIST_NOT_FOUND'] + ); + } + + const isPasswordValid = await this.hasherService.compare( + psychologistLoginDto.password, + psychologist.password + ); + + if (!isPasswordValid) { + throw new UnauthorizedException(PSYCHOLOGIST_ERROR_MESSAGES['INVALID_CREDENTIALS']); + } + + return psychologist; + } +} diff --git a/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist.spec.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist.spec.ts new file mode 100644 index 0000000..b52a391 --- /dev/null +++ b/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist.spec.ts @@ -0,0 +1,53 @@ +import { fakerPT_BR as faker } from '@faker-js/faker'; + +import { PSYCHOLOGIST_ERROR_MESSAGES } from '@clinicControl/core-rest-api/core/src/shared/errors/error-messages'; +import { ConflictException } from '@nestjs/common'; +import { Plan, Role } from '../../../../shared/interfaces/payments'; +import { InMemoryPsychologistDatabaseRepository } from '../../repositories/database-in-memory-repository'; +import { PsychologistDatabaseRepository } from '../../repositories/database-repository'; +import { CreatePsychologistService } from '../create-psychologist/create-psychologist.service'; +import { AuthenticatePsychologistService } from './authenticate-psychologist.service'; + +describe('teste', () => { + const fakePsychologist = { + name: faker.person.fullName(), + email: faker.internet.email(), + password: faker.internet.password({ length: 8 }), + role: Role.PSYCHOLOGIST, + plan: Plan.PREMIUM, + }; + + let createPsychologistService: CreatePsychologistService; + let loginService: AuthenticatePsychologistService; + let databaseRepository: PsychologistDatabaseRepository; + + beforeEach(async () => { + databaseRepository = new InMemoryPsychologistDatabaseRepository(); + createPsychologistService = new CreatePsychologistService(databaseRepository); + loginService = new AuthenticatePsychologistService(databaseRepository); + + await createPsychologistService.execute(fakePsychologist); + }); + + it('should throw an error if psychologist not exist in database', async () => { + const loginCredentials = { + email: 'fake@email.com', + password: fakePsychologist.password, + }; + + await expect(loginService.execute(loginCredentials)).rejects.toThrow( + new ConflictException(PSYCHOLOGIST_ERROR_MESSAGES['PSYCHOLOGIST_NOT_FOUND']) + ); + }); + + it('should throw an error if password is invalid', async () => { + const loginCredentials = { + email: fakePsychologist.email, + password: faker.internet.password({ length: 5 }), + }; + + await expect(loginService.execute(loginCredentials)).rejects.toThrow( + new ConflictException(PSYCHOLOGIST_ERROR_MESSAGES['INVALID_CREDENTIALS']) + ); + }); +}); diff --git a/libs/core-rest-api/core/src/domains/psychologist/use-cases/create-psychologist/create-psychologist.service.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/create-psychologist/create-psychologist.service.ts index f7ab978..493a630 100644 --- a/libs/core-rest-api/core/src/domains/psychologist/use-cases/create-psychologist/create-psychologist.service.ts +++ b/libs/core-rest-api/core/src/domains/psychologist/use-cases/create-psychologist/create-psychologist.service.ts @@ -1,5 +1,6 @@ import { ConflictException } from '@nestjs/common'; import { plainToInstance } from 'class-transformer'; +import { BcryptHasherService } from '../../../../shared/cryptography/use-cases/bcrypt-hasher.service'; import { PSYCHOLOGIST_ERROR_MESSAGES } from '../../../../shared/errors/error-messages'; import { applicationValidateOrReject } from '../../../../shared/validators/validate-or-reject'; import { PsychologistEntity } from '../../entities/psychologist/entity'; @@ -8,9 +9,9 @@ import { PsychologistDatabaseRepository } from '../../repositories/database-repo import { CreatePsychologistDto } from './create-psychologist-dto'; export class CreatePsychologistService { - constructor( - private psychologistDatabaseRepository: PsychologistDatabaseRepository - ) {} + private hasherService: BcryptHasherService = new BcryptHasherService(); + + constructor(private psychologistDatabaseRepository: PsychologistDatabaseRepository) {} async execute( createPsychologistDto: ICreatePsychologistServiceProps @@ -33,11 +34,13 @@ export class CreatePsychologistService { ); } + const hashedPassword = await this.hasherService.hash(createPsychologistDto.password); + // Create - const psychologist = - await this.psychologistDatabaseRepository.createPsychologist( - createPsychologistDto - ); + const psychologist = await this.psychologistDatabaseRepository.createPsychologist({ + ...createPsychologistDto, + password: hashedPassword, + }); return psychologist; } diff --git a/libs/core-rest-api/core/src/shared/cryptography/encrypter.ts b/libs/core-rest-api/core/src/shared/cryptography/repository/encrypter-repository.ts similarity index 100% rename from libs/core-rest-api/core/src/shared/cryptography/encrypter.ts rename to libs/core-rest-api/core/src/shared/cryptography/repository/encrypter-repository.ts diff --git a/libs/core-rest-api/core/src/shared/cryptography/hash-comparer.ts b/libs/core-rest-api/core/src/shared/cryptography/repository/hash-comparer-repository.ts similarity index 100% rename from libs/core-rest-api/core/src/shared/cryptography/hash-comparer.ts rename to libs/core-rest-api/core/src/shared/cryptography/repository/hash-comparer-repository.ts diff --git a/libs/core-rest-api/core/src/shared/cryptography/hash-generator.ts b/libs/core-rest-api/core/src/shared/cryptography/repository/hash-generator-repository.ts similarity index 100% rename from libs/core-rest-api/core/src/shared/cryptography/hash-generator.ts rename to libs/core-rest-api/core/src/shared/cryptography/repository/hash-generator-repository.ts diff --git a/libs/core-rest-api/core/src/shared/cryptography/use-cases/bcrypt-hasher.service.ts b/libs/core-rest-api/core/src/shared/cryptography/use-cases/bcrypt-hasher.service.ts new file mode 100644 index 0000000..191fa73 --- /dev/null +++ b/libs/core-rest-api/core/src/shared/cryptography/use-cases/bcrypt-hasher.service.ts @@ -0,0 +1,15 @@ +import { compare, hash } from 'bcryptjs'; +import { HashComparer } from '../repository/hash-comparer-repository'; +import { HashGenerator } from '../repository/hash-generator-repository'; + +export class BcryptHasherService implements HashGenerator, HashComparer { + private HASH_SALT_LENGTH = 8; + + hash(plain: string): Promise { + return hash(plain, this.HASH_SALT_LENGTH); + } + + compare(plain: string, hash: string): Promise { + return compare(plain, hash); + } +} diff --git a/libs/core-rest-api/core/src/shared/cryptography/use-cases/jwt-encrypter.service.ts b/libs/core-rest-api/core/src/shared/cryptography/use-cases/jwt-encrypter.service.ts new file mode 100644 index 0000000..a224507 --- /dev/null +++ b/libs/core-rest-api/core/src/shared/cryptography/use-cases/jwt-encrypter.service.ts @@ -0,0 +1,10 @@ +import { JwtService } from '@nestjs/jwt'; +import { Encrypter } from '../encrypter'; + +export class JwtEncrypterService implements Encrypter { + constructor(private jwtService: JwtService) {} + + encrypt(payload: Record): Promise { + return this.jwtService.signAsync(payload); + } +} diff --git a/libs/core-rest-api/core/src/shared/errors/error-messages.ts b/libs/core-rest-api/core/src/shared/errors/error-messages.ts index 89559fd..29fb23d 100644 --- a/libs/core-rest-api/core/src/shared/errors/error-messages.ts +++ b/libs/core-rest-api/core/src/shared/errors/error-messages.ts @@ -3,6 +3,7 @@ export const PSYCHOLOGIST_ERROR_MESSAGES = { INVALID_EMAIL: 'email must be an email', PSYCHOLOGIST_NOT_FOUND: 'psychologist not found', PSYCHOLOGIST_ALREADY_EXISTS: 'psychologist already exists', + INVALID_CREDENTIALS: 'invalid credentials', }; export const CLINIC_ERROR_MESSAGES = { diff --git a/libs/core-rest-api/core/tsconfig.lib.json b/libs/core-rest-api/core/tsconfig.lib.json index 1103067..e696c8e 100644 --- a/libs/core-rest-api/core/tsconfig.lib.json +++ b/libs/core-rest-api/core/tsconfig.lib.json @@ -2,7 +2,6 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "../../../dist/out-tsc", - "declaration": true, "types": ["node"], "target": "es2021", "strictNullChecks": true, diff --git a/package.json b/package.json index 9afec6d..73bb652 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,10 @@ "prisma:core:schema:validate": "prisma validate --schema=./libs/core-rest-api/adapters/src/database/infra/prisma/postgresql.schema.prisma", "prisma:core:schema:migrate": "prisma migrate dev --schema=./libs/core-rest-api/adapters/src/database/infra/prisma/postgresql.schema.prisma", "prisma:core:schema:generate": "prisma generate --schema=./libs/core-rest-api/adapters/src/database/infra/prisma/postgresql.schema.prisma", - "prisma:core:schema:studio": "prisma studio --schema=./libs/core-rest-api/adapters/src/database/infra/prisma/postgresql.schema.prisma" + "prisma:core:schema:studio": "prisma studio --schema=./libs/core-rest-api/adapters/src/database/infra/prisma/postgresql.schema.prisma", + "core-setup": "bash ./scripts/setup/core-rest-api/run-setup.sh", + "core-prisma-setup": "bash ./scripts/setup/core-rest-api/run-prisma-setup.sh", + "core-docker-compose": "bash ./scripts/setup/core-rest-api/docker-compose-control.sh" }, "private": true, "dependencies": { diff --git a/scripts/setup/core-rest-api/docker-compose-control.sh b/scripts/setup/core-rest-api/docker-compose-control.sh new file mode 100644 index 0000000..dd80279 --- /dev/null +++ b/scripts/setup/core-rest-api/docker-compose-control.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Analisamos todos os argumentos fornecidos +for arg in "$@"; do + if [[ $arg == --action=* ]]; then + # Extraímos o valor depois de '=' e substituímos as vírgulas por espaços + ACTIONS="${arg#*=}" + # Converta a string delimitada por vírgulas em um array + IFS=',' read -ra ACTIONS_ARRAY <<< "$ACTIONS" + shift + fi +done + +echo "Iniciando o docker-compose..." + +# Verificamos e executamos as ações em ordem +for action in "${ACTIONS_ARRAY[@]}"; do + if [ "$action" == "up" ]; then + docker compose -f "$PWD/docker-compose.yaml" up -d + elif [ "$action" == "down" ]; then + docker compose -f "$PWD/docker-compose.yaml" down -v + elif [ "$action" == "stop" ]; then + docker compose -f "$PWD/docker-compose.yaml" stop + elif [ "$action" == "restart" ]; then + docker compose -f "$PWD/docker-compose.yaml" restart + else + echo "Ação desconhecida: $action" + fi +done + +echo "Ações executadas com sucesso." diff --git a/scripts/setup/core-rest-api/run-prisma-setup.sh b/scripts/setup/core-rest-api/run-prisma-setup.sh new file mode 100644 index 0000000..faee02e --- /dev/null +++ b/scripts/setup/core-rest-api/run-prisma-setup.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +SCHEMA_PATH="./libs/core-rest-api/adapters/src/database/infra/prisma/postgresql.schema.prisma" + +# Analisamos todos os argumentos fornecidos +for arg in "$@"; do + case $arg in + --action=*) + # Extraímos o valor depois de '=' e substituímos as vírgulas por espaços + ACTIONS="${arg#*=}" + # Converta a string delimitada por vírgulas em um array + IFS=',' read -ra ACTIONS_ARRAY <<< "$ACTIONS" + shift + ;; + esac +done + +# Verificamos e executamos as ações em ordem: migrate e depois generate +for action in "${ACTIONS_ARRAY[@]}"; do + if [ "$action" == "migrate" ]; then + pnpm exec prisma migrate dev --schema=$SCHEMA_PATH + elif [ "$action" == "generate" ]; then + pnpm exec prisma generate --schema=$SCHEMA_PATH + elif [ "$action" == "studio" ]; then + pnpm exec prisma studio --schema=$SCHEMA_PATH + elif [ "$action" == "validate" ]; then + pnpm exec prisma validate --schema=$SCHEMA_PATH + else + echo "Ação desconhecida: $action" + fi +done diff --git a/scripts/setup/core-rest-api/run-setup.sh b/scripts/setup/core-rest-api/run-setup.sh new file mode 100644 index 0000000..cb8a83b --- /dev/null +++ b/scripts/setup/core-rest-api/run-setup.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Subir o docker-compose +echo "Subindo docker-compose..." +docker compose -f "$PWD/docker-compose.yaml" up -d # rodar script sempre da raiz do projeto + +# Verificar se o docker-compose subiu corretamente +if [ $? -ne 0 ]; then + echo "Erro ao subir o docker-compose." + exit 1 +fi + +# Dê algum tempo para que os serviços do docker-compose estejam prontos (se necessário) +sleep 10 + +# Rodar o script core-prisma-setup com os parâmetros passados +echo "Executando run-prisma-setup..." + +bash "$(dirname "$0")/run-prisma-setup.sh" "$@" + +# Verificar se o core-prisma-setup rodou corretamente +if [ $? -ne 0 ]; then + echo "Erro ao executar core-prisma-setup." + exit 1 +fi + +echo "Finalizado." diff --git a/tsconfig.base.json b/tsconfig.base.json index ec608a5..4be574a 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -3,7 +3,6 @@ "compilerOptions": { "rootDir": ".", "sourceMap": true, - "declaration": false, "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true,