Fix p2p_chat frozen instance error and improve sender info display
Some checks failed
continuous-integration/drone/pr Build is failing

- Remove frozen Message attribute assignment in back_to_menu handler
- Reconstruct chat menu properly instead of modifying frozen Message
- Add format_sender_name() function for consistent sender display
- Show user card number for admins in P2P dialogs
- Improve display of sender info with emoji indicators (🔵)
- Show card number in conversations list if available

Fixes: ValidationError: Instance is frozen on p2p:back_to_menu callback
This commit is contained in:
2026-03-07 11:11:06 +09:00
parent 6089c90d22
commit 45d960746b

View File

@@ -30,6 +30,31 @@ def is_admin(user_id: int) -> bool:
return user_id in ADMIN_IDS return user_id in ADMIN_IDS
def format_sender_name(user: User, is_current_user: bool = False, current_user_is_admin: bool = False) -> str:
"""
Форматирует имя отправителя для отображения в чате
Args:
user: Объект пользователя
is_current_user: Текущий ли это пользователь
current_user_is_admin: Админ ли текущий пользователь
Returns:
Отформатированное имя
"""
if is_current_user:
return "🔵 Вы"
# Формируем базовое имя
name = f"@{user.username}" if user.username else user.first_name or "Unknown"
# Добавляем информацию о карте если пользователь админ и у собеседника есть карта
if current_user_is_admin and user.club_card_number:
name += f" (карта: {user.club_card_number})"
return f"🔵 {name}"
@router.message(CaseInsensitiveCommand("chat")) @router.message(CaseInsensitiveCommand("chat"))
async def show_chat_menu(message: Message, state: FSMContext): async def show_chat_menu(message: Message, state: FSMContext):
""" """
@@ -169,7 +194,11 @@ async def start_conversation(callback: CallbackQuery, state: FSMContext):
if messages: if messages:
text += "📝 <b>Последние сообщения:</b>\n\n" text += "📝 <b>Последние сообщения:</b>\n\n"
for msg in reversed(messages[-5:]): # Последние 5 сообщений for msg in reversed(messages[-5:]): # Последние 5 сообщений
sender_name = "Вы" if msg.sender_id == sender.id else recipient_name # Определяем имя отправителя
is_current = msg.sender_id == sender.id
user_for_display = sender if is_current else recipient
sender_name = format_sender_name(user_for_display, is_current, is_admin(sender.telegram_id))
msg_text = msg.text[:50] + "..." if msg.text and len(msg.text) > 50 else (msg.text or f"[{msg.message_type}]") msg_text = msg.text[:50] + "..." if msg.text and len(msg.text) > 50 else (msg.text or f"[{msg.message_type}]")
text += f"{sender_name}: {msg_text}\n" text += f"{sender_name}: {msg_text}\n"
text += "\n" text += "\n"
@@ -234,7 +263,11 @@ async def show_conversations(callback: CallbackQuery):
callback_data=f"p2p:user:{peer.id}" callback_data=f"p2p:user:{peer.id}"
)]) )])
text += f"{icon} <b>{peer_name}</b>\n" text += f"{icon} <b>{peer_name}</b>"
# Показываем номер карты если есть
if peer.club_card_number:
text += f" (карта: {peer.club_card_number})"
text += "\n"
text += f" {preview}\n" text += f" {preview}\n"
if unread > 0: if unread > 0:
text += f" 📨 Непрочитанных: {unread}\n" text += f" 📨 Непрочитанных: {unread}\n"
@@ -268,12 +301,53 @@ async def end_conversation(callback: CallbackQuery, state: FSMContext):
async def back_to_menu(callback: CallbackQuery, state: FSMContext): async def back_to_menu(callback: CallbackQuery, state: FSMContext):
"""Вернуться в главное меню""" """Вернуться в главное меню"""
await callback.answer() await callback.answer()
await state.clear()
# Имитируем команду /chat async with async_session_maker() as session:
fake_message = callback.message user = await UserService.get_or_create_user(
fake_message.from_user = callback.from_user session,
callback.from_user.id,
username=callback.from_user.username,
first_name=callback.from_user.first_name,
last_name=callback.from_user.last_name
)
if not user:
await callback.message.edit_text("❌ Вы не зарегистрированы. Используйте /start")
return
# Получаем количество непрочитанных сообщений
unread_count = await P2PMessageService.get_unread_count(session, user.id)
# Получаем последние диалоги
recent = await P2PMessageService.get_recent_conversations(session, user.id, limit=5)
await show_chat_menu(fake_message, state) text = "💬 <b>Чат</b>\n\n"
if unread_count > 0:
text += f"📨 У вас <b>{unread_count}</b> непрочитанных сообщений\n\n"
text += "Выберите действие:"
buttons = [
[InlineKeyboardButton(
text="✉️ Написать пользователю",
callback_data="p2p:select_user"
)],
[InlineKeyboardButton(
text="📋 Мои диалоги",
callback_data="p2p:my_conversations"
)]
]
if recent:
text += "\n\n<b>Последние диалоги:</b>\n"
for peer, last_msg, unread in recent:
unread_badge = f" ({unread})" if unread > 0 else ""
text += f" • @{peer.username or peer.first_name}{unread_badge}\n"
kb = InlineKeyboardMarkup(inline_keyboard=buttons)
await callback.message.edit_text(text, reply_markup=kb, parse_mode="HTML")
# Обработчик сообщений в состоянии chatting # Обработчик сообщений в состоянии chatting