From d05b46e1179260f8506f1b5dd2a3ee2c5098e13e Mon Sep 17 00:00:00 2001 From: sdraris Date: Mon, 8 Sep 2025 15:47:22 +0200 Subject: [PATCH] user controller + service correction --- src/routes/user/user.controller.ts | 40 ++++++++++----------- src/routes/user/user.service.ts | 58 +++++++++++++++++++----------- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/routes/user/user.controller.ts b/src/routes/user/user.controller.ts index c8a791c..85c10e0 100644 --- a/src/routes/user/user.controller.ts +++ b/src/routes/user/user.controller.ts @@ -1,44 +1,44 @@ import { Body, Controller, Delete, Get, Param, Patch, Post, UseGuards } from '@nestjs/common'; -import { UserService } from './user.service'; -import { Roles } from 'src/common/decorators/roles.decorator'; -import { RoleType, Users } from 'src/entities/users.entity'; -import { CreateUserDto } from './dto/create_user.dto'; -import { User } from 'src/common/decorators/user.decorator'; -import { UpdateUserDto } from './dto/update_user.dto'; import { ApiBearerAuth, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger'; import { AuthGuard } from 'src/common/guards/auth.guard'; +import { Roles } from 'src/common/decorators/roles.decorator'; +import { User } from 'src/common/decorators/user.decorator'; +import { RoleType, Users } from 'src/entities/users.entity'; +import { UserService } from './user.service'; +import { CreateUserDto } from './dto/create_user.dto'; +import { UpdateUserDto } from './dto/update_user.dto'; @ApiTags('Utilisateurs') @ApiBearerAuth('access-token') @UseGuards(AuthGuard) @Controller('users') export class UserController { - constructor(private readonly userService: UserService) { } + constructor(private readonly userService: UserService) {} // Création d'un utilisateur (réservée aux super admins) @Post() @Roles(RoleType.SUPER_ADMIN) - @ApiOperation({ summary: 'Creer un nouvel utilisateur (pour super admin seulement)' }) - create( + @ApiOperation({ summary: 'Créer un nouvel utilisateur (super admin seulement)' }) + createUser( @Body() dto: CreateUserDto, @User() currentUser: Users - ): Promise { - return this.userService.create(dto, currentUser); + ) { + return this.userService.createUser(dto, currentUser); } - // Lister tous les utilisateurs (super_admin et gestionnaire) + // Lister tous les utilisateurs (super_admin uniquement) @Get() - @ApiOperation({ summary: 'Lister tous les utilisateurs' }) @Roles(RoleType.SUPER_ADMIN) + @ApiOperation({ summary: 'Lister tous les utilisateurs' }) findAll() { return this.userService.findAll(); } // Récupérer un utilisateur par son ID @Get(':id') + @Roles(RoleType.SUPER_ADMIN, RoleType.GESTIONNAIRE) @ApiOperation({ summary: 'Trouver un utilisateur par son id' }) @ApiParam({ name: 'id', description: "UUID de l'utilisateur" }) - @Roles(RoleType.SUPER_ADMIN, RoleType.GESTIONNAIRE) findOne(@Param('id') id: string) { return this.userService.findOne(id); } @@ -46,21 +46,21 @@ export class UserController { // Modifier un utilisateur (réservé super_admin) @Patch(':id') @Roles(RoleType.SUPER_ADMIN) - @ApiOperation({summary: 'Trouver un utilisateur par son id'}) - @ApiParam({name: 'id', description: "UUID de l'utilisateur"}) - update( + @ApiOperation({ summary: 'Mettre à jour un utilisateur' }) + @ApiParam({ name: 'id', description: "UUID de l'utilisateur" }) + updateUser( @Param('id') id: string, @Body() dto: UpdateUserDto, @User() currentUser: Users ) { - return this.userService.update(id, dto, currentUser); + return this.userService.updateUser(id, dto, currentUser); } // Supprimer un utilisateur (super_admin et gestionnaire) - @ApiOperation({summary: 'Supprimer un utilisateur'}) - @ApiParam({name: 'id', description: "UUID de l'utilisateur"}) @Delete(':id') @Roles(RoleType.SUPER_ADMIN, RoleType.GESTIONNAIRE) + @ApiOperation({ summary: 'Supprimer un utilisateur' }) + @ApiParam({ name: 'id', description: "UUID de l'utilisateur" }) remove(@Param('id') id: string) { return this.userService.remove(id); } diff --git a/src/routes/user/user.service.ts b/src/routes/user/user.service.ts index 378f012..cc5241f 100644 --- a/src/routes/user/user.service.ts +++ b/src/routes/user/user.service.ts @@ -5,25 +5,40 @@ import { Repository } from "typeorm"; import { CreateUserDto } from "./dto/create_user.dto"; import * as bcrypt from 'bcrypt'; import { UpdateUserDto } from "./dto/update_user.dto"; +import { BaseService } from "src/common/base.service"; @Injectable() -export class UserService { +export class UserService extends BaseService { constructor( @InjectRepository(Users) private readonly usersRepository: Repository - ) { } + ) { + super(usersRepository); + } //Creation utilisateur - async create(dto: CreateUserDto, currentUser?: Users): Promise { - //Securiser les roles + async createUser(dto: CreateUserDto, currentUser?: Users): Promise { + // Sécuriser le rôle if (!currentUser || currentUser.role !== RoleType.SUPER_ADMIN) { - dto.role = RoleType.PARENT; //Forcer le role parent si pas super admin + dto.role = RoleType.PARENT; } - //Hash mot de passe + // Nettoyage / validation consentement photo + let consentDate: Date | undefined; + if (dto.consent_photo && dto.consent_photo_at) { + if (dto.consent_photo_at) { + const parsed = new Date(dto.consent_photo_at); + if (!isNaN(parsed.getTime())) { + consentDate = parsed; + } + } + } + + // Hash mot de passe const salt = await bcrypt.genSalt(); const password_hash = await bcrypt.hash(dto.password, salt); - const user = this.usersRepository.create({ + + const entity = this.usersRepository.create({ email: dto.email, password_hash, first_name: dto.first_name, @@ -35,20 +50,16 @@ export class UserService { address: dto.address, photo_url: dto.photo_url, consent_photo: dto.consent_photo ?? false, - consent_photo_at: dto.consent_photo_at ? new Date(dto.consent_photo_at) : undefined, + consent_photo_at: consentDate, must_change_password: dto.must_change_password ?? false + }); - }) - return this.usersRepository.save(user); - } - - //Lister tous les utilisateurs - async findAll(): Promise { - return this.usersRepository.find(); + const saved = await this.usersRepository.save(entity); + return this.findOne(saved.id); } async findOneBy(where: Partial) { - return this.usersRepository.findOne( { where } ) + return this.usersRepository.findOne({ where }) } //Trouver utilisateur par ID @@ -61,16 +72,13 @@ export class UserService { } //Trouver utilisateur par email - async findByEmail(email: string): Promise { + async findByEmailOrNull(email: string): Promise { const user = await this.usersRepository.findOne({ where: { email } }); - if (!user) { - throw new NotFoundException('Utilisateur introuvable'); - } return user; } //Mettre a jour un utilisateur - async update(id: string, dto: UpdateUserDto, currentUser: Users): Promise { + async updateUser(id: string, dto: UpdateUserDto, currentUser: Users): Promise { const user = await this.findOne(id); //Tant que pas super_admin interdir changement de role @@ -84,6 +92,14 @@ export class UserService { user.password_hash = await bcrypt.hash(dto.password, salt); delete (dto as any).password; } + + if (dto.consent_photo_at !== undefined) { + user.consent_photo_at = dto.consent_photo_at + ? new Date(dto.consent_photo_at) + : undefined; + delete (dto as any).consent_photo_at; + } + Object.assign(user, dto); return this.usersRepository.save(user); }