From e6075c25c29cb4fa7472e14a997c34b7dd60fa4e Mon Sep 17 00:00:00 2001 From: DimitriRomano Date: Thu, 22 Feb 2024 15:20:45 +0100 Subject: [PATCH 1/4] fix swagger + patient --- src/appointments/appointments.controller.ts | 2 ++ src/dermatologues/dermatologues.controller.ts | 25 +++------------ .../entities/dermatologue.entity.ts | 4 +-- src/medecins/medecins.controller.ts | 7 +++- src/patients/patients.controller.ts | 20 ++---------- src/patients/patients.service.ts | 32 +++++++++---------- 6 files changed, 33 insertions(+), 57 deletions(-) diff --git a/src/appointments/appointments.controller.ts b/src/appointments/appointments.controller.ts index 9f93575..7410516 100644 --- a/src/appointments/appointments.controller.ts +++ b/src/appointments/appointments.controller.ts @@ -10,8 +10,10 @@ import { import { AppointmentsService } from './appointments.service'; import { CreateAppointmentDto } from './dto/create-appointment.dto'; import { UpdateAppointmentDto } from './dto/update-appointment.dto'; +import { ApiTags } from '@nestjs/swagger'; @Controller('appointments') +@ApiTags('patients') export class AppointmentsController { constructor(private readonly appointmentsService: AppointmentsService) {} diff --git a/src/dermatologues/dermatologues.controller.ts b/src/dermatologues/dermatologues.controller.ts index 9f4790f..8a08fbb 100644 --- a/src/dermatologues/dermatologues.controller.ts +++ b/src/dermatologues/dermatologues.controller.ts @@ -1,14 +1,7 @@ -import { - Controller, - Get, - Post, - Body, - Patch, - Param, - Delete, -} from '@nestjs/common'; +import { Controller, Get, Param } from '@nestjs/common'; import { DermatologuesService } from './dermatologues.service'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; +import { DermatologueEntity } from './entities/dermatologue.entity'; @ApiTags('dermatologues') @Controller('dermatologues') @@ -16,22 +9,14 @@ export class DermatologuesController { constructor(private readonly dermatologuesService: DermatologuesService) {} @Get() + @ApiOkResponse({ type: DermatologueEntity, isArray: true }) findAll() { return this.dermatologuesService.findAll(); } @Get(':id') + @ApiOkResponse({ type: DermatologueEntity }) findOne(@Param('id') id: string) { return this.dermatologuesService.findOne(id); } - - // @Patch(':id') - // update(@Param('id') id: string, @Body() updateDermatologueDto: ) { - // return this.dermatologuesService.update(+id, updateDermatologueDto); - // } - - // @Delete(':id') - // remove(@Param('id') id: string) { - // return this.dermatologuesService.remove(+id); - // } } diff --git a/src/dermatologues/entities/dermatologue.entity.ts b/src/dermatologues/entities/dermatologue.entity.ts index e193696..51a7aa4 100644 --- a/src/dermatologues/entities/dermatologue.entity.ts +++ b/src/dermatologues/entities/dermatologue.entity.ts @@ -2,8 +2,8 @@ import { ApiProperty } from '@nestjs/swagger'; import { Appointment, User } from '@prisma/client'; import { Exclude } from 'class-transformer'; -export class Medecin implements User { - constructor(partial: Partial) { +export class DermatologueEntity implements User { + constructor(partial: Partial) { Object.assign(this, partial); } diff --git a/src/medecins/medecins.controller.ts b/src/medecins/medecins.controller.ts index cb838d0..1bb68f4 100644 --- a/src/medecins/medecins.controller.ts +++ b/src/medecins/medecins.controller.ts @@ -10,7 +10,7 @@ import { } from '@nestjs/common'; import { MedecinsService } from './medecins.service'; import { ConsultationsService } from 'src/consultations/consultations.service'; -import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { Request } from 'express'; import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'; import { Role, User, statusConsultation } from '@prisma/client'; @@ -18,6 +18,8 @@ import { updateResultatConsultationDto } from './dto/update-resultat-consultatio import { updateConsultationStatusDto } from './dto/update-consultation-status.dto'; import { RolesGuard } from 'src/auth/roles.guard'; import { HasRole } from 'src/auth/has-role.decorator'; +import { Medecin } from './entities/medecin.entity'; +import { ConsultationEntity } from 'src/consultations/entities/consultation.entity'; // import { CreateMedecinDto } from './dto/create-medecin.dto'; // import { UpdateMedecinDto } from './dto/update-medecin.dto'; @@ -35,16 +37,19 @@ export class MedecinsController { // } @Get() + @ApiOkResponse({ type: Medecin, isArray: true }) async findAll() { return this.medecinsService.findAll(); } @Get(':id') + @ApiOkResponse({ type: Medecin }) findOne(@Param('id') id: string) { return this.medecinsService.findOne(id); } @Get(':id/consultations') + @ApiOkResponse({ type: ConsultationEntity, isArray: true }) @UseGuards(JwtAuthGuard, RolesGuard) @HasRole(Role.MEDECIN) @ApiBearerAuth() diff --git a/src/patients/patients.controller.ts b/src/patients/patients.controller.ts index 54dd03f..612f69c 100644 --- a/src/patients/patients.controller.ts +++ b/src/patients/patients.controller.ts @@ -10,7 +10,7 @@ import { import { PatientsService } from './patients.service'; import { ConsultationsService } from 'src/consultations/consultations.service'; import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'; -import { ApiBearerAuth, ApiOkResponse } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger'; import { Request } from 'express'; import { User } from '@prisma/client'; import { RolesGuard } from 'src/auth/roles.guard'; @@ -18,6 +18,7 @@ import { HasRole } from 'src/auth/has-role.decorator'; import { ConsultationEntity } from 'src/consultations/entities/consultation.entity'; @Controller('patients') +@ApiTags('patients') export class PatientsController { constructor( private readonly patientsService: PatientsService, @@ -31,7 +32,7 @@ export class PatientsController { @Get(':id') findOne(@Param('id') id: string) { - return this.patientsService.findOne(+id); + return this.patientsService.findOne(id); } @ApiBearerAuth() @@ -64,19 +65,4 @@ export class PatientsController { return consultation; } - - // @Get() - // findAll() { - // return this.patientsService.findAll(); - // } - - // @Patch(':id') - // update(@Param('id') id: string, @Body() updatePatientDto: UpdatePatientDto) { - // return this.patientsService.update(+id, updatePatientDto); - // } - - // @Delete(':id') - // remove(@Param('id') id: string) { - // return this.patientsService.remove(+id); - // } } diff --git a/src/patients/patients.service.ts b/src/patients/patients.service.ts index e0a9940..bfd3fdf 100644 --- a/src/patients/patients.service.ts +++ b/src/patients/patients.service.ts @@ -1,26 +1,24 @@ import { Injectable } from '@nestjs/common'; -import { CreatePatientDto } from './dto/create-patient.dto'; -import { UpdatePatientDto } from './dto/update-patient.dto'; +import { PrismaService } from 'src/prisma/prisma.service'; @Injectable() export class PatientsService { - create(createPatientDto: CreatePatientDto) { - return 'This action adds a new patient'; - } - - findAll() { - return `This action returns all patients`; - } - - findOne(id: number) { - return `This action returns a #${id} patient`; - } + constructor(private readonly prismaService: PrismaService) {} - update(id: number, updatePatientDto: UpdatePatientDto) { - return `This action updates a #${id} patient`; + async findAll() { + return await this.prismaService.user.findMany({ + where: { + role: 'PATIENT', + }, + }); } - remove(id: number) { - return `This action removes a #${id} patient`; + findOne(id: string) { + return this.prismaService.user.findUnique({ + where: { + id, + role: 'PATIENT', + }, + }); } } From 06ba6ee1ba0f0e9fa29cba9dc2f4f2212bd0b3ba Mon Sep 17 00:00:00 2001 From: DimitriRomano Date: Thu, 22 Feb 2024 16:17:24 +0100 Subject: [PATCH 2/4] add appointement --- .../migration.sql | 27 ---- .../migration.sql | 12 -- .../migration.sql | 10 -- .../migration.sql | 153 ++++++++++++++++++ prisma/migrations/migration_lock.toml | 3 + src/appointments/appointments.controller.ts | 6 +- src/appointments/appointments.service.ts | 25 ++- .../dto/create-appointment.dto.ts | 37 ++++- src/patients/patients.controller.ts | 1 - 9 files changed, 214 insertions(+), 60 deletions(-) delete mode 100644 prisma/migrations/20240221222138_modifiy_appointement/migration.sql delete mode 100644 prisma/migrations/20240221225021_add_enum_status_appointement/migration.sql delete mode 100644 prisma/migrations/20240222105619_update_firstname_lastname/migration.sql create mode 100644 prisma/migrations/20240222142320_new_migration/migration.sql create mode 100644 prisma/migrations/migration_lock.toml diff --git a/prisma/migrations/20240221222138_modifiy_appointement/migration.sql b/prisma/migrations/20240221222138_modifiy_appointement/migration.sql deleted file mode 100644 index 18bb86c..0000000 --- a/prisma/migrations/20240221222138_modifiy_appointement/migration.sql +++ /dev/null @@ -1,27 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `criticity` on the `Appointment` table. All the data in the column will be lost. - - The `status` column on the `Consultation` table would be dropped and recreated. This will lead to data loss if there is data in the column. - - A unique constraint covering the columns `[idConsultation]` on the table `Appointment` will be added. If there are existing duplicate values, this will fail. - - Added the required column `idConsultation` to the `Appointment` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterEnum -ALTER TYPE "Role" ADD VALUE 'ADMIN'; - --- AlterTable -ALTER TABLE "Appointment" DROP COLUMN "criticity", -ADD COLUMN "idConsultation" TEXT NOT NULL; - --- AlterTable -ALTER TABLE "Consultation" ADD COLUMN "informations" TEXT NOT NULL DEFAULT '', -ADD COLUMN "resultat" TEXT NOT NULL DEFAULT '', -DROP COLUMN "status", -ADD COLUMN "status" "statusConsultation" NOT NULL DEFAULT 'WAITING'; - --- CreateIndex -CREATE UNIQUE INDEX "Appointment_idConsultation_key" ON "Appointment"("idConsultation"); - --- AddForeignKey -ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_idConsultation_fkey" FOREIGN KEY ("idConsultation") REFERENCES "Consultation"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20240221225021_add_enum_status_appointement/migration.sql b/prisma/migrations/20240221225021_add_enum_status_appointement/migration.sql deleted file mode 100644 index bd4b459..0000000 --- a/prisma/migrations/20240221225021_add_enum_status_appointement/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ -/* - Warnings: - - - The `status` column on the `Appointment` table would be dropped and recreated. This will lead to data loss if there is data in the column. - -*/ --- CreateEnum -CREATE TYPE "statusAppointment" AS ENUM ('WAITING', 'ACCEPTED', 'CANCELED', 'REFUSED'); - --- AlterTable -ALTER TABLE "Appointment" DROP COLUMN "status", -ADD COLUMN "status" "statusAppointment" NOT NULL DEFAULT 'WAITING'; diff --git a/prisma/migrations/20240222105619_update_firstname_lastname/migration.sql b/prisma/migrations/20240222105619_update_firstname_lastname/migration.sql deleted file mode 100644 index 68c0107..0000000 --- a/prisma/migrations/20240222105619_update_firstname_lastname/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ -/* - Warnings: - - - Added the required column `firstName` to the `User` table without a default value. This is not possible if the table is not empty. - - Added the required column `lastName` to the `User` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "User" ADD COLUMN "firstName" TEXT NOT NULL, -ADD COLUMN "lastName" TEXT NOT NULL; diff --git a/prisma/migrations/20240222142320_new_migration/migration.sql b/prisma/migrations/20240222142320_new_migration/migration.sql new file mode 100644 index 0000000..2c5267b --- /dev/null +++ b/prisma/migrations/20240222142320_new_migration/migration.sql @@ -0,0 +1,153 @@ +-- CreateEnum +CREATE TYPE "Role" AS ENUM ('PATIENT', 'MEDECIN', 'DERMATOLOGUE', 'ADMIN'); + +-- CreateEnum +CREATE TYPE "Sexe" AS ENUM ('M', 'F'); + +-- CreateEnum +CREATE TYPE "statusConsultation" AS ENUM ('WAITING', 'IN_PROGRESS', 'PROCESSED', 'CLOSED', 'CANCELED'); + +-- CreateEnum +CREATE TYPE "FileType" AS ENUM ('IMAGE', 'FILE'); + +-- CreateEnum +CREATE TYPE "statusAppointment" AS ENUM ('WAITING', 'ACCEPTED', 'CANCELED', 'REFUSED'); + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "role" "Role" NOT NULL, + "firstName" TEXT NOT NULL, + "lastName" TEXT NOT NULL, + "email" TEXT NOT NULL, + "sexe" TEXT NOT NULL DEFAULT 'M', + "password" TEXT NOT NULL, + "rppsNumber" TEXT, + "address" TEXT, + "city" TEXT, + "zipCode" TEXT, + "secuNumber" TEXT, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Consultation" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "idMedecin" TEXT NOT NULL, + "idPatient" TEXT NOT NULL, + "status" "statusConsultation" NOT NULL DEFAULT 'WAITING', + "criticity" INTEGER NOT NULL DEFAULT 0, + "informations" TEXT NOT NULL DEFAULT '', + "resultat" TEXT NOT NULL DEFAULT '', + + CONSTRAINT "Consultation_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "File" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "name" TEXT NOT NULL, + "url" TEXT NOT NULL, + "type" "FileType" NOT NULL, + "size" INTEGER NOT NULL, + + CONSTRAINT "File_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Appointment" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "idDermatologue" TEXT NOT NULL, + "idPatient" TEXT NOT NULL, + "date" TIMESTAMP(3) NOT NULL, + "status" "statusAppointment" NOT NULL DEFAULT 'WAITING', + "idConsultation" TEXT NOT NULL, + + CONSTRAINT "Appointment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Conversation" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "idFrom" TEXT NOT NULL, + "idToUser" TEXT NOT NULL, + "idToIa" TEXT NOT NULL, + + CONSTRAINT "Conversation_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Message" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "content" TEXT NOT NULL, + "idConversation" TEXT NOT NULL, + "idFrom" TEXT, + + CONSTRAINT "Message_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Ia" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "model" TEXT NOT NULL, + "parameters" JSONB NOT NULL, + + CONSTRAINT "Ia_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_rppsNumber_key" ON "User"("rppsNumber"); + +-- CreateIndex +CREATE UNIQUE INDEX "Appointment_idConsultation_key" ON "Appointment"("idConsultation"); + +-- AddForeignKey +ALTER TABLE "Consultation" ADD CONSTRAINT "Consultation_idMedecin_fkey" FOREIGN KEY ("idMedecin") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Consultation" ADD CONSTRAINT "Consultation_idPatient_fkey" FOREIGN KEY ("idPatient") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "File" ADD CONSTRAINT "File_id_fkey" FOREIGN KEY ("id") REFERENCES "Consultation"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_idDermatologue_fkey" FOREIGN KEY ("idDermatologue") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_idPatient_fkey" FOREIGN KEY ("idPatient") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Appointment" ADD CONSTRAINT "Appointment_idConsultation_fkey" FOREIGN KEY ("idConsultation") REFERENCES "Consultation"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Conversation" ADD CONSTRAINT "Conversation_idFrom_fkey" FOREIGN KEY ("idFrom") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Conversation" ADD CONSTRAINT "Conversation_idToUser_fkey" FOREIGN KEY ("idToUser") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Conversation" ADD CONSTRAINT "Conversation_idToIa_fkey" FOREIGN KEY ("idToIa") REFERENCES "Ia"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Message" ADD CONSTRAINT "Message_idConversation_fkey" FOREIGN KEY ("idConversation") REFERENCES "Conversation"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Message" ADD CONSTRAINT "Message_idFrom_fkey" FOREIGN KEY ("idFrom") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/src/appointments/appointments.controller.ts b/src/appointments/appointments.controller.ts index 7410516..86733da 100644 --- a/src/appointments/appointments.controller.ts +++ b/src/appointments/appointments.controller.ts @@ -29,7 +29,7 @@ export class AppointmentsController { @Get(':id') findOne(@Param('id') id: string) { - return this.appointmentsService.findOne(+id); + return this.appointmentsService.findOne(id); } @Patch(':id') @@ -37,11 +37,11 @@ export class AppointmentsController { @Param('id') id: string, @Body() updateAppointmentDto: UpdateAppointmentDto, ) { - return this.appointmentsService.update(+id, updateAppointmentDto); + return this.appointmentsService.update(id, updateAppointmentDto); } @Delete(':id') remove(@Param('id') id: string) { - return this.appointmentsService.remove(+id); + return this.appointmentsService.remove(id); } } diff --git a/src/appointments/appointments.service.ts b/src/appointments/appointments.service.ts index 05fd45b..568b7ba 100644 --- a/src/appointments/appointments.service.ts +++ b/src/appointments/appointments.service.ts @@ -36,15 +36,28 @@ export class AppointmentsService { return this.prismaService.appointment.findMany(); } - findOne(id: number) { - return `This action returns a #${id} appointment`; + findOne(id: string) { + return this.prismaService.appointment.findUnique({ + where: { + id: id, + }, + }); } - update(id: number, updateAppointmentDto: UpdateAppointmentDto) { - return `This action updates a #${id} appointment`; + update(id: string, updateAppointmentDto: UpdateAppointmentDto) { + return this.prismaService.appointment.update({ + where: { + id: id, + }, + data: updateAppointmentDto as Appointment, + }); } - remove(id: number) { - return `This action removes a #${id} appointment`; + remove(id: string) { + return this.prismaService.appointment.delete({ + where: { + id: id, + }, + }); } } diff --git a/src/appointments/dto/create-appointment.dto.ts b/src/appointments/dto/create-appointment.dto.ts index f9bf696..80e7488 100644 --- a/src/appointments/dto/create-appointment.dto.ts +++ b/src/appointments/dto/create-appointment.dto.ts @@ -1 +1,36 @@ -export class CreateAppointmentDto {} +import { ApiProperty } from '@nestjs/swagger'; +import { statusAppointment } from '@prisma/client'; +import { + IsDateString, + IsEnum, + IsNotEmpty, + IsOptional, + IsString, +} from 'class-validator'; + +export class CreateAppointmentDto { + @ApiProperty() + @IsNotEmpty() + @IsString() + idDermatologue: string; + + @ApiProperty() + @IsNotEmpty() + @IsString() + idPatient: string; + + @ApiProperty() + @IsNotEmpty() + @IsDateString() + date: Date; + + @ApiProperty({ enum: statusAppointment, default: statusAppointment.WAITING }) + @IsOptional() + @IsEnum(statusAppointment) + status: statusAppointment; + + @ApiProperty() + @IsNotEmpty() + @IsString() + idConsultation: string; +} diff --git a/src/patients/patients.controller.ts b/src/patients/patients.controller.ts index 612f69c..6408f5b 100644 --- a/src/patients/patients.controller.ts +++ b/src/patients/patients.controller.ts @@ -5,7 +5,6 @@ import { UseGuards, Req, HttpException, - Post, } from '@nestjs/common'; import { PatientsService } from './patients.service'; import { ConsultationsService } from 'src/consultations/consultations.service'; From a5a0781d97eaf5e580ab2e24276068c82c1fe21a Mon Sep 17 00:00:00 2001 From: DimitriRomano Date: Thu, 22 Feb 2024 16:33:04 +0100 Subject: [PATCH 3/4] add sanitizer guard --- package.json | 3 ++- src/main.ts | 2 ++ src/sanitizer.guard.ts | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/sanitizer.guard.ts diff --git a/package.json b/package.json index 2b940b0..b79c4ba 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "rxjs": "^7.8.1", "uuid": "^9.0.1", "winston": "^3.11.0", - "winston-daily-rotate-file": "^4.7.1" + "winston-daily-rotate-file": "^4.7.1", + "xss": "^1.0.14" }, "devDependencies": { "@nestjs/cli": "^10.0.0", diff --git a/src/main.ts b/src/main.ts index a64cc6b..1d306d4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,12 +3,14 @@ import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; import { LoggingInterceptor } from './logger/logger.interceptor'; import { ValidationPipe, ClassSerializerInterceptor } from '@nestjs/common'; +import { SanitizerGuard } from './sanitizer.guard'; declare const module: any; async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors({ origin: '*' }); app.useGlobalInterceptors(new LoggingInterceptor()); + app.useGlobalGuards(new SanitizerGuard()); app.useGlobalPipes(new ValidationPipe({ whitelist: true })); app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector))); diff --git a/src/sanitizer.guard.ts b/src/sanitizer.guard.ts new file mode 100644 index 0000000..19f1377 --- /dev/null +++ b/src/sanitizer.guard.ts @@ -0,0 +1,35 @@ +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; +import { Observable } from 'rxjs'; +import xss from 'xss'; + +@Injectable() +export class SanitizerGuard implements CanActivate { + canActivate( + context: ExecutionContext, + ): boolean | Promise | Observable { + const request = context.switchToHttp().getRequest(); + + if (request.body) { + request.body = this.cleanData(request.body); + } + + if (request.query) { + request.query = this.cleanData(request.query); + } + + if (request.params) { + request.params = this.cleanData(request.params); + } + + return true; + } + private cleanData(data: Record): Record { + for (const key in data) { + if (data.hasOwnProperty(key) && typeof data[key] === 'string') { + data[key] = xss(data[key]); + } + } + + return data; + } +} From a0d884cba72d81a6b45a95927de567d5dfe8f8c4 Mon Sep 17 00:00:00 2001 From: DimitriRomano Date: Mon, 11 Mar 2024 23:03:36 +0100 Subject: [PATCH 4/4] Update swagger --- src/appointments/appointments.controller.ts | 9 ++- src/patients/dto/create-patient.dto.ts | 65 ++++++++++++++++++++- src/patients/patients.controller.ts | 4 ++ 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/appointments/appointments.controller.ts b/src/appointments/appointments.controller.ts index 86733da..789d7a6 100644 --- a/src/appointments/appointments.controller.ts +++ b/src/appointments/appointments.controller.ts @@ -10,29 +10,34 @@ import { import { AppointmentsService } from './appointments.service'; import { CreateAppointmentDto } from './dto/create-appointment.dto'; import { UpdateAppointmentDto } from './dto/update-appointment.dto'; -import { ApiTags } from '@nestjs/swagger'; +import { ApiCreatedResponse, ApiOkResponse, ApiTags } from '@nestjs/swagger'; +import { AppointmentEntity } from './entities/appointment.entity'; @Controller('appointments') -@ApiTags('patients') +@ApiTags('Appointments') export class AppointmentsController { constructor(private readonly appointmentsService: AppointmentsService) {} @Post() + @ApiCreatedResponse({ type: CreateAppointmentDto }) create(@Body() createAppointmentDto: CreateAppointmentDto) { return this.appointmentsService.create(createAppointmentDto); } @Get() + @ApiOkResponse({ isArray: true, type: AppointmentEntity }) findAll() { return this.appointmentsService.findAll(); } @Get(':id') + @ApiOkResponse({ type: AppointmentEntity }) findOne(@Param('id') id: string) { return this.appointmentsService.findOne(id); } @Patch(':id') + @ApiCreatedResponse({ type: UpdateAppointmentDto }) update( @Param('id') id: string, @Body() updateAppointmentDto: UpdateAppointmentDto, diff --git a/src/patients/dto/create-patient.dto.ts b/src/patients/dto/create-patient.dto.ts index f63454c..1c057fc 100644 --- a/src/patients/dto/create-patient.dto.ts +++ b/src/patients/dto/create-patient.dto.ts @@ -1 +1,64 @@ -export class CreatePatientDto {} +import { ApiProperty } from '@nestjs/swagger'; +import { Role } from '@prisma/client'; +import { + IsEnum, + IsNotEmpty, + IsOptional, + IsString, + MinLength, +} from 'class-validator'; + +export class CreatePatientDto { + @IsNotEmpty() + @IsString() + @ApiProperty() + firstName: string; + + @IsNotEmpty() + @IsString() + @ApiProperty() + lastName: string; + + @IsOptional() + @IsEnum(Role) + @ApiProperty({ + enum: Role, + default: Role.PATIENT, + }) + role: Role; + + @IsString() + @IsNotEmpty() + @ApiProperty() + email: string; + + @IsString() + @IsNotEmpty() + @ApiProperty({ default: 'M' }) + sexe: string; + + @IsString() + @IsNotEmpty() + @MinLength(6) + @ApiProperty() + password: string; + + @ApiProperty({ required: false }) + @IsOptional() + @IsString() + address?: string; + + @ApiProperty({ required: false }) + @IsOptional() + @IsString() + city?: string; + + @ApiProperty({ required: false }) + @IsOptional() + @IsString() + zipCode?: string; + + @ApiProperty({ required: true }) + @IsString() + secuNumber: string; +} diff --git a/src/patients/patients.controller.ts b/src/patients/patients.controller.ts index 6408f5b..5c58ca5 100644 --- a/src/patients/patients.controller.ts +++ b/src/patients/patients.controller.ts @@ -15,6 +15,7 @@ import { User } from '@prisma/client'; import { RolesGuard } from 'src/auth/roles.guard'; import { HasRole } from 'src/auth/has-role.decorator'; import { ConsultationEntity } from 'src/consultations/entities/consultation.entity'; +import { PatientEntity } from './entities/patient.entity'; @Controller('patients') @ApiTags('patients') @@ -25,11 +26,13 @@ export class PatientsController { ) {} @Get() + @ApiOkResponse({ type: PatientEntity, isArray: true }) findAll() { return this.patientsService.findAll(); } @Get(':id') + @ApiOkResponse({ type: PatientEntity }) findOne(@Param('id') id: string) { return this.patientsService.findOne(id); } @@ -37,6 +40,7 @@ export class PatientsController { @ApiBearerAuth() @HasRole('PATIENT', 'ADMIN') @UseGuards(JwtAuthGuard, RolesGuard) + @ApiOkResponse({ type: ConsultationEntity, isArray: true }) @Get(':id/consultations') getConsultationsByPatientId(@Param('id') id: string) { return this.consultationService.getConsultationsByPatientId(id);