feat(admin): вкладки фильтра по статусу в списке пользователей

Задача 3 переопределена оператором: вместо окончательного удаления
пользователя (упёрлось в CHECK-constraint'ы participant/chat_messages,
требующие миграции схемы — решили отложить) добавлены вкладки
«Активные»/«Заблокированные»/«Все» перед полем поиска в админке —
список фильтруется по `is_blocked` на бэкенде (GET /admin/users?status=).
This commit is contained in:
2026-07-27 20:59:29 +03:00
parent 25ffd9e678
commit 09215da22a
5 changed files with 85 additions and 12 deletions

View File

@@ -2,7 +2,7 @@
import uuid
from sqlalchemy import func, or_, select
from sqlalchemy import ColumnElement, func, or_, select
from sqlalchemy.ext.asyncio import AsyncSession
from models.conference import Conference
@@ -56,20 +56,26 @@ class AdminConferenceRepository:
class AdminUserRepository:
"""Постраничный список пользователей с текстовым поиском по email/имени."""
"""Постраничный список пользователей с фильтром по статусу и текстовым поиском."""
def __init__(self, session: AsyncSession) -> None:
self._session = session
async def list_paginated(
self, *, q: str | None, limit: int, offset: int
self, *, status: str | None, q: str | None, limit: int, offset: int
) -> tuple[list[tuple[User, str | None]], int]:
"""Вернуть страницу пользователей (+ имя команды) и общее число совпадений.
`LEFT JOIN` на `teams` — имя команды нужно карточке профиля/таблице
админки, у пользователя без команды — `None`.
`status` — `"active"`/`"blocked"` (фильтр по `is_blocked`), `None` —
без фильтра (все пользователи). `LEFT JOIN` на `teams` — имя команды
нужно карточке профиля/таблице админки, у пользователя без команды —
`None`.
"""
filters = []
filters: list[ColumnElement[bool]] = []
if status == "active":
filters.append(User.is_blocked.is_(False))
elif status == "blocked":
filters.append(User.is_blocked.is_(True))
if q:
like = f"%{q}%"
filters.append(or_(User.email.ilike(like), User.name_user.ilike(like)))