only super admin can remove users now

This commit is contained in:
sdraris 2025-09-17 16:05:47 +02:00
parent c8635c4d09
commit 0823ffc5cf
2 changed files with 63 additions and 17 deletions

View File

@ -71,13 +71,24 @@ export class UserController {
return this.userService.validateUser(id, currentUser, comment); return this.userService.validateUser(id, currentUser, comment);
} }
@Patch(':id/suspendre')
// Supprimer un utilisateur (super_admin et gestionnaire)
@Delete(':id')
@Roles(RoleType.SUPER_ADMIN, RoleType.GESTIONNAIRE, RoleType.ADMINISTRATEUR) @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' }) @ApiOperation({ summary: 'Supprimer un utilisateur' })
@ApiParam({ name: 'id', description: "UUID de l'utilisateur" }) @ApiParam({ name: 'id', description: "UUID de l'utilisateur" })
remove(@Param('id') id: string) { remove(@Param('id') id: string, @User() currentUser: Users) {
return this.userService.remove(id); return this.userService.remove(id, currentUser);
} }
} }

View File

@ -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 { InjectRepository } from "@nestjs/typeorm";
import { RoleType, StatutUtilisateurType, Users } from "src/entities/users.entity"; import { RoleType, StatutUtilisateurType, Users } from "src/entities/users.entity";
import { Repository } from "typeorm"; import { Repository } from "typeorm";
@ -19,12 +19,44 @@ export class UserService {
// Création utilisateur // Création utilisateur
async createUser(dto: CreateUserDto, currentUser?: Users): Promise<Users> { async createUser(dto: CreateUserDto, currentUser?: Users): Promise<Users> {
// Sécuriser le rôle // Vérification CGU
if (!currentUser || currentUser.role !== RoleType.SUPER_ADMIN) { if (!dto.cguAccepted) {
dto.role = RoleType.PARENT; 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; let consentDate: Date | undefined;
if (dto.consentement_photo && dto.date_consentement_photo) { if (dto.consentement_photo && dto.date_consentement_photo) {
const parsed = new Date(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 salt = await bcrypt.genSalt();
const hashedPassword = await bcrypt.hash(dto.password, salt); const hashedPassword = await bcrypt.hash(dto.password, salt);
// Création de lentité
const entity = this.usersRepository.create({ const entity = this.usersRepository.create({
email: dto.email, email: dto.email,
password: hashedPassword, password: hashedPassword,
prenom: dto.prenom, prenom: dto.prenom,
nom: dto.nom, nom: dto.nom,
role: dto.role, role,
statut: currentUser?.role === RoleType.SUPER_ADMIN statut,
? dto.statut
: StatutUtilisateurType.EN_ATTENTE,
genre: dto.genre, genre: dto.genre,
telephone: dto.telephone, telephone: dto.telephone,
ville: dto.ville, ville: dto.ville,
@ -54,13 +85,14 @@ export class UserService {
photo_url: dto.photo_url, photo_url: dto.photo_url,
consentement_photo: dto.consentement_photo ?? false, consentement_photo: dto.consentement_photo ?? false,
date_consentement_photo: consentDate, 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); const saved = await this.usersRepository.save(entity);
return this.findOne(saved.id); return this.findOne(saved.id);
} }
async findAll(): Promise<Users[]> { async findAll(): Promise<Users[]> {
return this.usersRepository.find(); return this.usersRepository.find();
} }
@ -124,7 +156,7 @@ export class UserService {
status: StatutValidationType.VALIDE, status: StatutValidationType.VALIDE,
validated_by: currentUser, validated_by: currentUser,
comment comment
}); });
await this.validationRepository.save(validation); await this.validationRepository.save(validation);
return savedUser; return savedUser;
@ -149,7 +181,10 @@ export class UserService {
await this.validationRepository.save(suspend); await this.validationRepository.save(suspend);
return savedUser; return savedUser;
} }
async remove(id: string): Promise<void> { async remove(id: string, currentUser: Users): Promise<void> {
if (currentUser.role !== RoleType.SUPER_ADMIN) {
throw new ForbiddenException('Accès réservé aux super admins');
}
const result = await this.usersRepository.delete(id); const result = await this.usersRepository.delete(id);
if (result.affected === 0) { if (result.affected === 0) {
throw new NotFoundException('Utilisateur introuvable'); throw new NotFoundException('Utilisateur introuvable');