Standardize import order in `contents.controller.ts` and related files for better code readability. Adjust SQL formatting in repository methods for consistency.
189 lines
4.8 KiB
TypeScript
189 lines
4.8 KiB
TypeScript
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);
|
|
}
|
|
}
|