Skip to content

Commit

Permalink
Merge pull request #90 from ItaloRAmaral/81-criando-o-endpoint-para-o…
Browse files Browse the repository at this point in the history
…-use-case-de-criação-de-clinica

81 criando o endpoint para o use case de criação de clinica
  • Loading branch information
ItaloRAmaral authored Nov 17, 2023
2 parents 5f33b66 + 484feca commit 3afd755
Show file tree
Hide file tree
Showing 20 changed files with 423 additions and 37 deletions.
12 changes: 7 additions & 5 deletions libs/core-rest-api/adapters/src/controllers/api/api.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -31,7 +33,7 @@ import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update
],
controllers: [
CreatePsychologistController,
AuthenticatePsychologistController,
AuthenticatePsychologistController, CreateClinicController,
UpdatePsychologistController,
],
providers: [
Expand All @@ -40,6 +42,6 @@ import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update
NestjsCreatePsychologistService,
NestjsAuthenticatePsychologistService,
NestjsUpdatePsychologistService,
],
NestjsCreateClinicService],
})
export class ApiModule {}
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"
}
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);
}
}
}
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()`");
});
});
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);
}
}
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,
},
};
}
}
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,
},
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading

0 comments on commit 3afd755

Please sign in to comment.