Новая система уведомлений поверх готовой SSE-шины: события пишутся в БД,
живут 72 часа и чистятся (при чтении списка + фоновой задачей), всплывают
сверху экрана в момент прихода, доступны через колокольчик в правом верхнем
углу (бейдж непрочитанных + панель).
Типы: приглашение в группу (→ /group), старт/финиш партии участникам кроме
инициатора (→ /match/{id}). Титулы — готовый хелпер-задел (не подключён, т.к.
выдача титулов игрокам ещё не реализована).
Бэкенд: модель Notification + миграция 0008 (идемпотентная), notification_service,
notify.notifications_changed, роутер /api/notifications (GET + /read), триггеры
в groups/matches, фоновая чистка в lifespan, защита hub.publish от закрытого loop.
Фронт: useNotifications/useMarkNotificationsRead, NotificationBell/Panel/Toaster,
перекомпоновка top-bar, стили; useServerEvents знает тип notifications.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
1.3 KiB
Python
35 lines
1.3 KiB
Python
"""Уведомления игрока: список (pull) и отметка прочитанными.
|
|
|
|
Появление в реальном времени обеспечивает SSE-сигнал `{type:"notifications"}` — по нему клиент
|
|
перезапрашивает этот список. Хранение — 72 часа; протухшие чистятся при чтении (и фоном)."""
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from sqlmodel import Session
|
|
|
|
from app.auth.deps import get_current_user
|
|
from app.db.session import get_session
|
|
from app.models import User
|
|
from app.schemas import api as s
|
|
from app.services import notification_service
|
|
|
|
router = APIRouter(prefix="/notifications", tags=["notifications"])
|
|
|
|
|
|
@router.get("", response_model=s.NotificationList)
|
|
def my_notifications(
|
|
session: Session = Depends(get_session),
|
|
user: User = Depends(get_current_user),
|
|
) -> dict:
|
|
return notification_service.list_for_user(session, user.id) # type: ignore[arg-type]
|
|
|
|
|
|
@router.post("/read", response_model=s.OkResponse)
|
|
def mark_read(
|
|
body: s.NotificationMarkRead,
|
|
session: Session = Depends(get_session),
|
|
user: User = Depends(get_current_user),
|
|
) -> s.OkResponse:
|
|
notification_service.mark_read(session, user.id, body.ids) # type: ignore[arg-type]
|
|
return s.OkResponse()
|