From 705f1ad6e04e84e245ad077a2d8a1ebd32bce808 Mon Sep 17 00:00:00 2001 From: Mathis HERRIOT <197931332+0x485254@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:24:48 +0100 Subject: [PATCH] feat: add CategoriesModule with CRUD operations Implemented CategoriesModule with controller, service, and DTOs for managing categories. Includes endpoints for creation, retrieval, updating, and deletion, integrated with database logic. --- .../src/categories/categories.controller.ts | 43 +++++++++++++ backend/src/categories/categories.module.ts | 12 ++++ backend/src/categories/categories.service.ts | 64 +++++++++++++++++++ .../src/categories/dto/create-category.dto.ts | 15 +++++ .../src/categories/dto/update-category.dto.ts | 4 ++ 5 files changed, 138 insertions(+) create mode 100644 backend/src/categories/categories.controller.ts create mode 100644 backend/src/categories/categories.module.ts create mode 100644 backend/src/categories/categories.service.ts create mode 100644 backend/src/categories/dto/create-category.dto.ts create mode 100644 backend/src/categories/dto/update-category.dto.ts diff --git a/backend/src/categories/categories.controller.ts b/backend/src/categories/categories.controller.ts new file mode 100644 index 0000000..be8abff --- /dev/null +++ b/backend/src/categories/categories.controller.ts @@ -0,0 +1,43 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + Patch, + Post, +} from "@nestjs/common"; +import { CategoriesService } from "./categories.service"; +import { CreateCategoryDto } from "./dto/create-category.dto"; +import { UpdateCategoryDto } from "./dto/update-category.dto"; + +@Controller("categories") +export class CategoriesController { + constructor(private readonly categoriesService: CategoriesService) {} + + @Get() + findAll() { + return this.categoriesService.findAll(); + } + + @Get(":id") + findOne(@Param("id") id: string) { + return this.categoriesService.findOne(id); + } + + // Ces routes devraient être protégées par un AdminGuard + @Post() + create(@Body() createCategoryDto: CreateCategoryDto) { + return this.categoriesService.create(createCategoryDto); + } + + @Patch(":id") + update(@Param("id") id: string, @Body() updateCategoryDto: UpdateCategoryDto) { + return this.categoriesService.update(id, updateCategoryDto); + } + + @Delete(":id") + remove(@Param("id") id: string) { + return this.categoriesService.remove(id); + } +} diff --git a/backend/src/categories/categories.module.ts b/backend/src/categories/categories.module.ts new file mode 100644 index 0000000..8d3333a --- /dev/null +++ b/backend/src/categories/categories.module.ts @@ -0,0 +1,12 @@ +import { Module } from "@nestjs/common"; +import { DatabaseModule } from "../database/database.module"; +import { CategoriesController } from "./categories.controller"; +import { CategoriesService } from "./categories.service"; + +@Module({ + imports: [DatabaseModule], + controllers: [CategoriesController], + providers: [CategoriesService], + exports: [CategoriesService], +}) +export class CategoriesModule {} diff --git a/backend/src/categories/categories.service.ts b/backend/src/categories/categories.service.ts new file mode 100644 index 0000000..ad6eae0 --- /dev/null +++ b/backend/src/categories/categories.service.ts @@ -0,0 +1,64 @@ +import { Injectable } from "@nestjs/common"; +import { eq } from "drizzle-orm"; +import { DatabaseService } from "../database/database.service"; +import { categories } from "../database/schemas"; +import { CreateCategoryDto } from "./dto/create-category.dto"; +import { UpdateCategoryDto } from "./dto/update-category.dto"; + +@Injectable() +export class CategoriesService { + constructor(private readonly databaseService: DatabaseService) {} + + async findAll() { + return await this.databaseService.db + .select() + .from(categories) + .orderBy(categories.name); + } + + async findOne(id: string) { + const result = await this.databaseService.db + .select() + .from(categories) + .where(eq(categories.id, id)) + .limit(1); + + return result[0] || null; + } + + async create(data: CreateCategoryDto) { + const slug = data.name + .toLowerCase() + .replace(/ /g, "-") + .replace(/[^\w-]/g, ""); + return await this.databaseService.db + .insert(categories) + .values({ ...data, slug }) + .returning(); + } + + async update(id: string, data: UpdateCategoryDto) { + const updateData = { + ...data, + updatedAt: new Date(), + slug: data.name + ? data.name + .toLowerCase() + .replace(/ /g, "-") + .replace(/[^\w-]/g, "") + : undefined, + }; + return await this.databaseService.db + .update(categories) + .set(updateData) + .where(eq(categories.id, id)) + .returning(); + } + + async remove(id: string) { + return await this.databaseService.db + .delete(categories) + .where(eq(categories.id, id)) + .returning(); + } +} diff --git a/backend/src/categories/dto/create-category.dto.ts b/backend/src/categories/dto/create-category.dto.ts new file mode 100644 index 0000000..52e0884 --- /dev/null +++ b/backend/src/categories/dto/create-category.dto.ts @@ -0,0 +1,15 @@ +import { IsNotEmpty, IsOptional, IsString } from "class-validator"; + +export class CreateCategoryDto { + @IsString() + @IsNotEmpty() + name!: string; + + @IsOptional() + @IsString() + description?: string; + + @IsOptional() + @IsString() + iconUrl?: string; +} diff --git a/backend/src/categories/dto/update-category.dto.ts b/backend/src/categories/dto/update-category.dto.ts new file mode 100644 index 0000000..066c87f --- /dev/null +++ b/backend/src/categories/dto/update-category.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from "@nestjs/mapped-types"; +import { CreateCategoryDto } from "./create-category.dto"; + +export class UpdateCategoryDto extends PartialType(CreateCategoryDto) {}