miltu-bot refactor
This commit is contained in:
104
bot/handlers.py
104
bot/handlers.py
@@ -1,61 +1,61 @@
|
||||
from datetime import datetime, timezone as py_tz
|
||||
import logging
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
from django.utils import timezone
|
||||
from .models import TelegramChat
|
||||
|
||||
def _now_aware():
|
||||
return timezone.now()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
async def upsert_chat_from_update(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""
|
||||
Вызывайте в message-хендлерах, чтобы обновлять last_message_at и тайтл.
|
||||
"""
|
||||
chat = update.effective_chat
|
||||
if not chat:
|
||||
return
|
||||
def _svc(context: ContextTypes.DEFAULT_TYPE):
|
||||
return context.application.bot_data["services"] # BotServices
|
||||
|
||||
obj, created = TelegramChat.objects.update_or_create(
|
||||
id=chat.id,
|
||||
defaults={
|
||||
"type": chat.type,
|
||||
"title": chat.title or "",
|
||||
"username": chat.username or "",
|
||||
"is_member": True, # если есть сообщения — бот, скорее всего, в чате
|
||||
"last_message_at": _now_aware(),
|
||||
}
|
||||
)
|
||||
# created можно игнорировать; при необходимости — логировать
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
if update.effective_chat:
|
||||
s = _svc(context)
|
||||
await s.chats.upsert_chat(
|
||||
bot=s.bot,
|
||||
chat_id=update.effective_chat.id,
|
||||
chat_type=update.effective_chat.type,
|
||||
title=getattr(update.effective_chat, "title", "") or "",
|
||||
username=getattr(update.effective_chat, "username", "") or "",
|
||||
is_member=True,
|
||||
touch_last_message=True,
|
||||
)
|
||||
user = update.effective_user
|
||||
await update.effective_message.reply_text(f"Привет, {user.first_name or 'друг'}! Я бот автопостинга.")
|
||||
|
||||
async def ping(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
await update.effective_message.reply_text("pong")
|
||||
|
||||
async def on_my_chat_member(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""
|
||||
Ловим изменение статуса бота в чатах (добавили/кикнули).
|
||||
"""
|
||||
if not update.my_chat_member:
|
||||
return
|
||||
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
if update.effective_chat:
|
||||
s = _svc(context)
|
||||
await s.chats.upsert_chat(
|
||||
bot=s.bot,
|
||||
chat_id=update.effective_chat.id,
|
||||
chat_type=update.effective_chat.type,
|
||||
title=getattr(update.effective_chat, "title", "") or "",
|
||||
username=getattr(update.effective_chat, "username", "") or "",
|
||||
is_member=True,
|
||||
touch_last_message=True,
|
||||
)
|
||||
await update.effective_message.reply_text(update.effective_message.text)
|
||||
|
||||
chat = update.my_chat_member.chat
|
||||
new_status = update.my_chat_member.new_chat_member.status # "member"/"administrator"/"kicked"/"left"/...
|
||||
is_in_chat = new_status in ("member", "administrator")
|
||||
async def my_chat_member_update(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
try:
|
||||
chat = update.effective_chat
|
||||
status = update.my_chat_member.new_chat_member.status # administrator|member|left|kicked
|
||||
is_member = status in ("administrator", "member")
|
||||
s = _svc(context)
|
||||
await s.chats.upsert_chat(
|
||||
bot=s.bot,
|
||||
chat_id=chat.id,
|
||||
chat_type=chat.type,
|
||||
title=getattr(chat, "title", "") or "",
|
||||
username=getattr(chat, "username", "") or "",
|
||||
is_member=is_member,
|
||||
)
|
||||
logger.info("my_chat_member: %s in %s (%s)", status, chat.id, chat.type)
|
||||
except Exception:
|
||||
logger.exception("Failed to process my_chat_member update")
|
||||
|
||||
defaults = {
|
||||
"type": chat.type,
|
||||
"title": chat.title or "",
|
||||
"username": getattr(chat, "username", "") or "",
|
||||
"is_member": is_in_chat,
|
||||
"last_message_at": _now_aware(),
|
||||
}
|
||||
|
||||
if is_in_chat:
|
||||
defaults["left_at"] = None
|
||||
defaults.setdefault("joined_at", _now_aware())
|
||||
|
||||
obj, _ = TelegramChat.objects.update_or_create(
|
||||
id=chat.id,
|
||||
defaults=defaults
|
||||
)
|
||||
|
||||
if not is_in_chat and obj.left_at is None:
|
||||
obj.left_at = _now_aware()
|
||||
obj.save(update_fields=["is_member", "left_at"])
|
||||
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
logger.exception("PTB error: %s", context.error)
|
||||
Reference in New Issue
Block a user