Fix text dialog routing and club card registration recovery
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-09-13 21:39:40 +09:00
parent 3c1a6a02a5
commit f3f8d0f737
28 changed files with 788 additions and 334 deletions

View File

@@ -1,8 +1,10 @@
"""Админские обработчики для управления чатом"""
from html import escape
from src.utils.input_validation import numeric_id
from src.utils.errors import public_error
from aiogram import Router, F
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
from aiogram.filters import Command
from src.filters.case_insensitive import CaseInsensitiveCommand as Command
from sqlalchemy.ext.asyncio import AsyncSession
from src.filters.case_insensitive import CaseInsensitiveCommand
@@ -20,6 +22,23 @@ from src.core.permissions import admin_only
router = Router(name='admin_chat_router')
async def reply_target(message: Message):
"""Resolve the human author of a bot copy only within the operator's dialog."""
replied = message.reply_to_message
if replied.from_user and not replied.from_user.is_bot:
return replied.from_user.id
from sqlalchemy import select
from src.core.models import User, P2PMessage
async with async_session_maker() as session:
original = await ChatMessageService.get_message_by_telegram_id(
session, replied.message_id, chat_id=message.chat.id)
if original:
return await session.scalar(select(User.telegram_id).where(User.id == original.user_id))
operator_id = select(User.id).where(User.telegram_id == message.from_user.id).scalar_subquery()
return await session.scalar(select(User.telegram_id).join(P2PMessage, P2PMessage.sender_id == User.id).where(
P2PMessage.recipient_id == operator_id, P2PMessage.recipient_message_id == replied.message_id))
def get_chat_mode_keyboard() -> InlineKeyboardMarkup:
"""Клавиатура выбора режима чата"""
return InlineKeyboardMarkup(inline_keyboard=[
@@ -89,7 +108,11 @@ async def cmd_set_forward(message: Message):
)
return
chat_id = args[1].strip()
try:
chat_id = str(numeric_id(args[1], signed=True))
except ValueError as error:
await message.answer(str(error))
return
async with async_session_maker() as session:
settings = await ChatSettingsService.set_forward_chat(session, chat_id)
@@ -135,7 +158,10 @@ async def cmd_ban(message: Message):
# Проверяем является ли это ответом на сообщение
if message.reply_to_message:
target_user_id = message.reply_to_message.from_user.id
target_user_id = await reply_target(message)
if target_user_id is None:
await message.answer("Не удалось определить автора. Укажите его Telegram ID в команде.")
return
reason = message.text.split(maxsplit=1)[1] if len(message.text.split(maxsplit=1)) > 1 else None
else:
args = message.text.split(maxsplit=2)
@@ -150,7 +176,7 @@ async def cmd_ban(message: Message):
return
try:
target_user_id = int(args[1])
target_user_id = numeric_id(args[1])
reason = args[2] if len(args) > 2 else None
except ValueError:
await message.answer("❌ Неверный ID пользователя")
@@ -182,11 +208,11 @@ async def cmd_ban(message: Message):
reason=reason
)
reason_text = f"\n📝 Причина: {reason}" if reason else ""
reason_text = f"\n📝 Причина: {escape(reason[:500])}" if reason else ""
await message.answer(
f"🚫 <b>Пользователь забанен</b>\n\n"
f"👤 Пользователь: {user.name or 'Неизвестен'}\n"
f"👤 Пользователь: {escape(user.nickname or user.first_name or 'Неизвестен')}\n"
f"🆔 ID: <code>{target_user_id}</code>"
f"{reason_text}",
parse_mode="HTML"
@@ -200,7 +226,10 @@ async def cmd_unban(message: Message):
# Проверяем является ли это ответом на сообщение
if message.reply_to_message:
target_user_id = message.reply_to_message.from_user.id
target_user_id = await reply_target(message)
if target_user_id is None:
await message.answer("Не удалось определить автора. Укажите его Telegram ID в команде.")
return
else:
args = message.text.split()
if len(args) < 2:
@@ -214,7 +243,7 @@ async def cmd_unban(message: Message):
return
try:
target_user_id = int(args[1])
target_user_id = numeric_id(args[1])
except ValueError:
await message.answer("❌ Неверный ID пользователя")
return
@@ -252,11 +281,11 @@ async def cmd_banlist(message: Message):
user = ban.user
admin = ban.admin
text += f"👤 {user.name or 'Неизвестен'} (<code>{ban.telegram_id}</code>)\n"
text += f"🔨 Забанил: {admin.name if admin else 'Неизвестен'}\n"
text += f"👤 {escape(user.nickname or user.first_name or 'Неизвестен')} (<code>{ban.telegram_id}</code>)\n"
text += f"🔨 Забанил: {escape((admin.nickname or admin.first_name or 'Неизвестен') if admin else 'Неизвестен')}\n"
if ban.reason:
text += f"📝 Причина: {ban.reason}\n"
text += f"📝 Причина: {escape(ban.reason[:500])}\n"
text += f"📅 Дата: {ban.banned_at.strftime('%d.%m.%Y %H:%M')}\n"
text += "\n"