feat(admin): поиск пользователей по названию команды

AdminUserRepository.list_paginated ищет теперь и по названию команды
(LEFT JOIN teams, как и раньше) — пользователи без команды по-прежнему
не пропадают из общей выдачи, просто не совпадают с этой частью поиска.
Плейсхолдер поля поиска в админке обновлён под новое поведение.
This commit is contained in:
2026-07-27 21:04:26 +03:00
parent 09215da22a
commit c4721fcf99
4 changed files with 42 additions and 7 deletions

View File

@@ -67,9 +67,11 @@ class AdminUserRepository:
"""Вернуть страницу пользователей (+ имя команды) и общее число совпадений.
`status` — `"active"`/`"blocked"` (фильтр по `is_blocked`), `None` —
без фильтра (все пользователи). `LEFT JOIN` на `teams` — имя команды
нужно карточке профиля/таблице админки, у пользователя без команды —
`None`.
без фильтра (все пользователи). `q` ищет по email/имени пользователя
И по названию команды (`LEFT JOIN` на `teams` — нужен и для этого
поиска, и для колонки «Команда» в таблице админки; `LEFT`, а не
`INNER`, — пользователи без команды не должны пропадать из общей
выдачи, только не совпадать с поиском по названию команды).
"""
filters: list[ColumnElement[bool]] = []
if status == "active":
@@ -78,9 +80,13 @@ class AdminUserRepository:
filters.append(User.is_blocked.is_(True))
if q:
like = f"%{q}%"
filters.append(or_(User.email.ilike(like), User.name_user.ilike(like)))
filters.append(
or_(User.email.ilike(like), User.name_user.ilike(like), Team.name.ilike(like))
)
count_stmt = select(func.count()).select_from(User)
count_stmt = (
select(func.count()).select_from(User).outerjoin(Team, User.team_id == Team.id)
)
items_stmt = (
select(User, Team.name)
.outerjoin(Team, User.team_id == Team.id)