Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

81 criando o endpoint para o use case de criação de clinica #90

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7cdb264
config(CC-81): add folders and files to create clinic endpoint
luanavfg Oct 23, 2023
65d8c6c
feat(CC-81): adjust test
luanavfg Oct 23, 2023
0b714fc
feat(CC-81): add prisma clinic repository and rename psychologist rep…
luanavfg Oct 27, 2023
a8c737e
feat(CC-81): add prisma clinic mapper
luanavfg Oct 27, 2023
56b7d4e
feat(CC-81): make clinic factory
luanavfg Oct 27, 2023
0ffbb4d
feat(CC-81): add repository in repositories module
luanavfg Oct 27, 2023
9cdff17
feat(CC-81): add create clinic e2e test and refactor folder organization
luanavfg Oct 27, 2023
87e4fe2
adjust(CC-81): make adjustments in mapper and controller
luanavfg Oct 29, 2023
21dcc38
feat(CC-81): add client.http
luanavfg Oct 30, 2023
729eba7
refactor(CC-81): rename use-case folder to use-cases in adapters
luanavfg Oct 30, 2023
07f8608
refactor(CC-81): adjust typo error in json - client.http
luanavfg Oct 30, 2023
90d49fc
feat(CC-81): add clinic controller and service to api module
luanavfg Oct 30, 2023
8bc3d92
config(CC-81): adjust client.http
luanavfg Oct 30, 2023
6fb6ad4
feat(CC-81): add response message in clinic creation
luanavfg Nov 6, 2023
9d3eb6a
adjust(CC-81): adjust types
luanavfg Nov 6, 2023
ac81064
adjust(CC-81): adjust create clinic test
luanavfg Nov 6, 2023
7d98798
chore(CC-81): delete comment
luanavfg Nov 6, 2023
9004d17
refactor(CC-81): remove hardcoded clinic name
luanavfg Nov 8, 2023
acebf95
refactor(CC-81): change psychologist creation in clinic test to makeP…
luanavfg Nov 8, 2023
7347307
adjust(CC-81): adjust dto attributes
luanavfg Nov 9, 2023
b0ffb92
Merge branch 'main' of https://github.com/ItaloRAmaral/cliniccontrol …
luanavfg Nov 9, 2023
b94ec75
chore(CC-81): update client.http for client and psychologist
luanavfg Nov 9, 2023
91a76d6
adjust(CC-81): adjust error name
luanavfg Nov 9, 2023
9ecb224
adjust(CC-81): adjust error name
luanavfg Nov 9, 2023
241f902
adjust(CC-81): adjust conflicts
luanavfg Nov 9, 2023
2906041
adjust(CC-81): adjust imports
luanavfg Nov 9, 2023
7bd1a10
adjust(CC-81): add psychologistId in clinic use-cases to verify if it…
luanavfg Nov 9, 2023
20179d2
adjust(CC-81): add psychologistId in clinic postgres prisma repositor…
luanavfg Nov 9, 2023
e9d5b7d
feat(CC-81): add configs for auth
luanavfg Nov 10, 2023
0670b96
feat(CC-81): adjust e2e create clinic test
luanavfg Nov 16, 2023
12371c2
Merge branch 'main' of https://github.com/ItaloRAmaral/cliniccontrol …
luanavfg Nov 16, 2023
b94d417
fix(CC-81): adjust errors and delete logs
luanavfg Nov 17, 2023
230a835
test(CC-81): adjust create clinic e2e test
luanavfg Nov 17, 2023
484feca
adjust(CC-81): adjust error treatment and test
luanavfg Nov 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading