Fix poll handler for kurigram compatibility
Changes: - Replace PollAnswerHandler with RawUpdateHandler - Handle UpdateMessagePollVote instead of PollAnswer - Parse options as Vector<bytes> per Telegram API spec - Extract user_id from PeerUser properly - Add test_kurigram_compat.py for validation - Update STATISTICS_GUIDE.md with correct handler info Fixes ImportError with kurigram's handler structure. Now compatible with Telegram MTProto API Layer 222. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -2,9 +2,8 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.handlers import PollAnswerHandler
|
||||
from pyrogram.types import PollAnswer
|
||||
from pyrogram import Client, raw
|
||||
from pyrogram.handlers import RawUpdateHandler
|
||||
|
||||
from game import SQLiteWouldYouRatherRepository
|
||||
|
||||
@@ -19,45 +18,70 @@ class PollStatisticsHandler:
|
||||
|
||||
def register(self, client: Client) -> None:
|
||||
"""Регистрирует обработчик в клиенте Pyrogram."""
|
||||
client.add_handler(PollAnswerHandler(self._on_poll_answer))
|
||||
client.add_handler(RawUpdateHandler(self._on_raw_update))
|
||||
logger.info("Poll statistics handler registered.")
|
||||
|
||||
async def _on_poll_answer(self, _: Client, poll_answer: PollAnswer) -> None:
|
||||
"""Обрабатывает ответ пользователя на опрос."""
|
||||
async def _on_raw_update(self, client: Client, update, users, chats) -> None:
|
||||
"""Обрабатывает raw update от Telegram."""
|
||||
# Проверяем, является ли это обновлением голосования в опросе
|
||||
if not isinstance(update, raw.types.UpdateMessagePollVote):
|
||||
return
|
||||
|
||||
try:
|
||||
poll_id = poll_answer.poll_id
|
||||
if not poll_id:
|
||||
return
|
||||
|
||||
# Получаем question_id по poll_id
|
||||
question_id = self.repository.get_question_id_by_poll(poll_id)
|
||||
if question_id is None:
|
||||
logger.debug("Poll %s not found in mappings, skipping.", poll_id)
|
||||
return
|
||||
|
||||
# Обрабатываем выбранные опции
|
||||
option_ids = poll_answer.option_ids or []
|
||||
for option_index in option_ids:
|
||||
# Получаем answer_id по индексу опции
|
||||
answer_id = self.repository.get_answer_id_by_option_index(
|
||||
question_id, option_index
|
||||
)
|
||||
if answer_id is None:
|
||||
logger.warning(
|
||||
"Answer not found for question %s option %s",
|
||||
question_id,
|
||||
option_index,
|
||||
)
|
||||
continue
|
||||
|
||||
# Записываем статистику
|
||||
self.repository.record_answer(question_id, answer_id, increment=1)
|
||||
logger.debug(
|
||||
"Recorded answer: question=%s, answer=%s, user=%s",
|
||||
question_id,
|
||||
answer_id,
|
||||
poll_answer.user.id if poll_answer.user else "unknown",
|
||||
)
|
||||
|
||||
await self._process_poll_vote(update)
|
||||
except Exception:
|
||||
logger.exception("Failed to process poll answer: %s", poll_answer)
|
||||
logger.exception("Failed to process poll vote: %s", update)
|
||||
|
||||
async def _process_poll_vote(self, update: raw.types.UpdateMessagePollVote) -> None:
|
||||
"""Обрабатывает голос пользователя в опросе."""
|
||||
poll_id = str(update.poll_id)
|
||||
|
||||
# Получаем question_id по poll_id
|
||||
question_id = self.repository.get_question_id_by_poll(poll_id)
|
||||
if question_id is None:
|
||||
logger.debug("Poll %s not found in mappings, skipping.", poll_id)
|
||||
return
|
||||
|
||||
# Обрабатываем выбранные опции (каждая опция - это bytes объект)
|
||||
option_bytes_list = update.options or []
|
||||
|
||||
# Получаем user_id из peer
|
||||
peer = update.peer
|
||||
if isinstance(peer, raw.types.PeerUser):
|
||||
user_id = peer.user_id
|
||||
else:
|
||||
user_id = "unknown"
|
||||
|
||||
for option_data in option_bytes_list:
|
||||
# В Telegram API каждая опция - это один байт с индексом
|
||||
# option_data это bytes объект, берём первый байт как индекс
|
||||
try:
|
||||
if isinstance(option_data, bytes):
|
||||
option_index = option_data[0] if len(option_data) > 0 else 0
|
||||
else:
|
||||
option_index = int(option_data)
|
||||
except (ValueError, TypeError, IndexError) as e:
|
||||
logger.warning("Invalid option data: %s (%s)", option_data, e)
|
||||
continue
|
||||
|
||||
# Получаем answer_id по индексу опции
|
||||
answer_id = self.repository.get_answer_id_by_option_index(
|
||||
question_id, option_index
|
||||
)
|
||||
if answer_id is None:
|
||||
logger.warning(
|
||||
"Answer not found for question %s option %s",
|
||||
question_id,
|
||||
option_index,
|
||||
)
|
||||
continue
|
||||
|
||||
# Записываем статистику
|
||||
self.repository.record_answer(question_id, answer_id, increment=1)
|
||||
logger.debug(
|
||||
"Recorded answer: question=%s, answer=%s, option=%s, user=%s",
|
||||
question_id,
|
||||
answer_id,
|
||||
option_index,
|
||||
user_id,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user