119 lines
4.6 KiB
Python
119 lines
4.6 KiB
Python
from collections.abc import Awaitable, Callable
|
|
from typing import Any
|
|
|
|
from maxapi.filters.middleware import BaseMiddleware
|
|
from maxapi.types.updates.bot_started import BotStarted
|
|
from maxapi.types.updates.message_callback import MessageCallback
|
|
from maxapi.types.updates.message_created import MessageCreated
|
|
|
|
from bot.logging_setup import get_logger
|
|
from database.queries.bot_users import get_bot_user_by_max_id
|
|
from database.queries.message_log import log_message
|
|
|
|
logger = get_logger("bot.middleware")
|
|
|
|
|
|
def _user_label(bot_user: dict | None, user_id: int | None) -> str:
|
|
if bot_user:
|
|
name = bot_user.get("first_name") or bot_user.get("username") or ""
|
|
return f"user_id={bot_user['max_user_id']} ({name})" if name else f"user_id={bot_user['max_user_id']}"
|
|
return f"user_id={user_id}"
|
|
|
|
|
|
class AuthMiddleware(BaseMiddleware):
|
|
async def __call__(
|
|
self,
|
|
handler: Callable[[Any, dict[str, Any]], Awaitable[Any]],
|
|
event: Any,
|
|
data: dict[str, Any],
|
|
) -> Any:
|
|
update_type = getattr(event, "update_type", type(event).__name__)
|
|
|
|
# BotStarted — всегда пропускаем
|
|
if isinstance(event, BotStarted):
|
|
logger.info("▶ bot_started | user_id=%s chat_id=%s", event.user.user_id, event.chat_id)
|
|
return await handler(event, data)
|
|
|
|
# /start — пропускаем без авторизации
|
|
if isinstance(event, MessageCreated):
|
|
body = event.message.body
|
|
text = (body.text or "").strip() if body else ""
|
|
if text.lower().startswith("/start"):
|
|
ids = event.get_ids()
|
|
logger.info("▶ /start | user_id=%s", ids[1])
|
|
return await handler(event, data)
|
|
|
|
# Получаем user_id
|
|
ids = event.get_ids()
|
|
user_id = ids[1] if ids else None
|
|
chat_id = ids[0] if ids else None
|
|
if user_id is None:
|
|
return
|
|
|
|
bot_user = await get_bot_user_by_max_id(user_id)
|
|
|
|
if bot_user is None:
|
|
logger.debug("⚠ unknown user_id=%s | %s — ignored", user_id, update_type)
|
|
return
|
|
|
|
if bot_user["is_blocked"]:
|
|
logger.info("🚫 blocked %s | %s — ignored", _user_label(bot_user, user_id), update_type)
|
|
return
|
|
|
|
if not bot_user["is_authorized"]:
|
|
# Пропускаем шаринг контакта — это шаг авторизации
|
|
if isinstance(event, MessageCreated):
|
|
body = event.message.body
|
|
if body and body.attachments:
|
|
from maxapi.enums.attachment import AttachmentType
|
|
for att in body.attachments:
|
|
if getattr(att, "type", None) == AttachmentType.CONTACT:
|
|
logger.info(
|
|
"📱 contact shared | %s",
|
|
_user_label(bot_user, user_id),
|
|
)
|
|
data["bot_user"] = bot_user
|
|
return await handler(event, data)
|
|
logger.debug("⚠ not authorized %s | %s — ignored", _user_label(bot_user, user_id), update_type)
|
|
return
|
|
|
|
data["bot_user"] = bot_user
|
|
|
|
# Логируем входящие сообщения
|
|
if isinstance(event, MessageCreated):
|
|
body = event.message.body
|
|
text_preview = ""
|
|
atts = []
|
|
if body:
|
|
text_preview = (body.text or "")[:80]
|
|
if body.attachments:
|
|
for a in body.attachments:
|
|
atts.append({"type": str(getattr(a, "type", ""))})
|
|
logger.info(
|
|
"💬 message | %s | chat=%s | text=%r | attachments=%s",
|
|
_user_label(bot_user, user_id), chat_id,
|
|
text_preview, [a["type"] for a in atts] or None,
|
|
)
|
|
await log_message(
|
|
direction="in",
|
|
max_user_id=user_id,
|
|
max_chat_id=chat_id,
|
|
message_id=body.mid if body else None,
|
|
text=body.text if body else None,
|
|
attachments=atts or None,
|
|
)
|
|
|
|
elif isinstance(event, MessageCallback):
|
|
payload = event.callback.payload or ""
|
|
logger.info(
|
|
"🔘 callback | %s | chat=%s | payload=%r",
|
|
_user_label(bot_user, user_id), chat_id, payload,
|
|
)
|
|
|
|
else:
|
|
logger.info(
|
|
"📨 %s | %s | chat=%s",
|
|
update_type, _user_label(bot_user, user_id), chat_id,
|
|
)
|
|
|
|
return await handler(event, data)
|