Переглянути джерело

(feat) mise en place de l'autentification

Brin AMONKONAN 1 рік тому
батько
коміт
bdd04e9209

+ 2 - 0
node_app/Dockerfile

@@ -23,6 +23,8 @@ RUN npm install --force
 COPY . .
 # Regénérer Prisma si utilisé
 RUN npx prisma generate
+# Appliquer les migrations à la DB (base déjà configurée via DATABASE_URL)
+RUN npx prisma migrate deploy
 # Nettoyage éventuel (optionnel, à mettre *après* la copie du code)
 RUN npm cache clean --force
 RUN npm run build

+ 14 - 0
node_app/prisma/migrations/20250504094504_make_user_fields_optional/migration.sql

@@ -0,0 +1,14 @@
+/*
+  Warnings:
+
+  - A unique constraint covering the columns `[email]` on the table `User` will be added. If there are existing duplicate values, this will fail.
+
+*/
+-- AlterTable
+ALTER TABLE `User` MODIFY `name` VARCHAR(191) NULL,
+    MODIFY `otherName` VARCHAR(191) NULL,
+    MODIFY `address` VARCHAR(191) NULL,
+    MODIFY `telephone` VARCHAR(191) NULL;
+
+-- CreateIndex
+CREATE UNIQUE INDEX `User_email_key` ON `User`(`email`);

+ 6 - 6
node_app/prisma/schema.prisma

@@ -35,12 +35,12 @@ model Driver {
 
 model User {
   id             Int           @id @default(autoincrement())
-  name           String
-  otherName      String
-  address        String
-  telephone      String
-  email          String
-  password       String
+  name           String?       // Rendu optionnel
+  otherName      String?       // Rendu optionnel
+  address        String?       // Rendu optionnel
+  telephone      String?       // Rendu optionnel
+  email          String        @unique // Reste obligatoire
+  password       String        // Reste obligatoire
   reservations   Reservation[] @relation("UserReservations")
   driver         Driver?       @relation("UserDriver")
   managedCompany Company?      @relation("CompanyManager")

+ 55 - 2
node_app/src/app.module.ts

@@ -1,4 +1,4 @@
-import { Module } from '@nestjs/common';
+import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
 import { ConfigModule } from '@nestjs/config';
 import { PrismaModule } from './infrastructure/database/prisma.module';
 import { ServicesModule } from './infrastructure/services/services.module';
@@ -19,6 +19,23 @@ import { VehiculeRepository } from './infrastructure/database/repositories/vehic
 import { VehiculeMapper } from './infrastructure/mappers/vehicule.mapper';
 import { UpdateCompanyUseCase } from './application/use-cases/company/update-company.use-case';
 import { UserMapper } from './infrastructure/mappers/user.mapper';
+import { CreateDriverUseCase } from './application/use-cases/driver/create-driver.use-case';
+import { UpdateDriverUseCase } from './application/use-cases/driver/update-driver.use-case';
+import { DriverRepository } from './infrastructure/database/repositories/driver.repository';
+import { DriverMapper } from './infrastructure/mappers/driver.mapper';
+import { CreateVehiculeUseCase } from './application/use-cases/vehicle/create-vehicle.use-case';
+import { UpdateVehiculeUseCase } from './application/use-cases/vehicle/update-vehicle.use-case';
+import { UpdateTrajetUseCase } from './application/use-cases/trajet/update-trajet.use-case';
+import { TrajetRepository } from './infrastructure/database/repositories/trajet.repository';
+import { TrajetMapper } from './infrastructure/mappers/trajet.mapper';
+import { DebugMiddleware } from './middleware/debug.middleware';
+import { FindUserByIdUseCase } from './application/use-cases/find-user-by-id.use-case';
+import { DeleteUserUseCase } from './application/use-cases/delete-user.use-case';
+import { FindAllUsersUseCase } from './application/use-cases/find-all-users.use-case';
+import { AuthController } from './presentation/controllers/auth.controller';
+import { AuthService } from './infrastructure/services/auth.service';
+import { APP_GUARD } from '@nestjs/core';
+import { AuthGuard } from './presentation/guards/auth.guard';
 
 @Module({
   imports: [
@@ -35,12 +52,25 @@ import { UserMapper } from './infrastructure/mappers/user.mapper';
     PlaceController,
     VehiculeController,
     TrajetController,
+    AuthController, // Ajout du AuthController
   ],
   providers: [
+    // Configuration du AuthGuard global
+    {
+      provide: APP_GUARD,
+      useClass: AuthGuard,
+    },
     // User related providers
     CreateUserUseCase,
     UpdateUserUseCase,
+    FindUserByIdUseCase,
+    DeleteUserUseCase,
+    FindAllUsersUseCase,
     UserMapper,
+    {
+      provide: 'IAuthService',
+      useClass: AuthService,
+    },
     {
       provide: 'IUserRepository',
       useClass: UserRepository,
@@ -56,12 +86,35 @@ import { UserMapper } from './infrastructure/mappers/user.mapper';
       useClass: CompanyRepository,
     },
 
+    // Driver related providers
+    CreateDriverUseCase,
+    UpdateDriverUseCase,
+    DriverMapper,
+    {
+      provide: 'DriverRepository',
+      useClass: DriverRepository,
+    },
+
     // Vehicule related providers
+    CreateVehiculeUseCase,
+    UpdateVehiculeUseCase,
     VehiculeMapper,
     {
       provide: 'VehiculeRepository',
       useClass: VehiculeRepository,
     },
+
+    // Trajet related providers
+    UpdateTrajetUseCase,
+    TrajetMapper,
+    {
+      provide: 'TrajetRepository',
+      useClass: TrajetRepository,
+    },
   ],
 })
-export class AppModule {}
+export class AppModule implements NestModule {
+  configure(consumer: MiddlewareConsumer) {
+    consumer.apply(DebugMiddleware).forRoutes('*');
+  }
+}

+ 41 - 13
node_app/src/application/dto/create-user.dto.ts

@@ -3,34 +3,62 @@ import {
   IsString,
   IsNotEmpty,
   MinLength,
-  IsNumber,
+  IsOptional,
 } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
 
 export class CreateUserDto {
-  @IsNotEmpty()
-  @IsNumber()
-  id: string;
-
-  @IsNotEmpty()
+  @ApiProperty({
+    description: "Le nom de l'utilisateur",
+    example: 'Dupont',
+    required: false,
+  })
+  @IsOptional()
   @IsString()
-  name: string;
+  name?: string;
 
-  @IsNotEmpty()
+  @ApiProperty({
+    description: "Le prénom de l'utilisateur",
+    example: 'Jean',
+    required: false,
+  })
+  @IsOptional()
   @IsString()
-  otherName: string;
+  otherName?: string;
 
-  @IsNotEmpty()
+  @ApiProperty({
+    description: "L'adresse de l'utilisateur",
+    example: '123 Rue de la Paix, 75000 Paris',
+    required: false,
+  })
+  @IsOptional()
   @IsString()
-  address: string;
+  address?: string;
 
-  @IsNotEmpty()
+  @ApiProperty({
+    description: "Le numéro de téléphone de l'utilisateur",
+    example: '+33612345678',
+    required: false,
+  })
+  @IsOptional()
   @IsString()
-  telephone: string;
+  telephone?: string;
 
+  @ApiProperty({
+    description: "L'adresse email de l'utilisateur",
+    example: 'jean.dupont@example.com',
+    required: true,
+  })
   @IsNotEmpty()
   @IsEmail()
   email: string;
 
+  @ApiProperty({
+    description: "Le mot de passe de l'utilisateur",
+    example: 'motdepasse123',
+    required: true,
+    minLength: 6,
+  })
   @IsNotEmpty()
   @IsString()
   @MinLength(6)

+ 22 - 4
node_app/src/application/use-cases/create-user.use-case.ts

@@ -1,17 +1,35 @@
 import { Injectable, Inject } from '@nestjs/common';
 import { IUserRepository } from '../interfaces/i-user.repository';
 import { CreateUserDto } from '../dto/create-user.dto';
-import { UserResponseDto } from '../dto/responses/user-response.dto';
+import { UserMapper } from 'src/infrastructure/mappers/user.mapper';
+import { HasherService } from '../../infrastructure/services/hasher.service';
 
 @Injectable()
 export class CreateUserUseCase {
   constructor(
     @Inject('IUserRepository')
     private readonly userRepository: IUserRepository,
+    private readonly userMapper: UserMapper,
+    private readonly passwordHashService: HasherService,
   ) {}
 
-  async execute(createUserDto: CreateUserDto): Promise<UserResponseDto> {
-    const user = await this.userRepository.create(createUserDto);
-    return UserResponseDto.fromEntity(user);
+  async execute(createUserDto: CreateUserDto) {
+    // Hasher le mot de passe avant de créer l'utilisateur
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+    const hashedPassword = await this.passwordHashService.hash(
+      createUserDto.password,
+    );
+
+    // Créer un nouvel objet avec le mot de passe hashé
+    const userWithHashedPassword = {
+      ...createUserDto,
+      password: hashedPassword,
+    };
+
+    // Convertir le DTO en entité de domaine
+    const createUser = this.userMapper.fromDtoToDomain(userWithHashedPassword);
+
+    // Créer l'utilisateur dans la base de données
+    return this.userRepository.create(createUser);
   }
 }

+ 23 - 0
node_app/src/application/use-cases/delete-user.use-case.ts

@@ -0,0 +1,23 @@
+import { Injectable, Inject, NotFoundException } from '@nestjs/common';
+import { IUserRepository } from '../interfaces/i-user.repository';
+import { UserMapper } from '../../infrastructure/mappers/user.mapper';
+
+@Injectable()
+export class DeleteUserUseCase {
+  constructor(
+    @Inject('IUserRepository')
+    private readonly userRepository: IUserRepository,
+    private readonly userMapper: UserMapper,
+  ) {}
+
+  async execute(id: number): Promise<void> {
+    const user = await this.userRepository.findById(id);
+
+    if (!user) {
+      throw new NotFoundException(`Utilisateur avec l'ID ${id} non trouvé`);
+    }
+    const deletedUser = this.userMapper.fromDtoToDomain(user);
+    // Retourner les informations de l'utilisateur supprimé
+    void this.userRepository.delete(deletedUser.id);
+  }
+}

+ 16 - 0
node_app/src/application/use-cases/find-all-users.use-case.ts

@@ -0,0 +1,16 @@
+import { Injectable, Inject } from '@nestjs/common';
+import { IUserRepository } from '../interfaces/i-user.repository';
+import { UserResponseDto } from '../dto/responses/user-response.dto';
+
+@Injectable()
+export class FindAllUsersUseCase {
+  constructor(
+    @Inject('IUserRepository')
+    private readonly userRepository: IUserRepository,
+  ) {}
+
+  async execute(): Promise<UserResponseDto[]> {
+    const users = await this.userRepository.findAll();
+    return users.map((user) => UserResponseDto.fromEntity(user));
+  }
+}

+ 23 - 0
node_app/src/application/use-cases/find-user-by-id.use-case.ts

@@ -0,0 +1,23 @@
+import { Injectable, Inject, NotFoundException } from '@nestjs/common';
+import { IUserRepository } from '../interfaces/i-user.repository';
+import { UserResponseDto } from '../dto/responses/user-response.dto';
+import { UserMapper } from 'src/infrastructure/mappers/user.mapper';
+
+@Injectable()
+export class FindUserByIdUseCase {
+  constructor(
+    @Inject('IUserRepository')
+    private readonly userRepository: IUserRepository,
+    private readonly userMapper: UserMapper,
+  ) {}
+
+  async execute(id: number): Promise<UserResponseDto> {
+    const user = await this.userRepository.findById(id);
+
+    if (!user) {
+      throw new NotFoundException(`Utilisateur avec l'ID ${id} non trouvé`);
+    }
+
+    return UserResponseDto.fromEntity(user);
+  }
+}

+ 1 - 0
node_app/src/infrastructure/database/repositories/company.repository.ts

@@ -15,6 +15,7 @@ export class CompanyRepository implements IBaseRepository<Company> {
   constructor(private prisma: PrismaService) {}
 
   async create(data: Company): Promise<Company> {
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
     const prismaCompany = await this.prisma.company.create({
       data: {
         name: data.name,

+ 10 - 3
node_app/src/infrastructure/database/repositories/user.repository.ts

@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unsafe-call */
+/* eslint-disable @typescript-eslint/no-unsafe-assignment */
 import { Injectable } from '@nestjs/common';
 import { PrismaService } from '../prisma.service';
 import { User } from '../../../domain/entities/user.entity';
@@ -20,18 +22,20 @@ export class UserRepository implements IUserRepository {
   }
 
   async findByEmail(email: string): Promise<User | null> {
-    return this.prisma.user.findFirst({
+    const prismaUser = await this.prisma.user.findFirst({
       where: {
         email: email,
       },
     });
+    return prismaUser ? this.userMapper.toDomain(prismaUser) : null;
   }
 
   async update(id: number, data: UpdateUserDto): Promise<User> {
-    return this.prisma.user.update({
+    const prismaUser = await this.prisma.user.update({
       where: { id },
       data,
     });
+    return this.userMapper.toDomain(prismaUser);
   }
 
   async delete(id: number): Promise<void> {
@@ -41,10 +45,13 @@ export class UserRepository implements IUserRepository {
   }
 
   async findAll(): Promise<User[]> {
-    return this.prisma.user.findMany();
+    const prismaUsers = await this.prisma.user.findMany();
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
+    return prismaUsers.map((user) => this.userMapper.toDomain(user));
   }
 
   async create(data: User): Promise<User> {
+    console.log(data);
     const prismaUser = await this.prisma.user.create({
       data: this.userMapper.toPrisma(data),
     });

+ 9 - 8
node_app/src/infrastructure/mappers/user.mapper.ts

@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-unsafe-assignment */
 import { IPrismaMapper } from './prisma-mapper.interface';
 import { User as PrismaUser } from '@prisma/client';
 import { User } from 'src/domain/entities/user.entity';
@@ -6,24 +7,24 @@ export class UserMapper implements IPrismaMapper<PrismaUser, User> {
   toDomain(prismaUser: PrismaUser): User {
     return new User({
       id: prismaUser.id,
-      name: prismaUser.name,
-      otherName: prismaUser.otherName,
+      name: prismaUser.name || undefined,
+      otherName: prismaUser.otherName || undefined,
       email: prismaUser.email,
       password: prismaUser.password,
-      address: prismaUser.address,
-      telephone: prismaUser.telephone,
+      address: prismaUser.address || undefined,
+      telephone: prismaUser.telephone || undefined,
     });
   }
 
   toPrisma(user: User): PrismaUser {
     return {
       id: user.id,
-      name: user.name,
-      otherName: user.otherName,
+      name: user.name || '',
+      otherName: user.otherName || '',
       email: user.email,
       password: user.password,
-      address: user.address,
-      telephone: user.telephone,
+      address: user.address || '',
+      telephone: user.telephone || '',
     };
   }
 

+ 53 - 53
node_app/src/infrastructure/services/mocks/user.repository.mock.ts

@@ -1,53 +1,53 @@
-import { Injectable } from '@nestjs/common';
-import { IUserRepository } from '../../../application/interfaces/i-user.repository';
-import { User } from '../../../domain/entities/user.entity';
-
-@Injectable()
-export class MockUserRepository implements IUserRepository {
-  private users: User[] = [
-    {
-      id: 1,
-      name: 'Utilisateur Test',
-      address: '123 Rue de Test',
-      telephone: '+33123456789',
-      otherName: 'Test',
-      email: 'test@example.com',
-      password: 'hashedPassword',
-    },
-  ];
-
-  async create(user: User): Promise<User> {
-    const newUser = { ...user, id: this.users.length + 1 };
-    this.users.push(newUser);
-    return newUser;
-  }
-
-  async findById(id: number): Promise<User | null> {
-    return this.users.find((user) => user.id === id) || null;
-  }
-
-  async findByEmail(email: string): Promise<User | null> {
-    return this.users.find((user) => user.email === email) || null;
-  }
-
-  async findAll(): Promise<User[]> {
-    return [...this.users];
-  }
-
-  async update(id: number, user: Partial<User>): Promise<User | null> {
-    const index = this.users.findIndex((u) => u.id === id);
-    if (index === -1) return null;
-    
-    this.users[index] = { ...this.users[index], ...user };
-    return this.users[index];
-  }
-
-  async delete(id: number): Promise<User | null> {
-    const index = this.users.findIndex((u) => u.id === id);
-    if (index === -1) return null;
-    
-    const deletedUser = this.users[index];
-    this.users.splice(index, 1);
-    return deletedUser;
-  }
-}
+// import { Injectable } from '@nestjs/common';
+// import { IUserRepository } from '../../../application/interfaces/i-user.repository';
+// import { User } from '../../../domain/entities/user.entity';
+
+// @Injectable()
+// export class MockUserRepository implements IUserRepository {
+//   private users: User[] = [
+//     {
+//       id: 1,
+//       name: 'Utilisateur Test',
+//       address: '123 Rue de Test',
+//       telephone: '+33123456789',
+//       otherName: 'Test',
+//       email: 'test@example.com',
+//       password: 'hashedPassword',
+//     },
+//   ];
+
+//   async create(user: User): Promise<User> {
+//     const newUser = { ...user, id: this.users.length + 1 };
+//     this.users.push(newUser);
+//     return newUser;
+//   }
+
+//   async findById(id: number): Promise<User | null> {
+//     return this.users.find((user) => user.id === id) || null;
+//   }
+
+//   async findByEmail(email: string): Promise<User | null> {
+//     return this.users.find((user) => user.email === email) || null;
+//   }
+
+//   async findAll(): Promise<User[]> {
+//     return [...this.users];
+//   }
+
+//   async update(id: number, user: Partial<User>): Promise<User | null> {
+//     const index = this.users.findIndex((u) => u.id === id);
+//     if (index === -1) return null;
+
+//     this.users[index] = { ...this.users[index], ...user };
+//     return this.users[index];
+//   }
+
+//   async delete(id: number): Promise<User | null> {
+//     const index = this.users.findIndex((u) => u.id === id);
+//     if (index === -1) return null;
+
+//     const deletedUser = this.users[index];
+//     this.users.splice(index, 1);
+//     return deletedUser;
+//   }
+// }

+ 29 - 0
node_app/src/interceptors/body-parser.interceptor.ts

@@ -0,0 +1,29 @@
+import {
+  CallHandler,
+  ExecutionContext,
+  Injectable,
+  NestInterceptor,
+} from '@nestjs/common';
+import { Observable } from 'rxjs';
+
+@Injectable()
+export class BodyParserInterceptor implements NestInterceptor {
+  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+    const request = context.switchToHttp().getRequest();
+    console.log('Intercepteur - Headers:', request.headers);
+    console.log('Intercepteur - Body brut:', request.body);
+
+    // Si le body est une chaîne, essayer de le parser
+    if (typeof request.body === 'string') {
+      try {
+        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+        request.body = JSON.parse(request.body);
+      } catch (e) {
+        console.error('Erreur de parsing JSON:', e);
+      }
+    }
+
+    return next.handle();
+  }
+}

+ 5 - 2
node_app/src/main.ts

@@ -13,7 +13,9 @@ import {
 async function bootstrap() {
   const app = await NestFactory.create<NestFastifyApplication>(
     AppModule,
-    new FastifyAdapter(),
+    new FastifyAdapter({
+      logger: true,
+    }),
   );
 
   // swagger document
@@ -22,6 +24,7 @@ async function bootstrap() {
     .setDescription('The Transport API description')
     .setVersion('1.0')
     .addTag('Transport')
+    .addServer('/api') // Ajout explicite du préfixe API comme serveur
     .build();
 
   const document = SwaggerModule.createDocument(app, config, {
@@ -40,8 +43,8 @@ async function bootstrap() {
     }),
   );
 
+  app.enableCors();
   app.useGlobalInterceptors(new TransformInterceptor());
-
   app.setGlobalPrefix('api');
 
   // Try to connect to database with retries

+ 12 - 0
node_app/src/middleware/debug.middleware.ts

@@ -0,0 +1,12 @@
+import { Injectable, NestMiddleware } from '@nestjs/common';
+import { Request, Response, NextFunction } from 'express';
+
+@Injectable()
+export class DebugMiddleware implements NestMiddleware {
+  use(req: Request, res: Response, next: NextFunction) {
+    console.log('Headers:', req.headers);
+    console.log('Body:', req.body);
+    console.log('Content-Type:', req.headers['content-type']);
+    next();
+  }
+}

+ 75 - 0
node_app/src/presentation/controllers/auth.controller.ts

@@ -0,0 +1,75 @@
+import {
+  Controller,
+  Post,
+  Body,
+  UnauthorizedException,
+  UseGuards,
+  Req,
+  HttpCode,
+  HttpStatus,
+} from '@nestjs/common';
+import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
+import { IAuthService } from '../../application/interfaces/i-auth.service';
+import { Inject } from '@nestjs/common';
+import { AuthGuard } from '../guards/auth.guard';
+import { UserResponseDto } from '../../application/dto/responses/user-response.dto';
+import { User } from 'src/domain/entities/user.entity';
+
+class LoginDto {
+  email: string;
+  password: string;
+}
+
+@ApiTags('Authentification')
+@Controller('auth')
+export class AuthController {
+  constructor(
+    @Inject('IAuthService')
+    private readonly authService: IAuthService,
+  ) {}
+
+  @Post('login')
+  @HttpCode(HttpStatus.OK)
+  @ApiOperation({ description: 'Connexion utilisateur' })
+  @ApiResponse({ status: 200, description: 'Connexion réussie' })
+  @ApiResponse({ status: 401, description: 'Identifiants invalides' })
+  async login(@Body() loginDto: LoginDto) {
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+    const user: User = await this.authService.validateUser(
+      loginDto.email,
+      loginDto.password,
+    );
+
+    if (!user) {
+      throw new UnauthorizedException('Identifiants invalides');
+    }
+
+    const token = await this.authService.generateToken(user);
+
+    // Retourner les informations de l'utilisateur sans le mot de passe
+    const userResponse = UserResponseDto.fromEntity(user);
+
+    return {
+      user: userResponse,
+      access_token: token,
+    };
+  }
+
+  @Post('logout')
+  @UseGuards(AuthGuard)
+  @HttpCode(HttpStatus.OK)
+  @ApiOperation({ description: 'Déconnexion utilisateur' })
+  @ApiResponse({ status: 200, description: 'Déconnexion réussie' })
+  @ApiResponse({ status: 401, description: 'Non autorisé' })
+  logout(@Req() request: any) {
+    // Comme nous utilisons des JWT, la déconnexion côté serveur n'est pas nécessaire
+    // Le client doit simplement supprimer le token
+    // Mais nous pouvons ajouter une logique supplémentaire ici si nécessaire
+
+    return {
+      message: 'Déconnexion réussie',
+      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+      userId: request.user.sub,
+    };
+  }
+}

+ 78 - 8
node_app/src/presentation/controllers/user.controller.ts

@@ -6,31 +6,101 @@ import {
   Param,
   Put,
   Delete,
+  ParseIntPipe,
+  Patch,
 } from '@nestjs/common';
 import { CreateUserUseCase } from '../../application/use-cases/create-user.use-case';
 import { CreateUserDto } from '../../application/dto/create-user.dto';
+import { ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
+import { UseInterceptors } from '@nestjs/common';
+import { BodyParserInterceptor } from '../../interceptors/body-parser.interceptor';
+import { FindUserByIdUseCase } from '../../application/use-cases/find-user-by-id.use-case';
+import { UpdateUserUseCase } from '../../application/use-cases/update-user.use-case';
+import { UpdateUserDto } from '../../application/dto/update-user.dto';
+import { DeleteUserUseCase } from '../../application/use-cases/delete-user.use-case';
+import { FindAllUsersUseCase } from '../../application/use-cases/find-all-users.use-case';
 
 @Controller('users')
+@UseInterceptors(BodyParserInterceptor)
 export class UserController {
-  constructor(private readonly createUserUseCase: CreateUserUseCase) {}
+  constructor(
+    private readonly createUserUseCase: CreateUserUseCase,
+    private readonly findUserByIdUseCase: FindUserByIdUseCase,
+    private readonly updateUserUseCase: UpdateUserUseCase,
+    private readonly deleteUserUseCase: DeleteUserUseCase,
+    private readonly findAllUsersUseCase: FindAllUsersUseCase,
+  ) {}
 
   @Post()
+  @ApiOperation({ description: 'Creater un utilisateur' })
+  @ApiResponse({ status: 200 })
   async create(@Body() createUserDto: CreateUserDto) {
-    return this.createUserUseCase.execute(createUserDto);
+    //console.log('Requête reçue:', JSON.stringify(createUserDto));
+    // eslint-disable-next-line no-useless-catch
+    try {
+      const result = await this.createUserUseCase.execute(createUserDto);
+
+      return result;
+    } catch (error) {
+      throw error;
+    }
   }
 
   @Get(':id')
-  async findOne(@Param('id') id: string) {
-    // À implémenter avec le cas d'utilisation approprié
+  @ApiOperation({ description: 'Récupérer un utilisateur par son ID' })
+  @ApiResponse({ status: 200, description: 'Utilisateur trouvé' })
+  @ApiResponse({ status: 404, description: 'Utilisateur non trouvé' })
+  @ApiParam({ name: 'id', description: "ID de l'utilisateur", type: 'number' })
+  async findOne(@Param('id', ParseIntPipe) id: number) {
+    return this.findUserByIdUseCase.execute(id);
   }
 
   @Put(':id')
-  async update(@Param('id') id: string, @Body() updateUserDto: any) {
-    // À implémenter avec le cas d'utilisation approprié
+  @ApiOperation({ description: 'Mettre à jour un utilisateur par son ID' })
+  @ApiResponse({
+    status: 200,
+    description: 'Utilisateur mis à jour avec succès',
+  })
+  @ApiResponse({ status: 404, description: 'Utilisateur non trouvé' })
+  @ApiParam({ name: 'id', description: "ID de l'utilisateur", type: 'number' })
+  async update(
+    @Param('id', ParseIntPipe) id: number,
+    @Body() updateUserDto: UpdateUserDto,
+  ) {
+    return this.updateUserUseCase.execute(id, updateUserDto);
+  }
+
+  @Patch(':id')
+  @ApiOperation({
+    description: 'Mettre à jour partiellement un utilisateur par son ID',
+  })
+  @ApiResponse({
+    status: 200,
+    description: 'Utilisateur partiellement mis à jour avec succès',
+  })
+  @ApiResponse({ status: 404, description: 'Utilisateur non trouvé' })
+  @ApiParam({ name: 'id', description: "ID de l'utilisateur", type: 'number' })
+  async partialUpdate(
+    @Param('id', ParseIntPipe) id: number,
+    @Body() partialUpdateDto: Partial<UpdateUserDto>,
+  ) {
+    return this.updateUserUseCase.execute(id, partialUpdateDto);
   }
 
   @Delete(':id')
-  async remove(@Param('id') id: string) {
-    // À implémenter avec le cas d'utilisation approprié
+  @ApiOperation({ description: 'Supprimer un utilisateur par son ID' })
+  @ApiResponse({ status: 200, description: 'Utilisateur supprimé avec succès' })
+  @ApiResponse({ status: 404, description: 'Utilisateur non trouvé' })
+  @ApiParam({ name: 'id', description: "ID de l'utilisateur", type: 'number' })
+  async remove(@Param('id', ParseIntPipe) id: number) {
+    await this.deleteUserUseCase.execute(id);
+    return { message: 'Utilisateur supprimé avec succès' };
+  }
+
+  @Get()
+  @ApiOperation({ description: 'Récupérer tous les utilisateurs' })
+  @ApiResponse({ status: 200, description: 'Liste des utilisateurs' })
+  async findAll() {
+    return this.findAllUsersUseCase.execute();
   }
 }

+ 12 - 2
node_app/src/presentation/guards/auth.guard.ts

@@ -1,10 +1,20 @@
-import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
+/* eslint-disable @typescript-eslint/no-unsafe-call */
+/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+import {
+  Injectable,
+  CanActivate,
+  ExecutionContext,
+  Inject,
+} from '@nestjs/common';
 import { Observable } from 'rxjs';
 import { IAuthService } from '../../application/interfaces/i-auth.service';
 
 @Injectable()
 export class AuthGuard implements CanActivate {
-  constructor(private readonly authService: IAuthService) {}
+  constructor(
+    @Inject('IAuthService')
+    private readonly authService: IAuthService,
+  ) {}
 
   canActivate(
     context: ExecutionContext,