"""Общий вход: внешняя личность → пользователь → сессия. Прод-безопасный модуль (без импортов 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.security import client_ip 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, user.token_version) # 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=client_ip(request), 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)