import { CacheInterceptor, CacheTTL } from "@nestjs/cache-manager"; import { Body, Controller, DefaultValuePipe, Delete, Get, Header, NotFoundException, Param, ParseBoolPipe, ParseIntPipe, Post, Query, Req, Res, UploadedFile, UseGuards, UseInterceptors, } from "@nestjs/common"; import { FileInterceptor } from "@nestjs/platform-express"; import type { Response } from "express"; import { Roles } from "../auth/decorators/roles.decorator"; import { AuthGuard } from "../auth/guards/auth.guard"; import { OptionalAuthGuard } from "../auth/guards/optional-auth.guard"; import { RolesGuard } from "../auth/guards/roles.guard"; import type { AuthenticatedRequest } from "../common/interfaces/request.interface"; import { ContentsService } from "./contents.service"; import { CreateContentDto } from "./dto/create-content.dto"; import { UploadContentDto } from "./dto/upload-content.dto"; @Controller("contents") export class ContentsController { constructor(private readonly contentsService: ContentsService) {} @Post() @UseGuards(AuthGuard) create( @Req() req: AuthenticatedRequest, @Body() createContentDto: CreateContentDto, ) { return this.contentsService.create(req.user.sub, createContentDto); } @Post("upload-url") @UseGuards(AuthGuard) getUploadUrl( @Req() req: AuthenticatedRequest, @Query("fileName") fileName: string, ) { return this.contentsService.getUploadUrl(req.user.sub, fileName); } @Post("upload") @UseGuards(AuthGuard) @UseInterceptors(FileInterceptor("file")) upload( @Req() req: AuthenticatedRequest, @UploadedFile() file: Express.Multer.File, @Body() uploadContentDto: UploadContentDto, ) { return this.contentsService.uploadAndProcess( req.user.sub, file, uploadContentDto, ); } @Get("explore") @UseGuards(OptionalAuthGuard) @UseInterceptors(CacheInterceptor) @CacheTTL(60) @Header("Cache-Control", "public, max-age=60") explore( @Req() req: AuthenticatedRequest, @Query("limit", new DefaultValuePipe(10), ParseIntPipe) limit: number, @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, @Query("sort") sort?: "trend" | "recent", @Query("tag") tag?: string, @Query("category") category?: string, @Query("author") author?: string, @Query("query") query?: string, @Query("favoritesOnly", new DefaultValuePipe(false), ParseBoolPipe) favoritesOnly?: boolean, @Query("userId") userIdQuery?: string, ) { return this.contentsService.findAll({ limit, offset, sortBy: sort, tag, category, author, query, favoritesOnly, userId: userIdQuery || req.user?.sub, }); } @Get("trends") @UseGuards(OptionalAuthGuard) @UseInterceptors(CacheInterceptor) @CacheTTL(300) @Header("Cache-Control", "public, max-age=300") trends( @Req() req: AuthenticatedRequest, @Query("limit", new DefaultValuePipe(10), ParseIntPipe) limit: number, @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, ) { return this.contentsService.findAll({ limit, offset, sortBy: "trend", userId: req.user?.sub, }); } @Get("recent") @UseGuards(OptionalAuthGuard) @UseInterceptors(CacheInterceptor) @CacheTTL(60) @Header("Cache-Control", "public, max-age=60") recent( @Req() req: AuthenticatedRequest, @Query("limit", new DefaultValuePipe(10), ParseIntPipe) limit: number, @Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number, ) { return this.contentsService.findAll({ limit, offset, sortBy: "recent", userId: req.user?.sub, }); } @Get(":idOrSlug") @UseGuards(OptionalAuthGuard) @UseInterceptors(CacheInterceptor) @CacheTTL(3600) @Header("Cache-Control", "public, max-age=3600") async findOne( @Param("idOrSlug") idOrSlug: string, @Req() req: AuthenticatedRequest, @Res() res: Response, ) { const content = await this.contentsService.findOne(idOrSlug, req.user?.sub); if (!content) { throw new NotFoundException("Contenu non trouvé"); } const userAgent = req.headers["user-agent"] || ""; const isBot = /bot|googlebot|crawler|spider|robot|crawling|facebookexternalhit|twitterbot/i.test( userAgent, ); if (isBot) { const html = this.contentsService.generateBotHtml(content); return res.send(html); } return res.json(content); } @Post(":id/view") incrementViews(@Param("id") id: string) { return this.contentsService.incrementViews(id); } @Post(":id/use") incrementUsage(@Param("id") id: string) { return this.contentsService.incrementUsage(id); } @Delete(":id") @UseGuards(AuthGuard) remove(@Param("id") id: string, @Req() req: AuthenticatedRequest) { return this.contentsService.remove(id, req.user.sub); } @Delete(":id/admin") @UseGuards(AuthGuard, RolesGuard) @Roles("admin") removeAdmin(@Param("id") id: string) { return this.contentsService.removeAdmin(id); } }