-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #90 from ItaloRAmaral/81-criando-o-endpoint-para-o…
…-use-case-de-criação-de-clinica 81 criando o endpoint para o use case de criação de clinica
- Loading branch information
Showing
20 changed files
with
423 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
libs/core-rest-api/adapters/src/controllers/api/use-cases/clinic/create-clinic/client.http
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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": "[email protected]", | ||
"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" | ||
} |
31 changes: 31 additions & 0 deletions
31
...i/adapters/src/controllers/api/use-cases/clinic/create-clinic/create-clinic.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<createClinicResponse>{ | ||
try { | ||
await this.createClinicService.execute(createClinicDto); | ||
return {message: 'Clinic created successfully'} | ||
} catch (error: unknown) { | ||
throw new GlobalAppHttpException(error); | ||
} | ||
} | ||
} |
118 changes: 118 additions & 0 deletions
118
...api/adapters/src/controllers/api/use-cases/clinic/create-clinic/create-clinic.e2e-spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()`"); | ||
}); | ||
}); |
10 changes: 10 additions & 0 deletions
10
...apters/src/controllers/api/use-cases/clinic/create-clinic/nestjs-create-clinic.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
libs/core-rest-api/adapters/src/database/mappers/postgresql-prisma-clinic-mapper.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
}, | ||
}; | ||
} | ||
} |
110 changes: 110 additions & 0 deletions
110
...st-api/adapters/src/database/repositories/clinic/postgres-prisma-orm-clinic-repository.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<ClinicEntity> { | ||
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<ClinicEntity | null> { | ||
|
||
const clinic = await this.postgreSqlPrismaOrmService['clinic'].findFirst( | ||
{ | ||
where: { | ||
name, | ||
psychologistId: psychologistId | ||
}, | ||
} | ||
); | ||
|
||
if (!clinic) { | ||
return null; | ||
} | ||
|
||
return PostgresqlPrismaClinicMapper.toDomain(clinic); | ||
} | ||
|
||
async findClinicById(id: string): Promise<ClinicEntity | null> { | ||
const clinic = await this.postgreSqlPrismaOrmService['clinic'].findUnique( | ||
{ | ||
where: { | ||
id, | ||
}, | ||
} | ||
); | ||
|
||
if (!clinic) { | ||
return null; | ||
} | ||
|
||
return PostgresqlPrismaClinicMapper.toDomain(clinic); | ||
} | ||
|
||
async getClinics(): Promise<ClinicEntity[]> { | ||
const clinics = await this.postgreSqlPrismaOrmService[ | ||
'clinic' | ||
].findMany(); | ||
|
||
return PostgresqlPrismaClinicMapper.toDomainMany(clinics); | ||
} | ||
|
||
async updateClinic(newClinic: UpdateClinicDto): Promise<void> { | ||
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<void> { | ||
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, | ||
}, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.