Files
memegoat/backend/src/users/users.controller.ts
Mathis HERRIOT a30113e8e2 feat(users): add avatar and bio support, improve user profile handling
Introduce `avatarUrl` and `bio` fields in the user schema. Update repository, service, and controller to handle avatar uploads, processing, and bio updates. Add S3 integration for avatar storage and enhance user data handling for private and public profiles.
2026-01-14 21:42:46 +01:00

134 lines
3.4 KiB
TypeScript

import { CacheInterceptor, CacheTTL } from "@nestjs/cache-manager";
import {
Body,
Controller,
DefaultValuePipe,
Delete,
forwardRef,
Get,
Inject,
Param,
ParseIntPipe,
Patch,
Post,
Query,
Req,
UploadedFile,
UseGuards,
UseInterceptors,
} from "@nestjs/common";
import { FileInterceptor } from "@nestjs/platform-express";
import { AuthService } from "../auth/auth.service";
import { Roles } from "../auth/decorators/roles.decorator";
import { AuthGuard } from "../auth/guards/auth.guard";
import { RolesGuard } from "../auth/guards/roles.guard";
import type { AuthenticatedRequest } from "../common/interfaces/request.interface";
import { UpdateConsentDto } from "./dto/update-consent.dto";
import { UpdateUserDto } from "./dto/update-user.dto";
import { UsersService } from "./users.service";
@Controller("users")
export class UsersController {
constructor(
private readonly usersService: UsersService,
@Inject(forwardRef(() => AuthService))
private readonly authService: AuthService,
) {}
// Gestion administrative des utilisateurs
@Get("admin")
@UseGuards(AuthGuard, RolesGuard)
@Roles("admin")
findAll(
@Query("limit", new DefaultValuePipe(10), ParseIntPipe) limit: number,
@Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number,
) {
return this.usersService.findAll(limit, offset);
}
// Listing public d'un profil
@Get("public/:username")
@UseInterceptors(CacheInterceptor)
@CacheTTL(60000) // 1 minute
findPublicProfile(@Param("username") username: string) {
return this.usersService.findPublicProfile(username);
}
// Gestion de son propre compte
@Get("me")
@UseGuards(AuthGuard)
findMe(@Req() req: AuthenticatedRequest) {
return this.usersService.findOneWithPrivateData(req.user.sub);
}
@Get("me/export")
@UseGuards(AuthGuard)
exportMe(@Req() req: AuthenticatedRequest) {
return this.usersService.exportUserData(req.user.sub);
}
@Patch("me")
@UseGuards(AuthGuard)
updateMe(
@Req() req: AuthenticatedRequest,
@Body() updateUserDto: UpdateUserDto,
) {
return this.usersService.update(req.user.sub, updateUserDto);
}
@Post("me/avatar")
@UseGuards(AuthGuard)
@UseInterceptors(FileInterceptor("file"))
updateAvatar(
@Req() req: AuthenticatedRequest,
@UploadedFile() file: Express.Multer.File,
) {
return this.usersService.updateAvatar(req.user.sub, file);
}
@Patch("me/consent")
@UseGuards(AuthGuard)
updateConsent(
@Req() req: AuthenticatedRequest,
@Body() consentDto: UpdateConsentDto,
) {
return this.usersService.updateConsent(
req.user.sub,
consentDto.termsVersion,
consentDto.privacyVersion,
);
}
@Delete("me")
@UseGuards(AuthGuard)
removeMe(@Req() req: AuthenticatedRequest) {
return this.usersService.remove(req.user.sub);
}
@Delete(":uuid")
@UseGuards(AuthGuard, RolesGuard)
@Roles("admin")
removeAdmin(@Param("uuid") uuid: string) {
return this.usersService.remove(uuid);
}
// Double Authentification (2FA)
@Post("me/2fa/setup")
@UseGuards(AuthGuard)
setup2fa(@Req() req: AuthenticatedRequest) {
return this.authService.generateTwoFactorSecret(req.user.sub);
}
@Post("me/2fa/enable")
@UseGuards(AuthGuard)
enable2fa(@Req() req: AuthenticatedRequest, @Body("token") token: string) {
return this.authService.enableTwoFactor(req.user.sub, token);
}
@Post("me/2fa/disable")
@UseGuards(AuthGuard)
disable2fa(@Req() req: AuthenticatedRequest, @Body("token") token: string) {
return this.authService.disableTwoFactor(req.user.sub, token);
}
}