diff --git a/src/routes/user/user.controller.ts b/src/routes/user/user.controller.ts index 0b45b53..3fe3187 100644 --- a/src/routes/user/user.controller.ts +++ b/src/routes/user/user.controller.ts @@ -71,13 +71,24 @@ export class UserController { return this.userService.validateUser(id, currentUser, comment); } - - // Supprimer un utilisateur (super_admin et gestionnaire) - @Delete(':id') + @Patch(':id/suspendre') @Roles(RoleType.SUPER_ADMIN, RoleType.GESTIONNAIRE, RoleType.ADMINISTRATEUR) + @ApiOperation({ summary: 'Suspendre un compte utilisateur' }) + @ApiParam({ name: 'id', description: "UUID de l'utilisateur" }) + suspend( + @Param('id') id: string, + @User() currentUser: Users, + @Body('comment') comment?: string, + ) { + return this.userService.suspendUser(id, currentUser, comment); + } + + // Supprimer un utilisateur (super_admin uniquement) + @Delete(':id') + @Roles(RoleType.SUPER_ADMIN) @ApiOperation({ summary: 'Supprimer un utilisateur' }) @ApiParam({ name: 'id', description: "UUID de l'utilisateur" }) - remove(@Param('id') id: string) { - return this.userService.remove(id); + remove(@Param('id') id: string, @User() currentUser: Users) { + return this.userService.remove(id, currentUser); } } diff --git a/src/routes/user/user.service.ts b/src/routes/user/user.service.ts index f235324..3684159 100644 --- a/src/routes/user/user.service.ts +++ b/src/routes/user/user.service.ts @@ -1,4 +1,4 @@ -import { ForbiddenException, Injectable, NotFoundException } from "@nestjs/common"; +import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { RoleType, StatutUtilisateurType, Users } from "src/entities/users.entity"; import { Repository } from "typeorm"; @@ -19,12 +19,44 @@ export class UserService { // Création utilisateur async createUser(dto: CreateUserDto, currentUser?: Users): Promise { - // Sécuriser le rôle - if (!currentUser || currentUser.role !== RoleType.SUPER_ADMIN) { - dto.role = RoleType.PARENT; + // Vérification CGU + if (!dto.cguAccepted) { + throw new BadRequestException( + 'Vous devez accepter les CGU et la Politique de confidentialité pour créer un compte.', + ); } - // Nettoyage / validation consentement photo + // Déterminer si le créateur est super admin + const isSuperAdmin = currentUser?.role === RoleType.SUPER_ADMIN; + + // Forcer rôle et statut si pas super admin + const role = isSuperAdmin ? dto.role : RoleType.PARENT; + const statut = isSuperAdmin + ? dto.statut ?? StatutUtilisateurType.EN_ATTENTE + : StatutUtilisateurType.EN_ATTENTE; + + // Vérification spécifique pour assistantes maternelles + if (role === RoleType.ASSISTANTE_MATERNELLE && !dto.photo_url) { + throw new BadRequestException( + 'La photo de profil est obligatoire pour les assistantes maternelles.', + ); + } + + // Vérification des champs obligatoires (déjà couverts par DTO, mais double sécurité) + if (!dto.nom?.trim()) { + throw new BadRequestException('Nom est obligatoire.'); + } + else if (!dto.prenom?.trim()) { + throw new BadRequestException('Prénom est obligatoire.'); + } + else if (!dto.adresse?.trim()) { + throw new BadRequestException('Adresse est obligatoire.'); + } + else if (!dto.telephone?.trim()) { + throw new BadRequestException('Téléphone est obligatoire.'); + } + + // Gestion consentement photo let consentDate: Date | undefined; if (dto.consentement_photo && dto.date_consentement_photo) { const parsed = new Date(dto.date_consentement_photo); @@ -37,15 +69,14 @@ export class UserService { const salt = await bcrypt.genSalt(); const hashedPassword = await bcrypt.hash(dto.password, salt); + // Création de l’entité const entity = this.usersRepository.create({ email: dto.email, password: hashedPassword, prenom: dto.prenom, nom: dto.nom, - role: dto.role, - statut: currentUser?.role === RoleType.SUPER_ADMIN - ? dto.statut - : StatutUtilisateurType.EN_ATTENTE, + role, + statut, genre: dto.genre, telephone: dto.telephone, ville: dto.ville, @@ -54,13 +85,14 @@ export class UserService { photo_url: dto.photo_url, consentement_photo: dto.consentement_photo ?? false, date_consentement_photo: consentDate, - changement_mdp_obligatoire: dto.changement_mdp_obligatoire ?? false + changement_mdp_obligatoire: dto.changement_mdp_obligatoire ?? false, }); const saved = await this.usersRepository.save(entity); return this.findOne(saved.id); } + async findAll(): Promise { return this.usersRepository.find(); } @@ -124,7 +156,7 @@ export class UserService { status: StatutValidationType.VALIDE, validated_by: currentUser, comment - + }); await this.validationRepository.save(validation); return savedUser; @@ -149,7 +181,10 @@ export class UserService { await this.validationRepository.save(suspend); return savedUser; } - async remove(id: string): Promise { + async remove(id: string, currentUser: Users): Promise { + if (currentUser.role !== RoleType.SUPER_ADMIN) { + throw new ForbiddenException('Accès réservé aux super admins'); + } const result = await this.usersRepository.delete(id); if (result.affected === 0) { throw new NotFoundException('Utilisateur introuvable');