From b96bffda377e480a37774a674f16b2737491ed9d Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 30 Oct 2026 14:44:43 +0200 Subject: [PATCH] fix(posts): split copy_text and callback_data into separate buttons per Bot API spec --- VERSION | 2 +- keyboards.py | 14 ++++++++++++-- tests/test_writer_features.py | 8 +++++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index cfdc2af..53f6902 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0+86 +0.1.0+87 diff --git a/keyboards.py b/keyboards.py index 1e41882..d553cc7 100644 --- a/keyboards.py +++ b/keyboards.py @@ -103,12 +103,22 @@ def subscription_plans_keyboard() -> InlineKeyboardMarkup: def post_copy_keyboard(post_text: str, post_index: int) -> InlineKeyboardMarkup: - """Кнопка копирования поста: клик копирует текст (copy_text), нажатие пишется в статистику (callback_data).""" + """Кнопка копирования поста. + + По доке Bot API (InlineKeyboardButton): «Exactly one of the fields other than + text/icon_custom_emoji_id/style must be used» — copy_text и callback_data в одной + кнопке не работают: Telegram трактует такую кнопку как callback-кнопку и копирование + не происходит. Поэтому две отдельные кнопки: левая чисто копирует текст, правая + пишет нажатие в статистику. + """ return InlineKeyboardMarkup( inline_keyboard=[[ InlineKeyboardButton( text="📋 Скопировать", - copy_text=CopyTextButton(text=post_text), + copy_text=CopyTextButton(text=post_text[:256]), + ), + InlineKeyboardButton( + text="📊", callback_data=f"copy_post:{post_index}", ), ]], diff --git a/tests/test_writer_features.py b/tests/test_writer_features.py index 60e7e34..99810cb 100644 --- a/tests/test_writer_features.py +++ b/tests/test_writer_features.py @@ -1232,9 +1232,10 @@ class PostCopyButtonTests(unittest.IsolatedAsyncioTestCase): ): await bot._send_three_posts(cast(Any, message), ["Пост А", "Пост Б"], user_id=None) first = message.answer.await_args_list[0] - button = first.kwargs["reply_markup"].inline_keyboard[0][0] - self.assertEqual(button.copy_text.text, "Пост А") - self.assertEqual(button.callback_data, "copy_post:0") + copy_button, stats_button = first.kwargs["reply_markup"].inline_keyboard[0] + self.assertEqual(copy_button.copy_text.text, "Пост А") + self.assertIsNone(copy_button.callback_data) # по доке: copy_text и callback_data в одной кнопке несовместимы + self.assertEqual(stats_button.callback_data, "copy_post:0") async def test_copy_callback_records_event_and_keeps_button(self): callback = SimpleNamespace( @@ -1242,6 +1243,7 @@ class PostCopyButtonTests(unittest.IsolatedAsyncioTestCase): message=MagicMock(spec=bot.Message), answer=AsyncMock(), ) + callback.message.edit_reply_markup = AsyncMock() with patch.object(bot.asyncio, "to_thread", new=AsyncMock()) as to_thread: await bot.post_copy_pressed(cast(Any, callback)) to_thread.assert_awaited_once()