"""Общий вход: внешняя личность → пользователь → сессия. Прод-безопасный модуль (без импортов dev-провайдера). Используется и Telegram-входом, и dev-входом. """ from __future__ import annotations from fastapi import Request, Response from sqlmodel import Session from app.auth.provider import ExternalIdentity from app.core import security from app.core.errors import ForbiddenError from app.models import User from app.services import audit_service, user_service def establish_session( session: Session, response: Response, request: Request, user: User, provider: str ) -> User: """Открыть сессию уже найденному/созданному пользователю (cookie + аудит).""" if not user.is_active: raise ForbiddenError("Аккаунт отключён администратором.", code="ACCOUNT_DISABLED") security.set_user_session(response, user.id, provider) # type: ignore[arg-type] audit_service.record( session, actor_id=user.id, action="login", entity_type="user", entity_id=user.id, payload={"provider": provider}, ip=request.client.host if request.client else None, user_agent=request.headers.get("user-agent"), ) session.commit() return user def login_with_identity( session: Session, response: Response, request: Request, identity: ExternalIdentity ) -> User: """Вход с авто-созданием (dev-вход по нику): ник подбирается автоматически.""" user = user_service.get_or_create_from_identity(session, identity) return establish_session(session, response, request, user, identity.provider)