From 03edfd21e011d2e640fc44c5c40161c2bbbbb7eb Mon Sep 17 00:00:00 2001 From: italo Date: Wed, 25 Oct 2023 13:53:34 -0300 Subject: [PATCH 01/10] config(CC-88): config setup bash scripts --- .../setup/core-rest-api/core-prisma-setup.sh | 42 +++++++++++++++++++ .../core-rest-api/docker-compose-control.sh | 29 +++++++++++++ scripts/setup/core-rest-api/run-setup.sh | 26 ++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 scripts/setup/core-rest-api/core-prisma-setup.sh create mode 100644 scripts/setup/core-rest-api/docker-compose-control.sh create mode 100644 scripts/setup/core-rest-api/run-setup.sh diff --git a/scripts/setup/core-rest-api/core-prisma-setup.sh b/scripts/setup/core-rest-api/core-prisma-setup.sh new file mode 100644 index 0000000..da908cc --- /dev/null +++ b/scripts/setup/core-rest-api/core-prisma-setup.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +SCHEMA_PATH="./libs/core-rest-api/adapters/src/database/infra/prisma/postgresql.schema.prisma" + +# Função para executar comandos e manipular erros +execute_command() { + $@ + STATUS=$? + + if [ $STATUS -ne 0 ]; then + echo "Erro ao executar: $@" + exit $STATUS + fi +} + +# 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/docker-compose-control.sh b/scripts/setup/core-rest-api/docker-compose-control.sh new file mode 100644 index 0000000..c099dbc --- /dev/null +++ b/scripts/setup/core-rest-api/docker-compose-control.sh @@ -0,0 +1,29 @@ +#!/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 + +# 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-setup.sh b/scripts/setup/core-rest-api/run-setup.sh new file mode 100644 index 0000000..e3a87ca --- /dev/null +++ b/scripts/setup/core-rest-api/run-setup.sh @@ -0,0 +1,26 @@ +#!/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 core-prisma-setup..." +./core-prisma-setup "$@" + +# Verificar se o core-prisma-setup rodou corretamente +if [ $? -ne 0 ]; then + echo "Erro ao executar core-prisma-setup." + exit 1 +fi + +echo "Finalizado." From 7d757bdeae4d35851901faa672f926c68798e2d8 Mon Sep 17 00:00:00 2001 From: italo Date: Wed, 25 Oct 2023 13:55:31 -0300 Subject: [PATCH 02/10] adjust(CC-88): initial setu of login endpoint --- .vscode/settings.json | 1 + .../src/controllers/api/api.module.ts | 4 +-- .../create-psychologist/client.http | 0 .../create-psychologist.controller.ts | 6 ++-- .../create-psychologist.e2e-spec.ts | 6 ++-- .../create-psychologist/docs.ts | 0 .../nestjs-create-psychologist.service.ts | 0 .../psychologist-login/client.http | 0 .../psychologist/psychologist-login/docs.ts | 0 .../nestjs-psychologist-login.service.ts | 0 .../psychologist-login.controller.ts | 0 .../psychologist-login.e2e-spec.ts | 3 ++ .../psychologist-login-dto.ts | 9 +++++ .../psychologist-login.service.ts | 33 +++++++++++++++++++ .../psychologist-login.spec.ts | 5 +++ .../repository/hash-comparer-repository.ts | 3 ++ .../repository/hash-generator-repository.ts | 3 ++ .../use-cases/bcrypt-hasher.service.ts | 15 +++++++++ .../core/src/shared/errors/error-messages.ts | 1 + 19 files changed, 80 insertions(+), 9 deletions(-) rename libs/core-rest-api/adapters/src/controllers/api/use-case/{ => psychologist}/create-psychologist/client.http (100%) rename libs/core-rest-api/adapters/src/controllers/api/use-case/{ => psychologist}/create-psychologist/create-psychologist.controller.ts (89%) rename libs/core-rest-api/adapters/src/controllers/api/use-case/{ => psychologist}/create-psychologist/create-psychologist.e2e-spec.ts (91%) rename libs/core-rest-api/adapters/src/controllers/api/use-case/{ => psychologist}/create-psychologist/docs.ts (100%) rename libs/core-rest-api/adapters/src/controllers/api/use-case/{ => psychologist}/create-psychologist/nestjs-create-psychologist.service.ts (100%) create mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/client.http create mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/docs.ts create mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/nestjs-psychologist-login.service.ts create mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.controller.ts create mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.e2e-spec.ts create mode 100644 libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login-dto.ts create mode 100644 libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.service.ts create mode 100644 libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.spec.ts create mode 100644 libs/core-rest-api/core/src/shared/cryptography/repository/hash-comparer-repository.ts create mode 100644 libs/core-rest-api/core/src/shared/cryptography/repository/hash-generator-repository.ts create mode 100644 libs/core-rest-api/core/src/shared/cryptography/use-cases/bcrypt-hasher.service.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 0e24cc5..71dbff3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,6 +16,7 @@ "CQRS", "github", "GITHUB", + "Hasher", "instanceof", "italo", "keyof", 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..930da1a 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 @@ -6,8 +6,8 @@ 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 { CreatePsychologistController } from './use-case/psychologist/create-psychologist/create-psychologist.controller'; +import { NestjsCreatePsychologistService } from './use-case/psychologist/create-psychologist/nestjs-create-psychologist.service'; @Module({ imports: [ 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-case/psychologist/create-psychologist/client.http similarity index 100% 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-case/psychologist/create-psychologist/client.http 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-case/psychologist/create-psychologist/create-psychologist.controller.ts similarity index 89% 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-case/psychologist/create-psychologist/create-psychologist.controller.ts index 7215d05..52029b1 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-case/psychologist/create-psychologist/create-psychologist.controller.ts @@ -5,7 +5,7 @@ import { applicationValidateOrReject } from '@clinicControl/core-rest-api/core/s 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,9 +13,7 @@ import { NestjsCreatePsychologistService } from './nestjs-create-psychologist.se path: 'psychologist', }) export class CreatePsychologistController { - constructor( - private createPsychologistService: NestjsCreatePsychologistService - ) {} + constructor(private createPsychologistService: NestjsCreatePsychologistService) {} @Post('create') @UseGuards(ApiKeyGuard) 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-case/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-case/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-case/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/api/use-case/create-psychologist/docs.ts b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/create-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-case/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-case/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-case/psychologist/create-psychologist/nestjs-create-psychologist.service.ts diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/client.http b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/client.http new file mode 100644 index 0000000..e69de29 diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/docs.ts b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/docs.ts new file mode 100644 index 0000000..e69de29 diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/nestjs-psychologist-login.service.ts b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/nestjs-psychologist-login.service.ts new file mode 100644 index 0000000..e69de29 diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.controller.ts b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.controller.ts new file mode 100644 index 0000000..e69de29 diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.e2e-spec.ts b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.e2e-spec.ts new file mode 100644 index 0000000..9294852 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.e2e-spec.ts @@ -0,0 +1,3 @@ +it('teste', { + expect(true).toBe(true) +}) diff --git a/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login-dto.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login-dto.ts new file mode 100644 index 0000000..220acd1 --- /dev/null +++ b/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login-dto.ts @@ -0,0 +1,9 @@ +import { IsString } from 'class-validator'; + +export class PsychologistLoginInfoDto { + @IsString() + email!: string; + + @IsString() + password!: string; +} diff --git a/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.service.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.service.ts new file mode 100644 index 0000000..e7cf83f --- /dev/null +++ b/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.service.ts @@ -0,0 +1,33 @@ +import { PSYCHOLOGIST_ERROR_MESSAGES } from '@clinicControl/core-rest-api/core/src/shared/errors/error-messages'; +import { ConflictException } from '@nestjs/common'; +import { PsychologistEntity } from '../../entities/psychologist/entity'; +import { PsychologistDatabaseRepository } from '../../repositories/database-repository'; +import { PsychologistLoginInfoDto } from './psychologist-login-dto'; + +export class PsychologistLoginService { + constructor(private psychologistDatabaseRepository: PsychologistDatabaseRepository) {} + + async execute( + psychologistLoginDto: PsychologistLoginInfoDto + ): Promise { + const psychologist = + await this.psychologistDatabaseRepository.findPsychologistByEmail( + psychologistLoginDto.email + ); + + // Validate + if (!psychologist) { + throw new ConflictException(PSYCHOLOGIST_ERROR_MESSAGES['PSYCHOLOGIST_NOT_FOUND']); + } + + const comparePassword = + + // if (psychologist.password !== psychologistLoginDto.password) { + // throw new ConflictException(PSYCHOLOGIST_ERROR_MESSAGES['INVALID_CREDENTIALS']); + // } + + + + return psychologist; + } +} diff --git a/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.spec.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.spec.ts new file mode 100644 index 0000000..f4d0f26 --- /dev/null +++ b/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.spec.ts @@ -0,0 +1,5 @@ +describe('teste', () => { + it('teste', () => { + expect(true).toBe(true); + }); +}); diff --git a/libs/core-rest-api/core/src/shared/cryptography/repository/hash-comparer-repository.ts b/libs/core-rest-api/core/src/shared/cryptography/repository/hash-comparer-repository.ts new file mode 100644 index 0000000..9187002 --- /dev/null +++ b/libs/core-rest-api/core/src/shared/cryptography/repository/hash-comparer-repository.ts @@ -0,0 +1,3 @@ +export abstract class HashComparer { + abstract compare(plain: string, hash: string): Promise; +} diff --git a/libs/core-rest-api/core/src/shared/cryptography/repository/hash-generator-repository.ts b/libs/core-rest-api/core/src/shared/cryptography/repository/hash-generator-repository.ts new file mode 100644 index 0000000..77fff52 --- /dev/null +++ b/libs/core-rest-api/core/src/shared/cryptography/repository/hash-generator-repository.ts @@ -0,0 +1,3 @@ +export abstract class HashGenerator { + abstract hash(plain: string): Promise; +} 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/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 = { From 4e1961470f0e9bb355fda4335f2670da11f25c40 Mon Sep 17 00:00:00 2001 From: Italo Amaral Date: Fri, 27 Oct 2023 15:13:05 -0300 Subject: [PATCH 03/10] config(CC-88): project config, set up bash scripts config --- .vscode/settings.json | 3 ++ libs/core-rest-api/adapters/tsconfig.lib.json | 1 - libs/core-rest-api/core/tsconfig.lib.json | 1 - package.json | 5 ++- .../core-rest-api/docker-compose-control.sh | 2 ++ .../setup/core-rest-api/run-prisma-setup.sh | 31 +++++++++++++++++++ scripts/setup/core-rest-api/run-setup.sh | 7 +++-- tsconfig.base.json | 1 - 8 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 scripts/setup/core-rest-api/run-prisma-setup.sh diff --git a/.vscode/settings.json b/.vscode/settings.json index 71dbff3..3ab69b2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,8 +14,11 @@ "commitlint", "conventionalcommits", "CQRS", + "encrypter", + "Encrypter", "github", "GITHUB", + "hasher", "Hasher", "instanceof", "italo", 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/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 index c099dbc..dd80279 100644 --- a/scripts/setup/core-rest-api/docker-compose-control.sh +++ b/scripts/setup/core-rest-api/docker-compose-control.sh @@ -11,6 +11,8 @@ for arg in "$@"; do 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 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 index e3a87ca..cf06bde 100644 --- a/scripts/setup/core-rest-api/run-setup.sh +++ b/scripts/setup/core-rest-api/run-setup.sh @@ -11,11 +11,12 @@ if [ $? -ne 0 ]; then fi # Dê algum tempo para que os serviços do docker-compose estejam prontos (se necessário) -sleep 10 +# sleep 10 # Rodar o script core-prisma-setup com os parâmetros passados -echo "Executando core-prisma-setup..." -./core-prisma-setup "$@" +echo "Executando run-prisma-setup..." + +bash "$(dirname "$0")/run-prisma-setup.sh" "$@" # Verificar se o core-prisma-setup rodou corretamente if [ $? -ne 0 ]; then 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, From 76566aa0dc94afa0307ed81966e88e4b4dbbfb3a Mon Sep 17 00:00:00 2001 From: Italo Amaral Date: Fri, 27 Oct 2023 15:13:53 -0300 Subject: [PATCH 04/10] ci(CC-88): updated tests-pipeline with new setup scripts --- .github/workflows/tests-pipeline.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) 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 From d96accba6db3c349648a1081788e18ea344b77b4 Mon Sep 17 00:00:00 2001 From: Italo Amaral Date: Fri, 27 Oct 2023 15:14:43 -0300 Subject: [PATCH 05/10] feat(CC-88): created authenticate endpoint --- .../adapters/src/auth/auth.module.ts | 31 +++++--- .../adapters/src/auth/jwt-auth.guard.ts | 34 ++++++++- .../adapters/src/auth/jwt.strategy.ts | 24 +++--- .../core-rest-api/adapters/src/auth/public.ts | 4 + .../src/controllers/api/api.module.ts | 25 +++++-- .../api/decorators/current-user.decorator.ts | 18 +++++ .../psychologist-login/client.http | 0 .../nestjs-psychologist-login.service.ts | 0 .../psychologist-login.controller.ts | 0 .../psychologist-login.e2e-spec.ts | 3 - .../authenticate-psychologist}/docs.ts | 0 ...estjs-authenticate-psychologist.service.ts | 10 +++ .../psychologist-login.controller.ts | 36 +++++++++ .../psychologist-login.e2e-spec.ts | 75 +++++++++++++++++++ .../create-psychologist.controller.ts | 2 + .../create-psychologist.e2e-spec.ts | 0 .../psychologist/create-psychologist}/docs.ts | 0 .../nestjs-create-psychologist.service.ts | 0 .../psychologist/psychologist-client.http} | 11 +-- .../consumers(to-do)/consumers.controller.ts | 0 .../consumers(to-do)/consumers.module.ts | 0 .../src/cryptography/bcrypt-hasher.ts | 16 ---- .../src/cryptography/cryptography.module.ts | 13 +--- .../src/cryptography/jwt-encrypter.ts | 2 +- .../postgresql-prisma-orm-repository.ts | 14 +--- .../repositories/repositories.module.ts | 3 +- .../src/events(to-do)/repositories.module.ts | 0 .../tests/factories/make-psychologist.ts | 2 +- libs/core-rest-api/core/ajest.config.ts | 11 --- .../authenticate-psychologist-dto.ts} | 2 +- .../authenticate-psychologist.service.ts | 38 ++++++++++ .../authenticate-psychologist.spec.ts | 53 +++++++++++++ .../create-psychologist.service.ts | 17 +++-- .../psychologist-login.service.ts | 33 -------- .../psychologist-login.spec.ts | 5 -- .../src/shared/cryptography/hash-comparer.ts | 3 - .../src/shared/cryptography/hash-generator.ts | 3 - .../encrypter-repository.ts} | 0 .../use-cases/jwt-encrypter.service.ts | 10 +++ .../setup/core-rest-api/core-prisma-setup.sh | 42 ----------- 40 files changed, 353 insertions(+), 187 deletions(-) create mode 100644 libs/core-rest-api/adapters/src/auth/public.ts create mode 100644 libs/core-rest-api/adapters/src/controllers/api/decorators/current-user.decorator.ts delete mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/client.http delete mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/nestjs-psychologist-login.service.ts delete mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.controller.ts delete mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.e2e-spec.ts rename libs/core-rest-api/adapters/src/controllers/api/{use-case/psychologist/create-psychologist => use-cases/psychologist/authenticate-psychologist}/docs.ts (100%) create mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/nestjs-authenticate-psychologist.service.ts create mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.controller.ts create mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.e2e-spec.ts rename libs/core-rest-api/adapters/src/controllers/api/{use-case => use-cases}/psychologist/create-psychologist/create-psychologist.controller.ts (94%) rename libs/core-rest-api/adapters/src/controllers/api/{use-case => use-cases}/psychologist/create-psychologist/create-psychologist.e2e-spec.ts (100%) rename libs/core-rest-api/adapters/src/controllers/api/{use-case/psychologist/psychologist-login => use-cases/psychologist/create-psychologist}/docs.ts (100%) rename libs/core-rest-api/adapters/src/controllers/api/{use-case => use-cases}/psychologist/create-psychologist/nestjs-create-psychologist.service.ts (100%) rename libs/core-rest-api/adapters/src/controllers/api/{use-case/psychologist/create-psychologist/client.http => use-cases/psychologist/psychologist-client.http} (83%) delete mode 100644 libs/core-rest-api/adapters/src/controllers/consumers(to-do)/consumers.controller.ts delete mode 100644 libs/core-rest-api/adapters/src/controllers/consumers(to-do)/consumers.module.ts delete mode 100644 libs/core-rest-api/adapters/src/cryptography/bcrypt-hasher.ts delete mode 100644 libs/core-rest-api/adapters/src/events(to-do)/repositories.module.ts delete mode 100644 libs/core-rest-api/core/ajest.config.ts rename libs/core-rest-api/core/src/domains/psychologist/use-cases/{psychologist-login/psychologist-login-dto.ts => authenticate-psychologist/authenticate-psychologist-dto.ts} (72%) create mode 100644 libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist.service.ts create mode 100644 libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist.spec.ts delete mode 100644 libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.service.ts delete mode 100644 libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.spec.ts delete mode 100644 libs/core-rest-api/core/src/shared/cryptography/hash-comparer.ts delete mode 100644 libs/core-rest-api/core/src/shared/cryptography/hash-generator.ts rename libs/core-rest-api/core/src/shared/cryptography/{encrypter.ts => repository/encrypter-repository.ts} (100%) create mode 100644 libs/core-rest-api/core/src/shared/cryptography/use-cases/jwt-encrypter.service.ts delete mode 100644 scripts/setup/core-rest-api/core-prisma-setup.sh 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 930da1a..b186508 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,29 @@ 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/psychologist/create-psychologist/create-psychologist.controller'; -import { NestjsCreatePsychologistService } from './use-case/psychologist/create-psychologist/nestjs-create-psychologist.service'; +import { PsychologistLoginController } from './use-cases/psychologist/authenticate-psychologist/psychologist-login.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, PsychologistLoginController], + 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-case/psychologist/psychologist-login/client.http b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/client.http deleted file mode 100644 index e69de29..0000000 diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/nestjs-psychologist-login.service.ts b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/nestjs-psychologist-login.service.ts deleted file mode 100644 index e69de29..0000000 diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.controller.ts b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.controller.ts deleted file mode 100644 index e69de29..0000000 diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.e2e-spec.ts b/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.e2e-spec.ts deleted file mode 100644 index 9294852..0000000 --- a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/psychologist-login.e2e-spec.ts +++ /dev/null @@ -1,3 +0,0 @@ -it('teste', { - expect(true).toBe(true) -}) diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/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/psychologist/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-cases/psychologist/authenticate-psychologist/psychologist-login.controller.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.controller.ts new file mode 100644 index 0000000..467558b --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.controller.ts @@ -0,0 +1,36 @@ +import { Public } from '@clinicControl/core-rest-api/adapters/src/auth/public'; +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 { Body, Controller, Post } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { NestjsAuthenticatePsychologistService } from './nestjs-authenticate-psychologist.service'; + +@ApiTags() +@Controller({ + path: 'psychologist', +}) +export class PsychologistLoginController { + 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 { 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/psychologist-login.e2e-spec.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.e2e-spec.ts new file mode 100644 index 0000000..ca4f309 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.e2e-spec.ts @@ -0,0 +1,75 @@ +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({ + 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: 'wrong_password', + }); + + 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-case/psychologist/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 94% rename from libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/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 52029b1..459c11c 100644 --- a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/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,4 +1,5 @@ // 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'; @@ -17,6 +18,7 @@ export class CreatePsychologistController { @Post('create') @UseGuards(ApiKeyGuard) + @Public() async execute( @Body() createPsychologistDto: CreatePsychologistDto ): Promise { diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/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 100% rename from libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/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 diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-case/psychologist/psychologist-login/docs.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/api/use-case/psychologist/psychologist-login/docs.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/psychologist/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/psychologist/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/psychologist/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/psychologist/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/psychologist/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.controller.ts b/libs/core-rest-api/adapters/src/controllers/consumers(to-do)/consumers.controller.ts deleted file mode 100644 index e69de29..0000000 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/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/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/psychologist-login/psychologist-login-dto.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist-dto.ts similarity index 72% rename from libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login-dto.ts rename to libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist-dto.ts index 220acd1..2ace65a 100644 --- a/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login-dto.ts +++ b/libs/core-rest-api/core/src/domains/psychologist/use-cases/authenticate-psychologist/authenticate-psychologist-dto.ts @@ -1,6 +1,6 @@ import { IsString } from 'class-validator'; -export class PsychologistLoginInfoDto { +export class AuthenticatePsychologistDto { @IsString() email!: 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..2bcda0d --- /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: 'invalidPassword', + }; + + 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/domains/psychologist/use-cases/psychologist-login/psychologist-login.service.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.service.ts deleted file mode 100644 index e7cf83f..0000000 --- a/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { PSYCHOLOGIST_ERROR_MESSAGES } from '@clinicControl/core-rest-api/core/src/shared/errors/error-messages'; -import { ConflictException } from '@nestjs/common'; -import { PsychologistEntity } from '../../entities/psychologist/entity'; -import { PsychologistDatabaseRepository } from '../../repositories/database-repository'; -import { PsychologistLoginInfoDto } from './psychologist-login-dto'; - -export class PsychologistLoginService { - constructor(private psychologistDatabaseRepository: PsychologistDatabaseRepository) {} - - async execute( - psychologistLoginDto: PsychologistLoginInfoDto - ): Promise { - const psychologist = - await this.psychologistDatabaseRepository.findPsychologistByEmail( - psychologistLoginDto.email - ); - - // Validate - if (!psychologist) { - throw new ConflictException(PSYCHOLOGIST_ERROR_MESSAGES['PSYCHOLOGIST_NOT_FOUND']); - } - - const comparePassword = - - // if (psychologist.password !== psychologistLoginDto.password) { - // throw new ConflictException(PSYCHOLOGIST_ERROR_MESSAGES['INVALID_CREDENTIALS']); - // } - - - - return psychologist; - } -} diff --git a/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.spec.ts b/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.spec.ts deleted file mode 100644 index f4d0f26..0000000 --- a/libs/core-rest-api/core/src/domains/psychologist/use-cases/psychologist-login/psychologist-login.spec.ts +++ /dev/null @@ -1,5 +0,0 @@ -describe('teste', () => { - it('teste', () => { - expect(true).toBe(true); - }); -}); diff --git a/libs/core-rest-api/core/src/shared/cryptography/hash-comparer.ts b/libs/core-rest-api/core/src/shared/cryptography/hash-comparer.ts deleted file mode 100644 index 9187002..0000000 --- a/libs/core-rest-api/core/src/shared/cryptography/hash-comparer.ts +++ /dev/null @@ -1,3 +0,0 @@ -export abstract class HashComparer { - abstract compare(plain: string, hash: string): Promise; -} diff --git a/libs/core-rest-api/core/src/shared/cryptography/hash-generator.ts b/libs/core-rest-api/core/src/shared/cryptography/hash-generator.ts deleted file mode 100644 index 77fff52..0000000 --- a/libs/core-rest-api/core/src/shared/cryptography/hash-generator.ts +++ /dev/null @@ -1,3 +0,0 @@ -export abstract class HashGenerator { - abstract hash(plain: string): Promise; -} 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/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/scripts/setup/core-rest-api/core-prisma-setup.sh b/scripts/setup/core-rest-api/core-prisma-setup.sh deleted file mode 100644 index da908cc..0000000 --- a/scripts/setup/core-rest-api/core-prisma-setup.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -SCHEMA_PATH="./libs/core-rest-api/adapters/src/database/infra/prisma/postgresql.schema.prisma" - -# Função para executar comandos e manipular erros -execute_command() { - $@ - STATUS=$? - - if [ $STATUS -ne 0 ]; then - echo "Erro ao executar: $@" - exit $STATUS - fi -} - -# 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 From bc5b513a173f7fb731f29ad5e0b076c56f1dc41a Mon Sep 17 00:00:00 2001 From: Italo Amaral Date: Fri, 27 Oct 2023 15:22:02 -0300 Subject: [PATCH 06/10] test(CC-88): fixing hotspot vulnerabilities by sonarcloud --- .../psychologist-login.e2e-spec.ts | 10 ++++++---- .../authenticate-psychologist.spec.ts | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.e2e-spec.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.e2e-spec.ts index ca4f309..6dcd0b7 100644 --- a/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.e2e-spec.ts +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.e2e-spec.ts @@ -54,10 +54,12 @@ describe('[E2E] - Authenticate Psychologist', () => { email: 'new_user_entrie@email.com', }); - const response = await request(app.getHttpServer()).post('/psychologist/login').send({ - email: newPsychologist.email, - password: 'wrong_password', - }); + const response = await request(app.getHttpServer()) + .post('/psychologist/login') + .send({ + email: newPsychologist.email, + password: faker.internet.password({ length: 3 }), + }); expect(response.statusCode).toBe(401); }); 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 index 2bcda0d..b52a391 100644 --- 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 @@ -43,7 +43,7 @@ describe('teste', () => { it('should throw an error if password is invalid', async () => { const loginCredentials = { email: fakePsychologist.email, - password: 'invalidPassword', + password: faker.internet.password({ length: 5 }), }; await expect(loginService.execute(loginCredentials)).rejects.toThrow( From e11e6a0ef7c8f7d85cc20350c93e74ecb2042d6a Mon Sep 17 00:00:00 2001 From: Italo Amaral Date: Fri, 27 Oct 2023 15:28:51 -0300 Subject: [PATCH 07/10] adjust(CC-88): minor code adjustments --- .../core-rest-api/adapters/src/controllers/api/api.module.ts | 5 +++-- ...controller.ts => authenticate-psychologist.controller.ts} | 2 +- ...gin.e2e-spec.ts => authenticate-psychologist.e2e-spec.ts} | 0 scripts/setup/core-rest-api/run-setup.sh | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) rename libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/{psychologist-login.controller.ts => authenticate-psychologist.controller.ts} (96%) rename libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/{psychologist-login.e2e-spec.ts => authenticate-psychologist.e2e-spec.ts} (100%) 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 b186508..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 @@ -7,7 +7,8 @@ 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 { PsychologistLoginController } from './use-cases/psychologist/authenticate-psychologist/psychologist-login.controller'; + +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'; @@ -24,7 +25,7 @@ import { NestjsCreatePsychologistService } from './use-cases/psychologist/create AuthModule, CryptographyModule, ], - controllers: [CreatePsychologistController, PsychologistLoginController], + controllers: [CreatePsychologistController, AuthenticatePsychologistController], providers: [ BcryptHasherService, PostgreSqlPrismaOrmService, diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.controller.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller.ts similarity index 96% rename from libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.controller.ts rename to libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller.ts index 467558b..db166f6 100644 --- a/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.controller.ts +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller.ts @@ -10,7 +10,7 @@ import { NestjsAuthenticatePsychologistService } from './nestjs-authenticate-psy @Controller({ path: 'psychologist', }) -export class PsychologistLoginController { +export class AuthenticatePsychologistController { constructor( private AuthenticatePsychologistService: NestjsAuthenticatePsychologistService, private jwtEncrypter: Encrypter diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.e2e-spec.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.e2e-spec.ts similarity index 100% rename from libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/psychologist-login.e2e-spec.ts rename to libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.e2e-spec.ts diff --git a/scripts/setup/core-rest-api/run-setup.sh b/scripts/setup/core-rest-api/run-setup.sh index cf06bde..cb8a83b 100644 --- a/scripts/setup/core-rest-api/run-setup.sh +++ b/scripts/setup/core-rest-api/run-setup.sh @@ -11,7 +11,7 @@ if [ $? -ne 0 ]; then fi # Dê algum tempo para que os serviços do docker-compose estejam prontos (se necessário) -# sleep 10 +sleep 10 # Rodar o script core-prisma-setup com os parâmetros passados echo "Executando run-prisma-setup..." From a2342acc52ed6ed357a729364b33dcc80c4c2c45 Mon Sep 17 00:00:00 2001 From: Italo Amaral Date: Sat, 28 Oct 2023 18:25:18 -0300 Subject: [PATCH 08/10] adjust(CC-88): added authenticate controller response interface --- .../authenticate-psychologist.controller.ts | 13 ++++++++----- .../authenticate-psychologist.interface.ts | 8 ++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 libs/core-rest-api/adapters/src/controllers/api/use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.interface.ts 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 index db166f6..2d313c9 100644 --- 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 @@ -1,9 +1,12 @@ -import { Public } from '@clinicControl/core-rest-api/adapters/src/auth/public'; +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 { Body, Controller, Post } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; + +import { Public } from '../../../../../auth/public'; +import { AuthenticatePsychologistControllerResponse } from './authenticate-psychologist.interface'; import { NestjsAuthenticatePsychologistService } from './nestjs-authenticate-psychologist.service'; @ApiTags() @@ -20,7 +23,7 @@ export class AuthenticatePsychologistController { @Public() async execute( @Body() psychologistLoginDto: AuthenticatePsychologistDto - ): Promise { + ): Promise { try { const { id, name, email } = await this.AuthenticatePsychologistService.execute( psychologistLoginDto @@ -28,7 +31,7 @@ export class AuthenticatePsychologistController { const access_token = await this.jwtEncrypter.encrypt({ id, name, email }); - return { id, name, email, access_token }; + 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.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; +} From 3020ce12f3fda187b4ac595f88f5463fa2ccb3dc Mon Sep 17 00:00:00 2001 From: Italo Amaral Date: Sat, 28 Oct 2023 21:50:40 -0300 Subject: [PATCH 09/10] test(CC-88): fixed authenticate controller e2e --- .../authenticate-psychologist.e2e-spec.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 index 6dcd0b7..3c6cbb2 100644 --- 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 @@ -40,9 +40,11 @@ describe('[E2E] - Authenticate Psychologist', () => { expect(response.statusCode).toBe(201); expect(response.body).toEqual({ - id: newPsychologist.id, - name: newPsychologist.name, - email: newPsychologist.email, + user: { + id: newPsychologist.id, + name: newPsychologist.name, + email: newPsychologist.email, + }, access_token: expect.any(String), }); }); From 9431813a2f6afe6d478353b44213ab172c155e30 Mon Sep 17 00:00:00 2001 From: italo Date: Fri, 3 Nov 2023 13:51:36 -0300 Subject: [PATCH 10/10] config(CC-88): envs var validation --- libs/core-rest-api/adapters/src/env/env.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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;