feat: implement ReportsModule with service, controller, and endpoints

Added ReportsModule to manage user reports. Includes service methods for creating, retrieving, and updating report statuses, as well as controller endpoints for handling these operations. Integrated with authentication, role-based access control, and database logic.
This commit is contained in:
Mathis HERRIOT
2026-01-08 15:26:39 +01:00
parent dd875fe1ea
commit dde1bf522f
5 changed files with 149 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
import { IsEnum, IsOptional, IsString, IsUUID } from "class-validator";
export enum ReportReason {
INAPPROPRIATE = "inappropriate",
SPAM = "spam",
COPYRIGHT = "copyright",
OTHER = "other",
}
export class CreateReportDto {
@IsOptional()
@IsUUID()
contentId?: string;
@IsOptional()
@IsUUID()
tagId?: string;
@IsEnum(ReportReason)
reason!: "inappropriate" | "spam" | "copyright" | "other";
@IsOptional()
@IsString()
description?: string;
}

View File

@@ -0,0 +1,13 @@
import { IsEnum } from "class-validator";
export enum ReportStatus {
PENDING = "pending",
REVIEWED = "reviewed",
RESOLVED = "resolved",
DISMISSED = "dismissed",
}
export class UpdateReportStatusDto {
@IsEnum(ReportStatus)
status!: "pending" | "reviewed" | "resolved" | "dismissed";
}

View File

@@ -0,0 +1,54 @@
import {
Body,
Controller,
DefaultValuePipe,
Get,
Param,
ParseIntPipe,
Patch,
Post,
Query,
Req,
UseGuards,
} from "@nestjs/common";
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 { CreateReportDto } from "./dto/create-report.dto";
import { UpdateReportStatusDto } from "./dto/update-report-status.dto";
import { ReportsService } from "./reports.service";
@Controller("reports")
export class ReportsController {
constructor(private readonly reportsService: ReportsService) {}
@Post()
@UseGuards(AuthGuard)
create(
@Req() req: AuthenticatedRequest,
@Body() createReportDto: CreateReportDto,
) {
return this.reportsService.create(req.user.sub, createReportDto);
}
@Get()
@UseGuards(AuthGuard, RolesGuard)
@Roles("admin", "moderator")
findAll(
@Query("limit", new DefaultValuePipe(10), ParseIntPipe) limit: number,
@Query("offset", new DefaultValuePipe(0), ParseIntPipe) offset: number,
) {
return this.reportsService.findAll(limit, offset);
}
@Patch(":id/status")
@UseGuards(AuthGuard, RolesGuard)
@Roles("admin", "moderator")
updateStatus(
@Param("id") id: string,
@Body() updateReportStatusDto: UpdateReportStatusDto,
) {
return this.reportsService.updateStatus(id, updateReportStatusDto.status);
}
}

View File

@@ -0,0 +1,13 @@
import { Module } from "@nestjs/common";
import { AuthModule } from "../auth/auth.module";
import { CryptoModule } from "../crypto/crypto.module";
import { DatabaseModule } from "../database/database.module";
import { ReportsController } from "./reports.controller";
import { ReportsService } from "./reports.service";
@Module({
imports: [DatabaseModule, AuthModule, CryptoModule],
controllers: [ReportsController],
providers: [ReportsService],
})
export class ReportsModule {}

View File

@@ -0,0 +1,44 @@
import { Injectable } from "@nestjs/common";
import { desc, eq } from "drizzle-orm";
import { DatabaseService } from "../database/database.service";
import { reports } from "../database/schemas";
import { CreateReportDto } from "./dto/create-report.dto";
@Injectable()
export class ReportsService {
constructor(private readonly databaseService: DatabaseService) {}
async create(reporterId: string, data: CreateReportDto) {
const [newReport] = await this.databaseService.db
.insert(reports)
.values({
reporterId,
contentId: data.contentId,
tagId: data.tagId,
reason: data.reason,
description: data.description,
})
.returning();
return newReport;
}
async findAll(limit: number, offset: number) {
return await this.databaseService.db
.select()
.from(reports)
.orderBy(desc(reports.createdAt))
.limit(limit)
.offset(offset);
}
async updateStatus(
id: string,
status: "pending" | "reviewed" | "resolved" | "dismissed",
) {
return await this.databaseService.db
.update(reports)
.set({ status, updatedAt: new Date() })
.where(eq(reports.id, id))
.returning();
}
}