DispelEvilBot/bot/handlers/member_events.py

115 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""События участников: добавление бота, вход и выход пользователей."""
from __future__ import annotations
import logging
from aiogram import Router
from aiogram.enums import ChatMemberStatus
from aiogram.filters import JOIN_TRANSITION, LEAVE_TRANSITION, ChatMemberUpdatedFilter
from aiogram.types import ChatMemberUpdated, FSInputFile
from aiogram.utils.keyboard import InlineKeyboardBuilder
from bot.services import alerts
from bot.services import users as users_service
from common.analytics import EventType, record
from common.config import get_settings
from common.texts import system, welcome
from common.texts.render import render
from common.texts.store import get_text
logger = logging.getLogger(__name__)
router = Router(name="member_events")
@router.my_chat_member(ChatMemberUpdatedFilter(member_status_changed=JOIN_TRANSITION))
async def bot_added_handler(event: ChatMemberUpdated) -> None:
"""Бот добавлен в чат."""
settings = get_settings()
if event.chat.id not in {settings.chat_id, settings.alert_chat_id}:
await event.bot.send_message(chat_id=event.chat.id, text=system.MSG_BOT_FOREIGN_CHAT)
await event.bot.leave_chat(event.chat.id)
else:
await event.bot.send_message(chat_id=event.chat.id, text=system.MSG_BOT_ADDED)
@router.chat_member(ChatMemberUpdatedFilter(member_status_changed=JOIN_TRANSITION))
async def welcome_handler(event: ChatMemberUpdated) -> None:
"""Пользователь вошёл в чат — приветствие."""
user = event.new_chat_member.user
if user.is_bot:
return
if event.chat.id != get_settings().chat_id:
return
await users_service.register_from_event(event)
await alerts.notify_join(
event.bot,
username=user.username,
user_id=user.id,
chat_title=event.chat.title or "",
)
builder = InlineKeyboardBuilder()
builder.button(text=welcome.MSG_WELCOME_BUTTON_CAPTION, url=welcome.MSG_WELCOME_BUTTON_URL)
await event.bot.send_photo(
chat_id=event.chat.id,
photo=FSInputFile("images/welcome_image.jpg"),
caption=render(await get_text("welcome.text"), {"username": user.username}),
)
await event.bot.send_message(
chat_id=event.chat.id,
text=await get_text("welcome.text2"),
reply_markup=builder.as_markup(),
)
await event.bot.send_message(chat_id=event.chat.id, text=await get_text("welcome.text3"))
@router.chat_member(ChatMemberUpdatedFilter(member_status_changed=LEAVE_TRANSITION))
async def goodbye_handler(event: ChatMemberUpdated) -> None:
"""Пользователь вышел или был исключён — удалить данные именно его."""
leaver = event.old_chat_member.user
if leaver.is_bot:
return
actor = event.from_user
kicked = event.new_chat_member.status == ChatMemberStatus.KICKED
by_self = actor is None or actor.id == leaver.id
record(
EventType.LEAVE,
user_id=leaver.id,
username=leaver.username,
chat_id=event.chat.id,
payload={
"chat_title": event.chat.title or "",
"kicked": kicked,
"by_id": actor.id if actor and not by_self else 0,
"by_username": actor.username if actor and not by_self else "",
},
)
await users_service.delete_user(leaver.id)
logger.info("Удалён пользователь %s после выхода из чата", leaver.id)
# Исключение самим ботом (кнопка в админке): уведомление уже отправила админка.
if kicked and actor is not None and actor.id == event.bot.id:
return
if kicked and not by_self:
await alerts.notify_kick(
event.bot,
actor_username=actor.username if actor else None,
actor_id=actor.id if actor else 0,
username=leaver.username,
user_id=leaver.id,
chat_title=event.chat.title or "",
)
else:
await alerts.notify_leave(
event.bot,
username=leaver.username,
user_id=leaver.id,
chat_title=event.chat.title or "",
)