From f852835c59c0b1e54db2f85a4125628940415814 Mon Sep 17 00:00:00 2001 From: Mathis HERRIOT <197931332+0x485254@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:47:03 +0100 Subject: [PATCH] feat: add user search functionality - Implemented `GET /users/search` endpoint in the backend to enable user search by username or display name. - Added `search` method in `UsersService` and `UsersRepository`. - Updated frontend `UserService` to support the new search API. --- .../src/users/repositories/users.repository.ts | 17 ++++++++++++++++- backend/src/users/users.controller.ts | 6 ++++++ backend/src/users/users.service.ts | 10 ++++++++++ frontend/src/services/user.service.ts | 7 +++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/backend/src/users/repositories/users.repository.ts b/backend/src/users/repositories/users.repository.ts index eec6a8a..7a0b079 100644 --- a/backend/src/users/repositories/users.repository.ts +++ b/backend/src/users/repositories/users.repository.ts @@ -1,5 +1,5 @@ import { Injectable } from "@nestjs/common"; -import { and, eq, lte, sql } from "drizzle-orm"; +import { and, count, eq, ilike, or, sql } from "drizzle-orm"; import { DatabaseService } from "../../database/database.service"; import { contents, favorites, users } from "../../database/schemas"; @@ -97,6 +97,21 @@ export class UsersRepository { return result[0] || null; } + async search(query: string) { + return this.databaseService.db + .select({ + uuid: users.uuid, + username: users.username, + displayName: users.displayName, + avatarUrl: users.avatarUrl, + }) + .from(users) + .where( + or(ilike(users.username, `%${query}%`), ilike(users.displayName, `%${query}%`)), + ) + .limit(10); + } + async findOne(uuid: string) { const result = await this.databaseService.db .select() diff --git a/backend/src/users/users.controller.ts b/backend/src/users/users.controller.ts index 8ce1db6..ce0b4f8 100644 --- a/backend/src/users/users.controller.ts +++ b/backend/src/users/users.controller.ts @@ -54,6 +54,12 @@ export class UsersController { return this.usersService.findPublicProfile(username); } + @Get("search") + @UseGuards(AuthGuard) + search(@Query("q") query: string) { + return this.usersService.search(query); + } + // Gestion de son propre compte @Get("me") @UseGuards(AuthGuard) diff --git a/backend/src/users/users.service.ts b/backend/src/users/users.service.ts index a2e8ac3..4d82925 100644 --- a/backend/src/users/users.service.ts +++ b/backend/src/users/users.service.ts @@ -106,6 +106,16 @@ export class UsersService { }; } + async search(query: string) { + const users = await this.usersRepository.search(query); + return users.map((user) => ({ + ...user, + avatarUrl: user.avatarUrl + ? this.s3Service.getPublicUrl(user.avatarUrl) + : null, + })); + } + async findOne(uuid: string) { const user = await this.usersRepository.findOne(uuid); if (!user) return null; diff --git a/frontend/src/services/user.service.ts b/frontend/src/services/user.service.ts index 29e7fef..d78c782 100644 --- a/frontend/src/services/user.service.ts +++ b/frontend/src/services/user.service.ts @@ -12,6 +12,13 @@ export const UserService = { return data; }, + async search(query: string): Promise { + const { data } = await api.get("/users/search", { + params: { q: query }, + }); + return data; + }, + async updateMe(update: Partial): Promise { const { data } = await api.patch("/users/me", update); return data;