From a22ba094dbd49e2e35182e5efdbe354d12367aac Mon Sep 17 00:00:00 2001 From: "Choi A.K." Date: Sat, 6 Sep 2025 12:27:17 +0900 Subject: [PATCH] inline keyboard fix --- handlers/new_post.py | 55 +++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/handlers/new_post.py b/handlers/new_post.py index bf128fa..a385295 100644 --- a/handlers/new_post.py +++ b/handlers/new_post.py @@ -15,6 +15,7 @@ from sqlalchemy import select as sa_select from db import AsyncSessionLocal from models import Channel, Group from .permissions import get_or_create_admin, list_channels_for_admin, has_scope_on_channel, SCOPE_POST +from models import Channel, Group, Button SELECT_MEDIA, SELECT_TEXT, SELECT_TARGET = range(3) @@ -161,12 +162,28 @@ async def select_target(update: Update, context: ContextTypes.DEFAULT_TYPE): return ConversationHandler.END channel = (await session.execute(sa_select(Channel).where(Channel.id == channel_id))).scalar_one_or_none() - chat_id = channel.link if channel else None + if not channel: + await query.edit_message_text("Канал не найден.") + return ConversationHandler.END + chat_id = channel.link + + # КНОПКИ ДЛЯ КАНАЛА + btns = (await session.execute(sa_select(Button).where(Button.channel_id == channel_id))).scalars().all() + if btns: + markup = InlineKeyboardMarkup([[InlineKeyboardButton(str(b.name), url=str(b.url))] for b in btns]) elif data and data.startswith('group_'): group_id = int(data.split('_')[1]) group = (await session.execute(sa_select(Group).where(Group.id == group_id))).scalar_one_or_none() - chat_id = group.link if group else None + if not group: + await query.edit_message_text("Группа не найдена.") + return ConversationHandler.END + chat_id = group.link + + # КНОПКИ ДЛЯ ГРУППЫ + btns = (await session.execute(sa_select(Button).where(Button.group_id == group_id))).scalars().all() + if btns: + markup = InlineKeyboardMarkup([[InlineKeyboardButton(str(b.name), url=str(b.url))] for b in btns]) if not chat_id: await query.edit_message_text('Ошибка: объект не найден.') @@ -181,11 +198,11 @@ async def select_target(update: Update, context: ContextTypes.DEFAULT_TYPE): text: str = ud.get("text", "") or "" entities: List[MessageEntity] = ud.get("entities", []) or [] - # санация перед отправкой + # санация перед отправкой (custom_emoji/UTF-16) entities = _strip_broken_entities(entities) entities = _split_custom_emoji_by_utf16(text, entities) - # 1) Пытаемся «бит-в-бит» копию + # 1) Пытаемся «бит-в-бит» копию + КЛАВИАТУРУ has_media_parts = any(k in ud for k in ("photo","animation","video","document","audio","voice","sticker")) try: if ud.get("src_chat_id") and ud.get("src_msg_id") and not has_media_parts: @@ -193,46 +210,55 @@ async def select_target(update: Update, context: ContextTypes.DEFAULT_TYPE): chat_id=chat_id, from_chat_id=ud["src_chat_id"], message_id=ud["src_msg_id"], + reply_markup=markup, # <— ВАЖНО ) await query.edit_message_text("Пост отправлен!") return ConversationHandler.END except BadRequest: - pass # упадем в fallback + pass # упадём в fallback - # 2) fallback — отправка с entities/caption_entities (без parse_mode) + # 2) fallback — отправка с entities/caption_entities и КЛАВИАТУРОЙ try: sent = False if "photo" in ud: await context.bot.send_photo(chat_id=chat_id, photo=ud["photo"], - caption=(text or None), caption_entities=(entities if text else None)) + caption=(text or None), caption_entities=(entities if text else None), + reply_markup=markup) sent = True elif "animation" in ud: await context.bot.send_animation(chat_id=chat_id, animation=ud["animation"], - caption=(text or None), caption_entities=(entities if text else None)) + caption=(text or None), caption_entities=(entities if text else None), + reply_markup=markup) sent = True elif "video" in ud: await context.bot.send_video(chat_id=chat_id, video=ud["video"], - caption=(text or None), caption_entities=(entities if text else None)) + caption=(text or None), caption_entities=(entities if text else None), + reply_markup=markup) sent = True elif "document" in ud: await context.bot.send_document(chat_id=chat_id, document=ud["document"], - caption=(text or None), caption_entities=(entities if text else None)) + caption=(text or None), caption_entities=(entities if text else None), + reply_markup=markup) sent = True elif "audio" in ud: await context.bot.send_audio(chat_id=chat_id, audio=ud["audio"], - caption=(text or None), caption_entities=(entities if text else None)) + caption=(text or None), caption_entities=(entities if text else None), + reply_markup=markup) sent = True elif "voice" in ud: await context.bot.send_voice(chat_id=chat_id, voice=ud["voice"], - caption=(text or None), caption_entities=(entities if text else None)) + caption=(text or None), caption_entities=(entities if text else None), + reply_markup=markup) sent = True elif "sticker" in ud: - await context.bot.send_sticker(chat_id=chat_id, sticker=ud["sticker"]) + # Можно прикрепить клавиатуру и к стикеру (Telegram поддерживает reply_markup) + await context.bot.send_sticker(chat_id=chat_id, sticker=ud["sticker"], reply_markup=markup) + # Если есть текст — отправим вторым сообщением (кнопки уже в первом) if text: await context.bot.send_message(chat_id=chat_id, text=text, entities=entities) sent = True else: - await context.bot.send_message(chat_id=chat_id, text=text, entities=entities) + await context.bot.send_message(chat_id=chat_id, text=text, entities=entities, reply_markup=markup) sent = True await query.edit_message_text('Пост отправлен!' if sent else 'Ошибка: не удалось отправить сообщение.') @@ -241,6 +267,7 @@ async def select_target(update: Update, context: ContextTypes.DEFAULT_TYPE): return ConversationHandler.END + new_post_conv = ConversationHandler( entry_points=[CommandHandler("new_post", new_post_start)], states={