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 de4b0c3..61ce8ce 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 @@ -5,16 +5,18 @@ import { AuthModule } from '../../auth/auth.module'; import { CryptographyModule } from '../../cryptography/cryptography.module'; import { envSchema } from '../../env/env'; import { EnvModule } from '../../env/env.module'; +import { UpdatePsychologistController } from './use-cases/psychologist/update-psychologist/update-psychologist.controller'; import { BcryptHasherService } from '@clinicControl/core-rest-api/core/src/shared/cryptography/use-cases/bcrypt-hasher.service'; import { PostgreSqlPrismaOrmService } from '../../database/infra/prisma/prisma.service'; import { DatabaseRepositoriesModule } from '../../database/repositories/repositories.module'; -import { AuthenticatePsychologistController } from './use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller'; -import { CreatePsychologistController } from './use-cases/psychologist/create-psychologist/create-psychologist.controller'; -import { UpdatePsychologistController } from './use-cases/psychologist/update-psychologist/update-psychologist.controller'; +import { CreateClinicController } from './use-cases/clinic/create-clinic/create-clinic.controller'; +import { NestjsCreateClinicService } from './use-cases/clinic/create-clinic/nestjs-create-clinic.service'; +import { AuthenticatePsychologistController } from './use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller'; import { NestjsAuthenticatePsychologistService } from './use-cases/psychologist/authenticate-psychologist/nestjs-authenticate-psychologist.service'; +import { CreatePsychologistController } from './use-cases/psychologist/create-psychologist/create-psychologist.controller'; import { NestjsCreatePsychologistService } from './use-cases/psychologist/create-psychologist/nestjs-create-psychologist.service'; import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update-psychologist/nestjs-update-psychologist.service'; @@ -31,7 +33,7 @@ import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update ], controllers: [ CreatePsychologistController, - AuthenticatePsychologistController, + AuthenticatePsychologistController, CreateClinicController, UpdatePsychologistController, ], providers: [ @@ -40,6 +42,6 @@ import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update NestjsCreatePsychologistService, NestjsAuthenticatePsychologistService, NestjsUpdatePsychologistService, - ], + NestjsCreateClinicService], }) export class ApiModule {} diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/client.http b/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/client.http new file mode 100644 index 0000000..dac6373 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/client.http @@ -0,0 +1,26 @@ +@baseUrl = http://localhost:3333/core +@authToken = {{loginauthenticate.response.body.access_token}} + +# @name loginauthenticate +POST http://localhost:3333/core/psychologist/login HTTP/1.1 +Content-Type: application/json + +{ + "email": "novo_usuario_33@gmail.com", + "password": "01212012" +} + +#### + +# @name create_clinic + +POST http://localhost:3333/core/clinic/create HTTP/1.1 +Content-Type: application/json +Authorization: Bearer {{authToken}} + +{ + "name": "Nova Clínica", + "psychologistId": "2b99214d-6642-4aaf-a9c6-e54e53ad52d0", + "city": "Fake City", + "state": "Fake State" +} diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/create-clinic.controller.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/create-clinic.controller.ts new file mode 100644 index 0000000..ace442c --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/create-clinic.controller.ts @@ -0,0 +1,31 @@ +// eslint-disable-next-line @nx/enforce-module-boundaries +import { CreateClinicDto } from '@clinicControl/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic-dto'; +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 { NestjsCreateClinicService } from './nestjs-create-clinic.service'; + +interface createClinicResponse { + message: string +} +@ApiTags('Clinic') +@Controller({ + path: 'clinic', +}) +export class CreateClinicController { + constructor( + private createClinicService: NestjsCreateClinicService + ) {} + + @Post('create') + async execute( + @Body() createClinicDto: CreateClinicDto + ): Promise{ + try { + await this.createClinicService.execute(createClinicDto); + return {message: 'Clinic created successfully'} + } catch (error: unknown) { + throw new GlobalAppHttpException(error); + } + } +} diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/create-clinic.e2e-spec.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/create-clinic.e2e-spec.ts new file mode 100644 index 0000000..bc3ea85 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/create-clinic.e2e-spec.ts @@ -0,0 +1,118 @@ +import request from 'supertest'; + +import { INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; + +import { DatabaseRepositoriesModule } from '@clinicControl/core-rest-api/adapters/src/database/repositories/repositories.module'; +import { ClinicEntity } from '@clinicControl/core-rest-api/core/src/domains/clinic/entities/clinic/entity'; +import { PsychologistEntity } from '@clinicControl/core-rest-api/core/src/domains/psychologist/entities/psychologist/entity'; +import { BcryptHasherService } from '@clinicControl/core-rest-api/core/src/shared/cryptography/use-cases/bcrypt-hasher.service'; +import { makeClinic } from '@clinicControl/root/libs/core-rest-api/adapters/tests/factories/make-clinic'; +import { PsychologistFactory } from '@clinicControl/root/libs/core-rest-api/adapters/tests/factories/make-psychologist'; +import { faker } from '@faker-js/faker'; +import { JwtService } from '@nestjs/jwt'; +import { PostgreSqlPrismaOrmService } from '../../../../../database/infra/prisma/prisma.service'; +import { ApiModule } from '../../../api.module'; + +describe('[E2E] - Create Clinic', () => { + let prisma: PostgreSqlPrismaOrmService; + let app: INestApplication; + let psychologistFactory: PsychologistFactory; + let jwt: JwtService; + let psychologistId: string; + let access_token: string; + let invalid_access_token: string; + let psychologist: PsychologistEntity; + let password: string; + let clinic: ClinicEntity + + beforeAll(async () => { + const moduleRef = await Test.createTestingModule({ + imports: [ApiModule, DatabaseRepositoriesModule], + providers: [PsychologistFactory] + }).compile(); + + app = moduleRef.createNestApplication(); + + prisma = moduleRef.get(PostgreSqlPrismaOrmService); + psychologistFactory = moduleRef.get(PsychologistFactory); + jwt = moduleRef.get(JwtService); + + await app.init(); + + // hashing a static known password to use in tests + const bcrypt = new BcryptHasherService(); + password = faker.internet.password({ length: 8 }); + const hashedPassword = await bcrypt.hash(password); + + // creating a psychologist account to use in tests + psychologist = await psychologistFactory.makePrismaPsychologist({ + password: hashedPassword, + }); + + psychologistId = psychologist.id; + access_token = jwt.sign({ + id: psychologistId, + name: psychologist.name, + email: psychologist.email, + }); + + invalid_access_token = jwt.sign({ psychologistId }); + clinic = makeClinic(psychologistId); + }); + + it('[POST] - Should successfully create a new clinic', async () => { + const createdClinicResponse = await request(app.getHttpServer()) + .post('/clinic/create') + .set('Authorization', `Bearer ${access_token}`) + .send(clinic); + + expect(createdClinicResponse.statusCode).toBe(201); + expect(createdClinicResponse.body.message).toBe('Clinic created successfully'); + }); + + it('[POST] - Should unsuccessfully try to create a new clinic without token', async () => { + const newClinic = makeClinic(psychologistId); + + const createdClinicResponse = await request(app.getHttpServer()) + .post('/clinic/create') + .send(newClinic); + + expect(createdClinicResponse.statusCode).toBe(401); + expect(createdClinicResponse.body.message).toBe('Invalid JWT token'); + }); + + it('[POST] - Should unsuccessfully try to create a new clinic without body request', async () => { + const newClinic = makeClinic(psychologistId); + + const createdClinicResponse = await request(app.getHttpServer()) + .post('/clinic/create') + .set('Authorization', `Bearer ${access_token}`) + + expect(createdClinicResponse.statusCode).toBe(400); + + expect(createdClinicResponse.body.message).toBe('Validation failed'); + expect(createdClinicResponse.text).toBe('{"message":"Validation failed","causes":[{"property":"name","constraints":{"isString":"name must be a string"}},{"property":"psychologistId","constraints":{"isString":"psychologistId must be a string"}},{"property":"city","constraints":{"isString":"city must be a string"}},{"property":"state","constraints":{"isString":"state must be a string"}}]}'); + }); + + it('[POST] - Should unsuccessfully try to create a clinic that already exists', async () => { + const createdClinicResponse = await request(app.getHttpServer()) + .post('/clinic/create') + .set('Authorization', `Bearer ${access_token}`) + .send(clinic); + + expect(createdClinicResponse.statusCode).toBe(409); + expect(createdClinicResponse.body.message).toBe('clinic already exists'); + }); + + it('[POST] - Should unsuccessfully try to create a clinic with an invalid psychologist Id', async () => { + clinic = makeClinic('invalid-psychologist-id'); + const createdClinicResponse = await request(app.getHttpServer()) + .post('/clinic/create') + .set('Authorization', `Bearer ${access_token}`) + .send(clinic); + + expect(createdClinicResponse.statusCode).toBe(400); + expect(createdClinicResponse.body.message).contain("Invalid `this.postgreSqlPrismaOrmService['clinic'].create()`"); + }); +}); diff --git a/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/nestjs-create-clinic.service.ts b/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/nestjs-create-clinic.service.ts new file mode 100644 index 0000000..c85c3d7 --- /dev/null +++ b/libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/nestjs-create-clinic.service.ts @@ -0,0 +1,10 @@ +import { ClinicDatabaseRepository } from '@clinicControl/core-rest-api/core/src/domains/clinic/repositories/database-repository'; +import { CreateClinicService } from '@clinicControl/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic.service'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class NestjsCreateClinicService extends CreateClinicService { + constructor(clinicDatabaseRepository: ClinicDatabaseRepository) { + super(clinicDatabaseRepository); + } +} diff --git a/libs/core-rest-api/adapters/src/database/mappers/postgresql-prisma-clinic-mapper.ts b/libs/core-rest-api/adapters/src/database/mappers/postgresql-prisma-clinic-mapper.ts new file mode 100644 index 0000000..0e12b82 --- /dev/null +++ b/libs/core-rest-api/adapters/src/database/mappers/postgresql-prisma-clinic-mapper.ts @@ -0,0 +1,42 @@ +import { ClinicEntity } from '@clinicControl/core-rest-api/core/src/domains/clinic/entities/clinic/entity'; +import { CreateClinicDto } from '@clinicControl/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic-dto'; +import { UpdateClinicDto } from '@clinicControl/core-rest-api/core/src/domains/clinic/use-cases/update-clinic/update-clinic-dto'; +import { + Prisma, + Clinic as PrismaClinicDto, +} from '@prisma/client'; + +export class PostgresqlPrismaClinicMapper { + static toDomain(raw: PrismaClinicDto): ClinicEntity { + return new ClinicEntity({ + ...raw, + }); + } + + static toDomainMany(raw: PrismaClinicDto[]): ClinicEntity[] { + return raw.map((clinic) => this.toDomain(clinic)); + } + + static toPrismaCreate(raw: CreateClinicDto): Prisma.ClinicCreateArgs { + + return { + data: { + ...raw, + city: raw.city, + name: raw.name, + state: raw.state, + } + }; + } + + static toPrismaUpdate(raw: UpdateClinicDto): Prisma.ClinicUpdateArgs { + return { + data: { + ...raw, + }, + where: { + id: raw.id, + }, + }; + } +} diff --git a/libs/core-rest-api/adapters/src/database/repositories/clinic/postgres-prisma-orm-clinic-repository.ts b/libs/core-rest-api/adapters/src/database/repositories/clinic/postgres-prisma-orm-clinic-repository.ts new file mode 100644 index 0000000..78123aa --- /dev/null +++ b/libs/core-rest-api/adapters/src/database/repositories/clinic/postgres-prisma-orm-clinic-repository.ts @@ -0,0 +1,110 @@ +import { ClinicEntity } from '@clinicControl/core-rest-api/core/src/domains/clinic/entities/clinic/entity'; +import { ClinicDatabaseRepository } from '@clinicControl/core-rest-api/core/src/domains/clinic/repositories/database-repository'; +import { CreateClinicDto } from '@clinicControl/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic-dto'; +import { UpdateClinicDto } from '@clinicControl/core-rest-api/core/src/domains/clinic/use-cases/update-clinic/update-clinic-dto'; +import { CLINIC_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'; +import { PostgresqlPrismaClinicMapper } from '../../mappers/postgresql-prisma-clinic-mapper'; + +@Injectable() +export class PostgresqlPrismaOrmClinicRepository + implements ClinicDatabaseRepository +{ + constructor( + private postgreSqlPrismaOrmService: PostgreSqlPrismaOrmService, + ) {} + + async createClinic( + clinic: CreateClinicDto + ): Promise { + const isClinicExists = await this.findClinicByNameAndPsychologistId(clinic.name, clinic.psychologistId); + + if (isClinicExists) { + throw new ConflictException( + CLINIC_ERROR_MESSAGES['CONFLICTING_CREDENTIALS'] + ); + } + + const toPrismaEntity = PostgresqlPrismaClinicMapper.toPrismaCreate({ + ...clinic, + + }); + + const newClinic = await this.postgreSqlPrismaOrmService['clinic'].create( + toPrismaEntity + ); + + return PostgresqlPrismaClinicMapper.toDomain(newClinic); + } + + async findClinicByNameAndPsychologistId(name: string, psychologistId: string): Promise { + + const clinic = await this.postgreSqlPrismaOrmService['clinic'].findFirst( + { + where: { + name, + psychologistId: psychologistId + }, + } + ); + + if (!clinic) { + return null; + } + + return PostgresqlPrismaClinicMapper.toDomain(clinic); + } + + async findClinicById(id: string): Promise { + const clinic = await this.postgreSqlPrismaOrmService['clinic'].findUnique( + { + where: { + id, + }, + } + ); + + if (!clinic) { + return null; + } + + return PostgresqlPrismaClinicMapper.toDomain(clinic); + } + + async getClinics(): Promise { + const clinics = await this.postgreSqlPrismaOrmService[ + 'clinic' + ].findMany(); + + return PostgresqlPrismaClinicMapper.toDomainMany(clinics); + } + + async updateClinic(newClinic: UpdateClinicDto): Promise { + const oldClinic = await this.findClinicById(newClinic.id); + + if (!oldClinic) { + throw new ConflictException(CLINIC_ERROR_MESSAGES['CONFLICTING_CREDENTIALS']); + } + + const toPrismaEntity = + PostgresqlPrismaClinicMapper.toPrismaUpdate(newClinic); + + await this.postgreSqlPrismaOrmService['clinic'].update(toPrismaEntity); + } + + async deleteClinic(name: string, psychologistId: string): Promise { + const isClinicExists = await this.findClinicByNameAndPsychologistId(name, psychologistId); + + if (!isClinicExists) { + throw new ConflictException(CLINIC_ERROR_MESSAGES['CLINIC_NOT_FOUND']); + } + + const clinicId = isClinicExists.id + await this.postgreSqlPrismaOrmService['clinic'].delete({ + where: { + id: clinicId, + }, + }); + } +} 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-psychologist-repository.ts similarity index 97% rename from libs/core-rest-api/adapters/src/database/repositories/psychologist/postgresql-prisma-orm-repository.ts rename to libs/core-rest-api/adapters/src/database/repositories/psychologist/postgresql-prisma-orm-psychologist-repository.ts index b3af8fb..640114f 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-psychologist-repository.ts @@ -4,7 +4,7 @@ import { CreatePsychologistDto } from '@clinicControl/core-rest-api/core/src/dom import { UpdatePsychologistDto } from '@clinicControl/core-rest-api/core/src/domains/psychologist/use-cases/update-psychologist/update-psychologist-dto'; 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'; +import { PostgreSqlPrismaOrmService } from '../../infra/prisma/prisma.service'; import { PostgresqlPrismaPsychologistMapper } from '../../mappers/postgresql-prisma-psychologist-mapper'; @Injectable() 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 c239db2..22e4df2 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,7 +1,9 @@ +import { ClinicDatabaseRepository } from '@clinicControl/core-rest-api/core/src/domains/clinic/repositories/database-repository'; import { PsychologistDatabaseRepository } from '@clinicControl/core-rest-api/core/src/domains/psychologist/repositories/database-repository'; import { Module } from '@nestjs/common'; import { PostgreSqlPrismaOrmService } from '../infra/prisma/prisma.service'; -import { PostgresqlPrismaOrmPsychologistRepository } from './psychologist/postgresql-prisma-orm-repository'; +import { PostgresqlPrismaOrmClinicRepository } from './clinic/postgres-prisma-orm-clinic-repository'; +import { PostgresqlPrismaOrmPsychologistRepository } from './psychologist/postgresql-prisma-orm-psychologist-repository'; @Module({ imports: [], @@ -12,6 +14,10 @@ import { PostgresqlPrismaOrmPsychologistRepository } from './psychologist/postgr provide: PsychologistDatabaseRepository, useClass: PostgresqlPrismaOrmPsychologistRepository, }, + { + provide: ClinicDatabaseRepository, + useClass: PostgresqlPrismaOrmClinicRepository, + }, ], exports: [ PostgreSqlPrismaOrmService, @@ -19,6 +25,10 @@ import { PostgresqlPrismaOrmPsychologistRepository } from './psychologist/postgr provide: PsychologistDatabaseRepository, useClass: PostgresqlPrismaOrmPsychologistRepository, }, + { + provide: ClinicDatabaseRepository, + useClass: PostgresqlPrismaOrmClinicRepository, + }, ], }) export class DatabaseRepositoriesModule {} diff --git a/libs/core-rest-api/adapters/tests/factories/make-clinic.ts b/libs/core-rest-api/adapters/tests/factories/make-clinic.ts new file mode 100644 index 0000000..4247ed4 --- /dev/null +++ b/libs/core-rest-api/adapters/tests/factories/make-clinic.ts @@ -0,0 +1,44 @@ +import { fakerPT_BR as faker } from '@faker-js/faker'; +import { Injectable } from '@nestjs/common'; + +import { ClinicEntity } from '@clinicControl/core-rest-api/core/src/domains/clinic/entities/clinic/entity'; +import { CreateClinicDto } from '@clinicControl/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic-dto'; +import { PostgreSqlPrismaOrmService } from '../../src/database/infra/prisma/prisma.service'; +import { PostgresqlPrismaClinicMapper } from '../../src/database/mappers/postgresql-prisma-clinic-mapper'; + +/* + Creating a factory for the Clinic entity, which will be used to create tests for the domain's use cases +*/ +export function makeClinic( + psychologistId?: string, + override: Partial = {} +): ClinicEntity { + const newClinic = new ClinicEntity({ + name: faker.word.noun(), + city: faker.location.city(), + state: faker.location.state(), + psychologistId: psychologistId ?? '', + ...override, + }); + return newClinic; +} + +/* + Creating a factory for Prisma's Clinic entity, which will be used to create e2e tests (controllers) +*/ +@Injectable() +export class ClinicFactory { + constructor(private postgreSqlPrismaOrmService: PostgreSqlPrismaOrmService) {} + + async makePrismaClinic( + clinic: CreateClinicDto + ): Promise { + const newPrismaClinic = makeClinic(clinic.psychologistId, clinic); + + await this.postgreSqlPrismaOrmService['clinic'].create( + PostgresqlPrismaClinicMapper.toPrismaCreate(newPrismaClinic) + ); + + return newPrismaClinic; + } +} diff --git a/libs/core-rest-api/core/src/domains/clinic/entities/clinic/dto.ts b/libs/core-rest-api/core/src/domains/clinic/entities/clinic/dto.ts index fcc2f4f..5618d9e 100644 --- a/libs/core-rest-api/core/src/domains/clinic/entities/clinic/dto.ts +++ b/libs/core-rest-api/core/src/domains/clinic/entities/clinic/dto.ts @@ -22,7 +22,7 @@ export class ClinicDto { @IsOptional() @IsDate() - createdAt?: Date; + createdAt!: Date; @IsOptional() @IsDate() diff --git a/libs/core-rest-api/core/src/domains/clinic/repositories/database-in-memory-repository.ts b/libs/core-rest-api/core/src/domains/clinic/repositories/database-in-memory-repository.ts index 366305e..9ea7881 100644 --- a/libs/core-rest-api/core/src/domains/clinic/repositories/database-in-memory-repository.ts +++ b/libs/core-rest-api/core/src/domains/clinic/repositories/database-in-memory-repository.ts @@ -11,10 +11,10 @@ export class InMemoryClinicDatabaseRepository private clinics: ClinicEntity[] = []; async createClinic(clinic: CreateClinicDto): Promise { - const isClinicExists = await this.findClinicByName(clinic.name); + const isClinicExists = await this.findClinicByNameAndPsychologistId(clinic.name, clinic.psychologistId); if (isClinicExists) { - throw new ConflictException(CLINIC_ERROR_MESSAGES['CONFLICTING_NAME']); + throw new ConflictException(CLINIC_ERROR_MESSAGES['CONFLICTING_CREDENTIALS']); } const newClinic = new ClinicEntity(clinic); @@ -28,8 +28,8 @@ export class InMemoryClinicDatabaseRepository return this.clinics; } - async findClinicByName(name: string): Promise { - return this.clinics.find((clinic) => clinic.name === name) ?? null; + async findClinicByNameAndPsychologistId(name: string, psychologistId: string): Promise { + return this.clinics.find((clinic) => clinic.name === name && clinic.psychologistId === psychologistId) ?? null; } async findClinicById(id: string): Promise { @@ -55,8 +55,8 @@ export class InMemoryClinicDatabaseRepository this.clinics[clinicIndex] = updatedClinic; } - async deleteClinic(name: string): Promise { - const isClinicExists = await this.findClinicByName(name); + async deleteClinic(name: string, psychologistId: string): Promise { + const isClinicExists = await this.findClinicByNameAndPsychologistId(name, psychologistId); if (!isClinicExists) { throw new ConflictException(CLINIC_ERROR_MESSAGES['CLINIC_NOT_FOUND']); diff --git a/libs/core-rest-api/core/src/domains/clinic/repositories/database-repository.ts b/libs/core-rest-api/core/src/domains/clinic/repositories/database-repository.ts index f1ef394..03ba994 100644 --- a/libs/core-rest-api/core/src/domains/clinic/repositories/database-repository.ts +++ b/libs/core-rest-api/core/src/domains/clinic/repositories/database-repository.ts @@ -5,8 +5,8 @@ import { UpdateClinicDto } from '../use-cases/update-clinic/update-clinic-dto'; export abstract class ClinicDatabaseRepository { abstract createClinic(clinic: CreateClinicDto): Promise; abstract getClinics(): Promise; - abstract findClinicByName(name: string): Promise; + abstract findClinicByNameAndPsychologistId(name: string, psychologistId: string): Promise; abstract findClinicById(id: string): Promise; abstract updateClinic(clinic: UpdateClinicDto): Promise; - abstract deleteClinic(name: string): Promise; + abstract deleteClinic(name: string, psychologistId: string): Promise; } diff --git a/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic-dto.ts b/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic-dto.ts index 6551ccc..a9d3df0 100644 --- a/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic-dto.ts +++ b/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic-dto.ts @@ -1,4 +1,4 @@ -import { IsDate, IsOptional, IsString } from 'class-validator'; +import { IsOptional, IsString } from 'class-validator'; export class CreateClinicDto { @IsString() @@ -16,12 +16,4 @@ export class CreateClinicDto { @IsString() state!: string; - - @IsOptional() - @IsDate() - createdAt?: Date; - - @IsOptional() - @IsDate() - updatedAt?: Date | null; } diff --git a/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic.service.ts b/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic.service.ts index dceb386..a355c68 100644 --- a/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic.service.ts +++ b/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic.service.ts @@ -21,12 +21,13 @@ export class CreateClinicService { await applicationValidateOrReject(createClinicDtoInstance); - const isClinicExist = await this.clinicDatabaseRepository.findClinicByName( - createClinicDto.name + const isClinicExist = await this.clinicDatabaseRepository.findClinicByNameAndPsychologistId( + createClinicDto.name, + createClinicDto.psychologistId, ); if (isClinicExist) { - throw new ConflictException(CLINIC_ERROR_MESSAGES['CONFLICTING_NAME']); + throw new ConflictException(CLINIC_ERROR_MESSAGES['CONFLICTING_CREDENTIALS']); } // Create diff --git a/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic.spec.ts b/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic.spec.ts index 2db40dc..ea201ff 100644 --- a/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic.spec.ts +++ b/libs/core-rest-api/core/src/domains/clinic/use-cases/create-clinic/create-clinic.spec.ts @@ -25,7 +25,7 @@ describe('[clinic] Create Clinic Service', () => { it('should create a new clinic', async () => { const createClinic = await service.execute(fakeClinic); - const clinic = await databaseRepository.findClinicByName(createClinic.name); + const clinic = await databaseRepository.findClinicByNameAndPsychologistId(createClinic.name, createClinic.psychologistId); expect(clinic?.name).toEqual(createClinic.name); expect(createClinic.name).toEqual(fakeClinic.name); diff --git a/libs/core-rest-api/core/src/domains/clinic/use-cases/delete-clinic/delete-clinic.service.ts b/libs/core-rest-api/core/src/domains/clinic/use-cases/delete-clinic/delete-clinic.service.ts index 7f662d3..f5b3cfd 100644 --- a/libs/core-rest-api/core/src/domains/clinic/use-cases/delete-clinic/delete-clinic.service.ts +++ b/libs/core-rest-api/core/src/domains/clinic/use-cases/delete-clinic/delete-clinic.service.ts @@ -5,10 +5,10 @@ import { ClinicDatabaseRepository } from '../../repositories/database-repository export class DeleteClinicService { constructor(private clinicDatabaseRepository: ClinicDatabaseRepository) {} - async execute(name: string): Promise { + async execute(name: string, psychologistId: string): Promise { // Validate if clinic exists in db - const isClinicExists = await this.clinicDatabaseRepository.findClinicByName( - name + const isClinicExists = await this.clinicDatabaseRepository.findClinicByNameAndPsychologistId( + name, psychologistId ); if (!isClinicExists) { @@ -16,6 +16,6 @@ export class DeleteClinicService { } // Delete clinic - await this.clinicDatabaseRepository.deleteClinic(name); + await this.clinicDatabaseRepository.deleteClinic(name, psychologistId); } } diff --git a/libs/core-rest-api/core/src/domains/clinic/use-cases/delete-clinic/delete-clinic.spec.ts b/libs/core-rest-api/core/src/domains/clinic/use-cases/delete-clinic/delete-clinic.spec.ts index 32171d4..ff16429 100644 --- a/libs/core-rest-api/core/src/domains/clinic/use-cases/delete-clinic/delete-clinic.spec.ts +++ b/libs/core-rest-api/core/src/domains/clinic/use-cases/delete-clinic/delete-clinic.spec.ts @@ -25,7 +25,7 @@ describe('[clinic] Delete Clinic Service', () => { it('should delete a new clinic', async () => { const createClinic = await databaseRepository.createClinic(fakeClinic); - await service.execute(createClinic.name); + await service.execute(createClinic.name, createClinic.psychologistId); const getClinics = await databaseRepository.getClinics(); @@ -33,7 +33,7 @@ describe('[clinic] Delete Clinic Service', () => { }); it('should throw conflict exception if clinic do not exists', async () => { - await expect(service.execute(fakeClinic.name)).rejects.toThrow( + await expect(service.execute(fakeClinic.name, fakeClinic.psychologistId)).rejects.toThrow( ConflictException ); }); 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 b0675fe..8f52490 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 @@ -9,7 +9,7 @@ export const PSYCHOLOGIST_ERROR_MESSAGES = { }; export const CLINIC_ERROR_MESSAGES = { - CONFLICTING_NAME: 'clinic already exists', + CONFLICTING_CREDENTIALS: 'clinic already exists', CLINIC_NOT_FOUND: 'clinic not found', }; diff --git a/libs/core-rest-api/core/src/shared/errors/globalAppHttpException.ts b/libs/core-rest-api/core/src/shared/errors/globalAppHttpException.ts index f6a1538..db0dde1 100644 --- a/libs/core-rest-api/core/src/shared/errors/globalAppHttpException.ts +++ b/libs/core-rest-api/core/src/shared/errors/globalAppHttpException.ts @@ -54,7 +54,7 @@ export class GlobalAppHttpException { exceptionMessage += ` Prisma Error Code: ${error.code}.`; } - if (error.code === 'P2002') { + if (error.code === 'P2002' || error.code === 'P2003') { // Remover linhas e espaços extras const relevantLines = error.message .split('\n')