Files
2026-05-06 20:47:53 +00:00

77 lines
2.6 KiB
Python

from collections.abc import Awaitable, Callable
from typing import Any
from aiogram import BaseMiddleware
from aiogram.types import CallbackQuery, Message, TelegramObject
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from config import ADMIN_ID
from core.cache_config import ADMIN_CACHE_TTL_SEC
from core.redis_cache import cache_get, cache_key, cache_set
from database.models import Admin
_ADMIN_CACHE_TTL = ADMIN_CACHE_TTL_SEC
class AdminMiddleware(BaseMiddleware):
"""Проверяет, является ли пользователь администратором. Сессию не создаёт — только data['session']."""
_admin_ids: set[int] = set(ADMIN_ID) if isinstance(ADMIN_ID, list | tuple) else {ADMIN_ID}
async def __call__(
self,
handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]],
event: TelegramObject,
data: dict[str, Any],
) -> Any:
session: AsyncSession | None = data.get("session")
data["admin"] = await self._check_admin_access(event, session)
return await handler(event, data)
async def _check_admin_access(
self,
event: TelegramObject,
session: AsyncSession | None,
) -> bool:
try:
user_id = None
if isinstance(event, Message):
if event.from_user:
user_id = event.from_user.id
elif isinstance(event, CallbackQuery):
if event.from_user:
user_id = event.from_user.id
else:
from_user = getattr(event, "from_user", None)
if from_user:
user_id = getattr(from_user, "id", None)
if not user_id:
return False
if user_id in self._admin_ids:
return True
cached = await cache_get(cache_key("admin_access", user_id))
if isinstance(cached, bool):
return cached
if not session:
await cache_set(cache_key("admin_access", user_id), False, _ADMIN_CACHE_TTL)
return False
result = await session.execute(select(Admin).where(Admin.tg_id == user_id))
is_admin = result.scalar_one_or_none() is not None
await cache_set(cache_key("admin_access", user_id), bool(is_admin), _ADMIN_CACHE_TTL)
return is_admin
except Exception:
if session is not None:
try:
await session.rollback()
except Exception:
pass
return False