feat(#105): Statut « refusé » – enum, migration, pending/reprise, refuser, connexion
- Enum statut_utilisateur_type + valeur 'refuse' (migration + BDD.sql) - GET /users/reprise, PATCH /users/:id/refuser (refus_compte en validations) - PATCH /users/:id/valider accepte en_attente et refuse (reprise) - Connexion refusée si statut refuse Made-with: Cursor
This commit is contained in:
parent
dfd58d9b6c
commit
393a527c37
@ -29,6 +29,7 @@ export enum StatutUtilisateurType {
|
||||
EN_ATTENTE = 'en_attente',
|
||||
ACTIF = 'actif',
|
||||
SUSPENDU = 'suspendu',
|
||||
REFUSE = 'refuse',
|
||||
}
|
||||
|
||||
export enum SituationFamilialeType {
|
||||
|
||||
@ -96,6 +96,12 @@ export class AuthService {
|
||||
throw new UnauthorizedException('Votre compte a été suspendu. Contactez un administrateur.');
|
||||
}
|
||||
|
||||
if (user.statut === StatutUtilisateurType.REFUSE) {
|
||||
throw new UnauthorizedException(
|
||||
'Votre compte a été refusé. Vous pouvez corriger votre dossier et le soumettre à nouveau ; un gestionnaire pourra le réexaminer.',
|
||||
);
|
||||
}
|
||||
|
||||
return this.generateTokens(user.id, user.email, user.role);
|
||||
}
|
||||
|
||||
|
||||
@ -50,6 +50,16 @@ export class UserController {
|
||||
return this.userService.findPendingUsers(role);
|
||||
}
|
||||
|
||||
// Lister les comptes refusés (à corriger / reprise)
|
||||
@Get('reprise')
|
||||
@Roles(RoleType.SUPER_ADMIN, RoleType.ADMINISTRATEUR, RoleType.GESTIONNAIRE)
|
||||
@ApiOperation({ summary: 'Lister les comptes refusés (reprise)' })
|
||||
findRefusedUsers(
|
||||
@Query('role') role?: RoleType
|
||||
) {
|
||||
return this.userService.findRefusedUsers(role);
|
||||
}
|
||||
|
||||
// Lister tous les utilisateurs (super_admin uniquement)
|
||||
@Get()
|
||||
@Roles(RoleType.SUPER_ADMIN, RoleType.ADMINISTRATEUR)
|
||||
@ -112,6 +122,18 @@ export class UserController {
|
||||
return this.userService.validateUser(id, currentUser, comment);
|
||||
}
|
||||
|
||||
@Patch(':id/refuser')
|
||||
@Roles(RoleType.SUPER_ADMIN, RoleType.GESTIONNAIRE, RoleType.ADMINISTRATEUR)
|
||||
@ApiOperation({ summary: 'Refuser un compte (à corriger)' })
|
||||
@ApiParam({ name: 'id', description: "UUID de l'utilisateur" })
|
||||
refuse(
|
||||
@Param('id') id: string,
|
||||
@User() currentUser: Users,
|
||||
@Body('comment') comment?: string,
|
||||
) {
|
||||
return this.userService.refuseUser(id, currentUser, comment);
|
||||
}
|
||||
|
||||
@Patch(':id/suspendre')
|
||||
@Roles(RoleType.SUPER_ADMIN, RoleType.GESTIONNAIRE, RoleType.ADMINISTRATEUR)
|
||||
@ApiOperation({ summary: 'Suspendre un compte utilisateur' })
|
||||
|
||||
@ -140,6 +140,15 @@ export class UserService {
|
||||
return this.usersRepository.find({ where });
|
||||
}
|
||||
|
||||
/** Comptes refusés (à corriger) : liste pour reprise par le gestionnaire */
|
||||
async findRefusedUsers(role?: RoleType): Promise<Users[]> {
|
||||
const where: any = { statut: StatutUtilisateurType.REFUSE };
|
||||
if (role) {
|
||||
where.role = role;
|
||||
}
|
||||
return this.usersRepository.find({ where });
|
||||
}
|
||||
|
||||
async findAll(): Promise<Users[]> {
|
||||
return this.usersRepository.find();
|
||||
}
|
||||
@ -214,7 +223,7 @@ export class UserService {
|
||||
return this.usersRepository.save(user);
|
||||
}
|
||||
|
||||
// Valider un compte utilisateur
|
||||
// Valider un compte utilisateur (en_attente ou refuse -> actif)
|
||||
async validateUser(user_id: string, currentUser: Users, comment?: string): Promise<Users> {
|
||||
if (![RoleType.SUPER_ADMIN, RoleType.ADMINISTRATEUR, RoleType.GESTIONNAIRE].includes(currentUser.role)) {
|
||||
throw new ForbiddenException('Accès réservé aux super admins, administrateurs et gestionnaires');
|
||||
@ -223,6 +232,10 @@ export class UserService {
|
||||
const user = await this.usersRepository.findOne({ where: { id: user_id } });
|
||||
if (!user) throw new NotFoundException('Utilisateur introuvable');
|
||||
|
||||
if (user.statut !== StatutUtilisateurType.EN_ATTENTE && user.statut !== StatutUtilisateurType.REFUSE) {
|
||||
throw new BadRequestException('Seuls les comptes en attente ou refusés (à corriger) peuvent être validés.');
|
||||
}
|
||||
|
||||
user.statut = StatutUtilisateurType.ACTIF;
|
||||
const savedUser = await this.usersRepository.save(user);
|
||||
if (user.role === RoleType.PARENT) {
|
||||
@ -270,6 +283,30 @@ export class UserService {
|
||||
await this.validationRepository.save(suspend);
|
||||
return savedUser;
|
||||
}
|
||||
|
||||
/** Refuser un compte (en_attente -> refuse) ; tracé dans validations */
|
||||
async refuseUser(user_id: string, currentUser: Users, comment?: string): Promise<Users> {
|
||||
if (![RoleType.SUPER_ADMIN, RoleType.ADMINISTRATEUR, RoleType.GESTIONNAIRE].includes(currentUser.role)) {
|
||||
throw new ForbiddenException('Accès réservé aux super admins, administrateurs et gestionnaires');
|
||||
}
|
||||
const user = await this.usersRepository.findOne({ where: { id: user_id } });
|
||||
if (!user) throw new NotFoundException('Utilisateur introuvable');
|
||||
if (user.statut !== StatutUtilisateurType.EN_ATTENTE) {
|
||||
throw new BadRequestException('Seul un compte en attente peut être refusé.');
|
||||
}
|
||||
user.statut = StatutUtilisateurType.REFUSE;
|
||||
const savedUser = await this.usersRepository.save(user);
|
||||
const validation = this.validationRepository.create({
|
||||
user: savedUser,
|
||||
type: 'refus_compte',
|
||||
status: StatutValidationType.REFUSE,
|
||||
validated_by: currentUser,
|
||||
comment,
|
||||
});
|
||||
await this.validationRepository.save(validation);
|
||||
return savedUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affecter ou modifier le numéro de dossier d'un utilisateur (parent ou AM).
|
||||
* Permet au gestionnaire/admin de rapprocher deux dossiers (même numéro pour plusieurs personnes).
|
||||
|
||||
@ -11,7 +11,7 @@ DO $$ BEGIN
|
||||
CREATE TYPE genre_type AS ENUM ('H', 'F');
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_utilisateur_type') THEN
|
||||
CREATE TYPE statut_utilisateur_type AS ENUM ('en_attente','actif','suspendu');
|
||||
CREATE TYPE statut_utilisateur_type AS ENUM ('en_attente','actif','suspendu','refuse');
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_enfant_type') THEN
|
||||
CREATE TYPE statut_enfant_type AS ENUM ('a_naitre','actif','scolarise');
|
||||
|
||||
4
database/migrations/2026_statut_utilisateur_refuse.sql
Normal file
4
database/migrations/2026_statut_utilisateur_refuse.sql
Normal file
@ -0,0 +1,4 @@
|
||||
-- Migration #105 : Statut utilisateur « refusé » (à corriger)
|
||||
-- Ajout de la valeur 'refuse' à l'enum statut_utilisateur_type.
|
||||
|
||||
ALTER TYPE statut_utilisateur_type ADD VALUE IF NOT EXISTS 'refuse';
|
||||
Loading…
x
Reference in New Issue
Block a user