Skip to content

Commit

Permalink
Merge pull request #134 from ItaloRAmaral/99-update-patient-endpoint
Browse files Browse the repository at this point in the history
feat(CC-99): update patient endpoint
  • Loading branch information
luanavfg authored Mar 6, 2024
2 parents d215a98 + 70e5f61 commit 5950291
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 18 deletions.
11 changes: 11 additions & 0 deletions apps/core-rest-api/http/patient-client.http
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,14 @@ Authorization: Bearer {{authToken}}
DELETE http://localhost:3333/core/patient/{{$dotenv PATIENT_ID}}/delete HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{authToken}}

### Update a patient
# @name update_patient
PATCH http://localhost:3333/core/patient/{{$dotenv PATIENT_ID}}/update HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{authToken}}

{
"name": "teste",
"email": "[email protected]"
}
40 changes: 22 additions & 18 deletions apps/core-rest-api/src/app/adapters/controllers/api/api.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,35 @@ import { BcryptHasherService } from '../../../core/shared/cryptography/use-cases
import { PostgreSqlPrismaOrmService } from '../../database/infra/prisma/prisma.service';
import { DatabaseRepositoriesModule } from '../../database/repositories/repositories.module';

import { CreateClinicController } from './use-cases/clinic/create-clinic/create-clinic.controller';
import { DeleteClinicController } from './use-cases/clinic/delete-clinic/delete-clinic.controller';
import { UpdateClinicController } from './use-cases/clinic/update-clinic/update-clinic.controller';
import { CreatePatientController } from './use-cases/patient/create-patient/create-patient.controller';
import { DeletePatientController } from './use-cases/patient/delete-patient/delete-patient.controller';
import { AuthenticatePsychologistController } from './use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller';
import { CreatePsychologistController } from './use-cases/psychologist/create-psychologist/create-psychologist.controller';
import { DeletePsychologistController } from './use-cases/psychologist/delete-psychologist/delete-psychologist.controller';

import { CreateAppointmentController } from './use-cases/appointment/create-appointment/create-appointment.controller';
import { NestjsCreateAppointmentService } from './use-cases/appointment/create-appointment/nestjs-create-appointment.service';
import { NestjsCreateClinicService } from './use-cases/clinic/create-clinic/nestjs-create-clinic.service';
import { NestjsDeleteClinicService } from './use-cases/clinic/delete-clinic/nestjs-delete-clinic.service';
import { NestjsUpdateClinicService } from './use-cases/clinic/update-clinic/nestjs-update-clinic.service';
import { CreatePatientAppointmentRegistryController } from './use-cases/patient-appointment-registry/create-patient-appointment-registry/create-patient-appointment-registry.controller';
import { NestjsCreatePatientAppointmentRegistryService } from './use-cases/patient-appointment-registry/create-patient-appointment-registry/nestjs-create-patient-appointment-registry.service';
import { DeletePatientAppointmentRegistryController } from './use-cases/patient-appointment-registry/delete-patient-appointment-registry/delete-patient-appointment-registry.controller';
import { NestjsDeletePatientAppointmentRegistryService } from './use-cases/patient-appointment-registry/delete-patient-appointment-registry/nestjs-delete-patient-appointment-registry.service';
import { NestjsUpdatePatientAppointmentRegistryService } from './use-cases/patient-appointment-registry/update-patient-appointment-registry/nestjs-update-patient-appointment-registry.service';
import { UpdatePatientAppointmentRegistryController } from './use-cases/patient-appointment-registry/update-patient-appointment-registry/update-patient-appointment-registry.controller';
import { NestjsCreatePatientService } from './use-cases/patient/create-patient/nestjs-create-patient.service';
import { NestjsDeletePatientService } from './use-cases/patient/delete-patient/nestjs-delete-patient.service';
import { NestjsUpdatePatientService } from './use-cases/patient/update-patient/nestjs-update-patient.service';
import { NestjsAuthenticatePsychologistService } from './use-cases/psychologist/authenticate-psychologist/nestjs-authenticate-psychologist.service';
import { NestjsCreatePsychologistService } from './use-cases/psychologist/create-psychologist/nestjs-create-psychologist.service';
import { NestjsDeletePsychologistService } from './use-cases/psychologist/delete-psychologist/nestjs-delete-psychologist.service';
import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update-psychologist/nestjs-update-psychologist.service';

import { CreateAppointmentController } from './use-cases/appointment/create-appointment/create-appointment.controller';
import { CreateClinicController } from './use-cases/clinic/create-clinic/create-clinic.controller';
import { DeleteClinicController } from './use-cases/clinic/delete-clinic/delete-clinic.controller';
import { UpdateClinicController } from './use-cases/clinic/update-clinic/update-clinic.controller';
import { CreatePatientAppointmentRegistryController } from './use-cases/patient-appointment-registry/create-patient-appointment-registry/create-patient-appointment-registry.controller';
import { NestjsCreatePatientAppointmentRegistryService } from './use-cases/patient-appointment-registry/create-patient-appointment-registry/nestjs-create-patient-appointment-registry.service';
import { DeletePatientAppointmentRegistryController } from './use-cases/patient-appointment-registry/delete-patient-appointment-registry/delete-patient-appointment-registry.controller';
import { NestjsDeletePatientAppointmentRegistryService } from './use-cases/patient-appointment-registry/delete-patient-appointment-registry/nestjs-delete-patient-appointment-registry.service';
import { NestjsUpdatePatientAppointmentRegistryService } from './use-cases/patient-appointment-registry/update-patient-appointment-registry/nestjs-update-patient-appointment-registry.service';
import { UpdatePatientAppointmentRegistryController } from './use-cases/patient-appointment-registry/update-patient-appointment-registry/update-patient-appointment-registry.controller';
import { CreatePatientController } from './use-cases/patient/create-patient/create-patient.controller';
import { DeletePatientController } from './use-cases/patient/delete-patient/delete-patient.controller';
import { UpdatePatientController } from './use-cases/patient/update-patient/update-patient.controller';
import { AuthenticatePsychologistController } from './use-cases/psychologist/authenticate-psychologist/authenticate-psychologist.controller';
import { CreatePsychologistController } from './use-cases/psychologist/create-psychologist/create-psychologist.controller';
import { DeletePsychologistController } from './use-cases/psychologist/delete-psychologist/delete-psychologist.controller';

@Module({
imports: [
ConfigModule.forRoot({
Expand All @@ -62,7 +64,8 @@ import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update
CreatePatientAppointmentRegistryController,
CreateAppointmentController,
DeletePatientAppointmentRegistryController,
UpdatePatientAppointmentRegistryController
UpdatePatientAppointmentRegistryController,
UpdatePatientController,
],
providers: [
BcryptHasherService,
Expand All @@ -79,7 +82,8 @@ import { NestjsUpdatePsychologistService } from './use-cases/psychologist/update
NestjsCreatePatientAppointmentRegistryService,
NestjsCreateAppointmentService,
NestjsDeletePatientAppointmentRegistryService,
NestjsUpdatePatientAppointmentRegistryService
NestjsUpdatePatientAppointmentRegistryService,
NestjsUpdatePatientService,
],
})
export class ApiModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { OperationObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface';

const description = `
---
\`Experimental\`
---
### Update an existing Patient
This endpoint help you to update an existing Patient.
You must at least provide one of the following body parameters
`;

export const patchMethodDocs: Partial<OperationObject> = {
summary: 'Update an existing Patient',
description,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { IsEnum, IsMobilePhone, IsOptional, IsString, IsUUID } from 'class-validator';
import { PaymentMethod } from '../../../../../../core/shared/interfaces/payments';

export class UpdatePatientControllerReqBodyInputDto {
@IsOptional()
@IsString()
name?: string;

@IsOptional()
@IsString()
email?: string;

@IsOptional()
@IsString()
cpf?: string;

@IsOptional()
@IsMobilePhone('pt-BR')
telephone?: string;

@IsOptional()
@IsEnum(PaymentMethod)
paymentMethod?: PaymentMethod;

@IsOptional()
@IsString()
clinicId?: string;
}

export class UpdatePatientControllerReqParamsInputDto {
@IsUUID()
id!: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Injectable } from '@nestjs/common';

import { PatientDatabaseRepository } from '../../../../../../../app/core/domains/patient/repositories/database-repository';
import { UpdatePatientService } from '../../../../../../../app/core/domains/patient/use-cases/update-patient/update-patient.service';

@Injectable()
export class NestjsUpdatePatientService extends UpdatePatientService {
constructor(patientDatabaseRepository: PatientDatabaseRepository) {
super(patientDatabaseRepository);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { BadRequestException, Body, Controller, Param, Patch } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { patchMethodDocs } from './docs';

import { GlobalAppHttpException } from '../../../../../../shared/errors/globalAppHttpException';
import {
UpdatePatientControllerReqBodyInputDto,
UpdatePatientControllerReqParamsInputDto,
} from './input-dto';
import { NestjsUpdatePatientService } from './nestjs-update-patient.service';

@ApiTags('Patient')
@ApiBearerAuth()
@Controller({
path: 'patient',
})
export class UpdatePatientController {
constructor(private updatePatientService: NestjsUpdatePatientService) {}

@Patch(':id/update')
@ApiOperation(patchMethodDocs)
async execute(
@Param() { id }: UpdatePatientControllerReqParamsInputDto,
@Body() updatePsychologistDto: UpdatePatientControllerReqBodyInputDto,
) {
try {
const isReqBodyEmpty = Object.keys(updatePsychologistDto).length === 0;

if (isReqBodyEmpty) {
throw new BadRequestException('Must provide at least one field to update');
}

await this.updatePatientService.execute({ id, ...updatePsychologistDto });

return { message: 'Patient updated successfully' };
} catch (error: unknown) {
throw new GlobalAppHttpException(error);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import request from 'supertest';

import { INestApplication } from '@nestjs/common';

import { faker } from '@faker-js/faker';
import { setupE2ETest } from '../../../../../../../../tests/utils/e2e-tests-initial-setup';
import { PatientEntity } from '../../../../../../core/domains/patient/entities/patient/entity';

describe('[E2E] - Update Psychologist Account', () => {
let app: INestApplication;

let patient: PatientEntity;
let access_token: string;
let invalid_access_token: string;

beforeAll(async () => {
const setup = await setupE2ETest();
app = setup.app;

patient = setup.patient;

access_token = setup.access_token;
invalid_access_token = setup.invalid_access_token;
});

it('[PATCH] - Should successfully update a patient account', async () => {
const updateInfos = {
name: 'New Name',
email: '[email protected]',
};

const response = await request(app.getHttpServer())
.patch(`/patient/${patient.id}/update`)
.set('Authorization', `Bearer ${access_token}`)
.send(updateInfos);

expect(response.statusCode).toBe(200);
expect(response.body.message).toBe('Patient updated successfully');
});

it('[PATCH] - Should return an error when trying to update a patient without access_token', async () => {
const updateInfos = {
name: 'New Name',
};

const response = await request(app.getHttpServer())
.patch(`/patient/${patient.id}/update`)
.send(updateInfos);

expect(response.statusCode).toBe(401);
expect(response.body.message).toBe('Invalid JWT token');
});

it('[PATCH] - Should return an error when trying to update a patient with invalid access_token', async () => {
const updateInfos = {
name: 'New Name',
};

const response = await request(app.getHttpServer())
.patch(`/patient/${patient.id}/update`)
.set('Authorization', `Bearer ${invalid_access_token}`)
.send(updateInfos);

expect(response.statusCode).toBe(401);
expect(response.body.message).toBe('Invalid JWT token');
});

it('[PATCH] - Should return an error when trying to update a patient with invalid id', async () => {
const updateInfos = {
name: 'New Name',
};

const response = await request(app.getHttpServer())
.patch(`/patient/invalid_id/update`)
.set('Authorization', `Bearer ${access_token}`)
.send(updateInfos);

expect(response.statusCode).toBe(400);
expect(response.body.message).toEqual(['id must be a UUID']);
});

it('[PATCH] - Should return an error when trying to update a patient with non existent id', async () => {
const nonExistentId = faker.string.uuid();

const updateInfos = {
name: 'New Name',
};

const response = await request(app.getHttpServer())
.patch(`/patient/${nonExistentId}/update`)
.set('Authorization', `Bearer ${access_token}`)
.send(updateInfos);

expect(response.statusCode).toBe(404);
expect(response.body.message).toBe('patient not found');
});

it('[PATCH] - Should return an error when trying to update a patient with empty request body', async () => {
const updateInfos = {};

const response = await request(app.getHttpServer())
.patch(`/psychologist/${patient.id}/update`)
.set('Authorization', `Bearer ${access_token}`)
.send(updateInfos);

expect(response.statusCode).toBe(400);
expect(response.body.message).toBe('Must provide at least one field to update');
});

it('[PATCH] - Should return an error when trying to update a patient with an invalid body type params', async () => {
const updateInfos = {
name: 123,
email: 123,
};

const response = await request(app.getHttpServer())
.patch(`/psychologist/${patient.id}/update`)
.set('Authorization', `Bearer ${access_token}`)
.send(updateInfos);

expect(response.statusCode).toBe(400);
expect(response.body.message).toEqual([
'name must be a string',
'email must be a string',
]);
});
});

0 comments on commit 5950291

Please sign in to comment.