From 6ce58d1639653e2abb4285b7af92d365f8982d14 Mon Sep 17 00:00:00 2001 From: Mathis HERRIOT <197931332+0x485254@users.noreply.github.com> Date: Wed, 14 Jan 2026 21:44:14 +0100 Subject: [PATCH] feat(admin): implement admin statistics API and service Add admin statistics endpoint to provide user, content, and category stats. Introduce `AdminModule` with controller, service, and repository integration for data aggregation. Include frontend service to consume the stats API. --- backend/src/admin/admin.controller.ts | 17 ++++++++++++++++ backend/src/admin/admin.module.ts | 14 +++++++++++++ backend/src/admin/admin.service.ts | 27 ++++++++++++++++++++++++++ frontend/src/services/admin.service.ts | 14 +++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 backend/src/admin/admin.controller.ts create mode 100644 backend/src/admin/admin.module.ts create mode 100644 backend/src/admin/admin.service.ts create mode 100644 frontend/src/services/admin.service.ts diff --git a/backend/src/admin/admin.controller.ts b/backend/src/admin/admin.controller.ts new file mode 100644 index 0000000..73db7fc --- /dev/null +++ b/backend/src/admin/admin.controller.ts @@ -0,0 +1,17 @@ +import { Controller, Get, UseGuards } from "@nestjs/common"; +import { AuthGuard } from "../auth/guards/auth.guard"; +import { RolesGuard } from "../auth/guards/roles.guard"; +import { Roles } from "../auth/decorators/roles.decorator"; +import { AdminService } from "./admin.service"; + +@Controller("admin") +@UseGuards(AuthGuard, RolesGuard) +@Roles("admin") +export class AdminController { + constructor(private readonly adminService: AdminService) {} + + @Get("stats") + getStats() { + return this.adminService.getStats(); + } +} diff --git a/backend/src/admin/admin.module.ts b/backend/src/admin/admin.module.ts new file mode 100644 index 0000000..3e684a0 --- /dev/null +++ b/backend/src/admin/admin.module.ts @@ -0,0 +1,14 @@ +import { Module } from "@nestjs/common"; +import { AuthModule } from "../auth/auth.module"; +import { UsersModule } from "../users/users.module"; +import { ContentsModule } from "../contents/contents.module"; +import { CategoriesModule } from "../categories/categories.module"; +import { AdminController } from "./admin.controller"; +import { AdminService } from "./admin.service"; + +@Module({ + imports: [AuthModule, UsersModule, ContentsModule, CategoriesModule], + controllers: [AdminController], + providers: [AdminService], +}) +export class AdminModule {} diff --git a/backend/src/admin/admin.service.ts b/backend/src/admin/admin.service.ts new file mode 100644 index 0000000..7fce6c5 --- /dev/null +++ b/backend/src/admin/admin.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from "@nestjs/common"; +import { UsersRepository } from "../users/repositories/users.repository"; +import { ContentsRepository } from "../contents/repositories/contents.repository"; +import { CategoriesRepository } from "../categories/repositories/categories.repository"; + +@Injectable() +export class AdminService { + constructor( + private readonly usersRepository: UsersRepository, + private readonly contentsRepository: ContentsRepository, + private readonly categoriesRepository: CategoriesRepository, + ) {} + + async getStats() { + const [userCount, contentCount, categoryCount] = await Promise.all([ + this.usersRepository.countAll(), + this.contentsRepository.count({}), + this.categoriesRepository.countAll(), + ]); + + return { + users: userCount, + contents: contentCount, + categories: categoryCount, + }; + } +} diff --git a/frontend/src/services/admin.service.ts b/frontend/src/services/admin.service.ts new file mode 100644 index 0000000..7ffa5cf --- /dev/null +++ b/frontend/src/services/admin.service.ts @@ -0,0 +1,14 @@ +import { api } from "./api"; + +export interface AdminStats { + users: number; + contents: number; + categories: number; +} + +export const adminService = { + getStats: async (): Promise => { + const response = await api.get("/admin/stats"); + return response.data; + }, +};