mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
Revert "Remove blockquote markup to prevent Telegram parse errors"
This commit is contained in:
@@ -14,7 +14,6 @@ from app.database.models import User
|
|||||||
from app.keyboards.admin import get_admin_main_keyboard
|
from app.keyboards.admin import get_admin_main_keyboard
|
||||||
from app.utils.validators import (
|
from app.utils.validators import (
|
||||||
get_html_help_text,
|
get_html_help_text,
|
||||||
format_telegram_quote,
|
|
||||||
sanitize_html,
|
sanitize_html,
|
||||||
validate_html_tags,
|
validate_html_tags,
|
||||||
)
|
)
|
||||||
@@ -183,14 +182,14 @@ async def process_new_message_text(
|
|||||||
)
|
)
|
||||||
|
|
||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
await message.answer(
|
await message.answer(
|
||||||
f"✅ <b>Сообщение добавлено!</b>\n\n"
|
f"✅ <b>Сообщение добавлено!</b>\n\n"
|
||||||
f"<b>ID:</b> {new_message.id}\n"
|
f"<b>ID:</b> {new_message.id}\n"
|
||||||
f"<b>Статус:</b> {'🟢 Активно' if new_message.is_active else '🔴 Неактивно'}\n"
|
f"<b>Статус:</b> {'🟢 Активно' if new_message.is_active else '🔴 Неактивно'}\n"
|
||||||
f"<b>Создано:</b> {new_message.created_at.strftime('%d.%m.%Y %H:%M')}\n\n"
|
f"<b>Создано:</b> {new_message.created_at.strftime('%d.%m.%Y %H:%M')}\n\n"
|
||||||
f"<b>Предварительный просмотр:</b>\n"
|
f"<b>Предварительный просмотр:</b>\n"
|
||||||
f"{format_telegram_quote(sanitize_html(message_text))}",
|
f"<blockquote>{message_text}</blockquote>",
|
||||||
reply_markup=get_user_messages_keyboard(db_user.language),
|
reply_markup=get_user_messages_keyboard(db_user.language),
|
||||||
parse_mode="HTML"
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
@@ -319,7 +318,7 @@ async def view_user_message(
|
|||||||
await callback.answer("❌ Сообщение не найдено", show_alert=True)
|
await callback.answer("❌ Сообщение не найдено", show_alert=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
safe_content = format_telegram_quote(sanitize_html(message.message_text))
|
safe_content = sanitize_html(message.message_text)
|
||||||
|
|
||||||
status_text = "🟢 Активно" if message.is_active else "🔴 Неактивно"
|
status_text = "🟢 Активно" if message.is_active else "🔴 Неактивно"
|
||||||
|
|
||||||
@@ -329,7 +328,7 @@ async def view_user_message(
|
|||||||
f"<b>Создано:</b> {message.created_at.strftime('%d.%m.%Y %H:%M')}\n"
|
f"<b>Создано:</b> {message.created_at.strftime('%d.%m.%Y %H:%M')}\n"
|
||||||
f"<b>Обновлено:</b> {message.updated_at.strftime('%d.%m.%Y %H:%M')}\n\n"
|
f"<b>Обновлено:</b> {message.updated_at.strftime('%d.%m.%Y %H:%M')}\n\n"
|
||||||
f"<b>Содержимое:</b>\n"
|
f"<b>Содержимое:</b>\n"
|
||||||
f"{safe_content}"
|
f"<blockquote>{safe_content}</blockquote>"
|
||||||
)
|
)
|
||||||
|
|
||||||
await callback.message.edit_text(
|
await callback.message.edit_text(
|
||||||
@@ -459,7 +458,7 @@ async def edit_user_message_start(
|
|||||||
await callback.message.edit_text(
|
await callback.message.edit_text(
|
||||||
f"✏️ <b>Редактирование сообщения ID {message.id}</b>\n\n"
|
f"✏️ <b>Редактирование сообщения ID {message.id}</b>\n\n"
|
||||||
f"<b>Текущий текст:</b>\n"
|
f"<b>Текущий текст:</b>\n"
|
||||||
f"{format_telegram_quote(sanitize_html(message.message_text))}\n\n"
|
f"<blockquote>{sanitize_html(message.message_text)}</blockquote>\n\n"
|
||||||
f"Введите новый текст сообщения или отправьте /cancel для отмены:",
|
f"Введите новый текст сообщения или отправьте /cancel для отмены:",
|
||||||
parse_mode="HTML"
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
@@ -524,7 +523,7 @@ async def process_edit_message_text(
|
|||||||
f"<b>ID:</b> {updated_message.id}\n"
|
f"<b>ID:</b> {updated_message.id}\n"
|
||||||
f"<b>Обновлено:</b> {updated_message.updated_at.strftime('%d.%m.%Y %H:%M')}\n\n"
|
f"<b>Обновлено:</b> {updated_message.updated_at.strftime('%d.%m.%Y %H:%M')}\n\n"
|
||||||
f"<b>Новый текст:</b>\n"
|
f"<b>Новый текст:</b>\n"
|
||||||
f"{format_telegram_quote(sanitize_html(new_text))}",
|
f"<blockquote>{sanitize_html(new_text)}</blockquote>",
|
||||||
reply_markup=get_user_messages_keyboard(db_user.language),
|
reply_markup=get_user_messages_keyboard(db_user.language),
|
||||||
parse_mode="HTML"
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ def _format_server_lines(
|
|||||||
name = server.display_name or server.name
|
name = server.display_name or server.name
|
||||||
flag_prefix = f"{server.flag} " if server.flag else ""
|
flag_prefix = f"{server.flag} " if server.flag else ""
|
||||||
server_line = f"{flag_prefix}{name} — {latency_text}"
|
server_line = f"{flag_prefix}{name} — {latency_text}"
|
||||||
lines.append(f"• {server_line}")
|
lines.append(f"<blockquote>{server_line}</blockquote>")
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ async def show_subscription_info(
|
|||||||
if show_devices and devices_list:
|
if show_devices and devices_list:
|
||||||
message += "\n\n" + texts.t(
|
message += "\n\n" + texts.t(
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE",
|
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE",
|
||||||
"📱 <b>Подключенные устройства:</b>\n",
|
"<blockquote>📱 <b>Подключенные устройства:</b>\n",
|
||||||
)
|
)
|
||||||
for device in devices_list[:5]:
|
for device in devices_list[:5]:
|
||||||
platform = device.get('platform', 'Unknown')
|
platform = device.get('platform', 'Unknown')
|
||||||
@@ -365,7 +365,7 @@ async def show_subscription_info(
|
|||||||
if len(device_info) > 35:
|
if len(device_info) > 35:
|
||||||
device_info = device_info[:32] + "..."
|
device_info = device_info[:32] + "..."
|
||||||
message += f"• {device_info}\n"
|
message += f"• {device_info}\n"
|
||||||
message += texts.t("SUBSCRIPTION_CONNECTED_DEVICES_FOOTER", "")
|
message += texts.t("SUBSCRIPTION_CONNECTED_DEVICES_FOOTER", "</blockquote>")
|
||||||
|
|
||||||
subscription_link = get_display_subscription_link(subscription)
|
subscription_link = get_display_subscription_link(subscription)
|
||||||
hide_subscription_link = settings.should_hide_subscription_link()
|
hide_subscription_link = settings.should_hide_subscription_link()
|
||||||
|
|||||||
@@ -1276,8 +1276,8 @@
|
|||||||
"SUBSCRIPTION_APPS_PROMPT": "Choose an app to connect:",
|
"SUBSCRIPTION_APPS_PROMPT": "Choose an app to connect:",
|
||||||
"SUBSCRIPTION_APPS_TITLE": "📱 <b>Apps for {device_name}</b>",
|
"SUBSCRIPTION_APPS_TITLE": "📱 <b>Apps for {device_name}</b>",
|
||||||
"SUBSCRIPTION_APP_NOT_FOUND": "❌ App not found",
|
"SUBSCRIPTION_APP_NOT_FOUND": "❌ App not found",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER": "",
|
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER": "</blockquote>",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE": "📱 <b>Connected devices:</b>\n",
|
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE": "<blockquote>📱 <b>Connected devices:</b>\n",
|
||||||
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE": "🚀 <b>Connect subscription</b>\n\n📱 Tap the button below to open the app:",
|
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE": "🚀 <b>Connect subscription</b>\n\n📱 Tap the button below to open the app:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE": "📱 <b>Connect subscription</b>\n\n🔗 <b>Subscription link:</b>\n<code>{subscription_url}</code>\n\n💡 <b>Choose your device</b> to get detailed setup instructions:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE": "📱 <b>Connect subscription</b>\n\n🔗 <b>Subscription link:</b>\n<code>{subscription_url}</code>\n\n💡 <b>Choose your device</b> to get detailed setup instructions:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN": "📱 <b>Connect subscription</b>\n\nℹ️ The subscription link is available via the buttons below or in the “My subscription” section.\n\n💡 <b>Choose your device</b> to get detailed setup instructions:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN": "📱 <b>Connect subscription</b>\n\nℹ️ The subscription link is available via the buttons below or in the “My subscription” section.\n\n💡 <b>Choose your device</b> to get detailed setup instructions:",
|
||||||
|
|||||||
@@ -1288,8 +1288,8 @@
|
|||||||
"SUBSCRIPTION_APPS_PROMPT": "Выберите приложение для подключения:",
|
"SUBSCRIPTION_APPS_PROMPT": "Выберите приложение для подключения:",
|
||||||
"SUBSCRIPTION_APPS_TITLE": "📱 <b>Приложения для {device_name}</b>",
|
"SUBSCRIPTION_APPS_TITLE": "📱 <b>Приложения для {device_name}</b>",
|
||||||
"SUBSCRIPTION_APP_NOT_FOUND": "❌ Приложение не найдено",
|
"SUBSCRIPTION_APP_NOT_FOUND": "❌ Приложение не найдено",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER": "",
|
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER": "</blockquote>",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE": "📱 <b>Подключенные устройства:</b>\n",
|
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE": "<blockquote>📱 <b>Подключенные устройства:</b>\n",
|
||||||
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE": "🚀 <b>Подключить подписку</b>\n\n📱 Нажмите кнопку ниже, чтобы открыть приложение:",
|
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE": "🚀 <b>Подключить подписку</b>\n\n📱 Нажмите кнопку ниже, чтобы открыть приложение:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE": "📱 <b>Подключить подписку</b>\n\n🔗 <b>Ссылка подписки:</b>\n<code>{subscription_url}</code>\n\n💡 <b>Выберите ваше устройство</b> для получения подробной инструкции по настройке:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE": "📱 <b>Подключить подписку</b>\n\n🔗 <b>Ссылка подписки:</b>\n<code>{subscription_url}</code>\n\n💡 <b>Выберите ваше устройство</b> для получения подробной инструкции по настройке:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN": "📱 <b>Подключить подписку</b>\n\nℹ️ Ссылка подписки доступна по кнопкам ниже или в разделе «Моя подписка».\n\n💡 <b>Выберите ваше устройство</b> для получения подробной инструкции по настройке:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN": "📱 <b>Подключить подписку</b>\n\nℹ️ Ссылка подписки доступна по кнопкам ниже или в разделе «Моя подписка».\n\n💡 <b>Выберите ваше устройство</b> для получения подробной инструкции по настройке:",
|
||||||
|
|||||||
@@ -1280,8 +1280,8 @@
|
|||||||
"SUBSCRIPTION_APPS_PROMPT": "Оберіть додаток для підключення:",
|
"SUBSCRIPTION_APPS_PROMPT": "Оберіть додаток для підключення:",
|
||||||
"SUBSCRIPTION_APPS_TITLE": "📱 <b>Додатки для {device_name}</b>",
|
"SUBSCRIPTION_APPS_TITLE": "📱 <b>Додатки для {device_name}</b>",
|
||||||
"SUBSCRIPTION_APP_NOT_FOUND": "❌ Додаток не знайдено",
|
"SUBSCRIPTION_APP_NOT_FOUND": "❌ Додаток не знайдено",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER": "",
|
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER": "</blockquote>",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE": "📱 <b>Підключені пристрої:</b>\n",
|
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE": "<blockquote>📱 <b>Підключені пристрої:</b>\n",
|
||||||
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE": "🚀 <b>Підключити підписку</b>\n\n📱 Натисніть кнопку нижче, щоб відкрити додаток:",
|
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE": "🚀 <b>Підключити підписку</b>\n\n📱 Натисніть кнопку нижче, щоб відкрити додаток:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE": "📱 <b>Підключити підписку</b>\n\n🔗 <b>Посилання підписки:</b>\n<code>{subscription_url}</code>\n\n💡 <b>Оберіть ваш пристрій</b> для отримання детальної інструкції з налаштування:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE": "📱 <b>Підключити підписку</b>\n\n🔗 <b>Посилання підписки:</b>\n<code>{subscription_url}</code>\n\n💡 <b>Оберіть ваш пристрій</b> для отримання детальної інструкції з налаштування:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN": "📱 <b>Підключити підписку</b>\n\nℹ️ Посилання підписки доступне за кнопками нижче або в розділі «Моя підписка».\n\n💡 <b>Оберіть ваш пристрій</b> для отримання детальної інструкції з налаштування:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN": "📱 <b>Підключити підписку</b>\n\nℹ️ Посилання підписки доступне за кнопками нижче або в розділі «Моя підписка».\n\n💡 <b>Оберіть ваш пристрій</b> для отримання детальної інструкції з налаштування:",
|
||||||
|
|||||||
@@ -1279,8 +1279,8 @@
|
|||||||
"SUBSCRIPTION_APPS_PROMPT":"请选择要连接的应用程序:",
|
"SUBSCRIPTION_APPS_PROMPT":"请选择要连接的应用程序:",
|
||||||
"SUBSCRIPTION_APPS_TITLE":"📱<b>适用于{device_name}的应用程序</b>",
|
"SUBSCRIPTION_APPS_TITLE":"📱<b>适用于{device_name}的应用程序</b>",
|
||||||
"SUBSCRIPTION_APP_NOT_FOUND":"❌未找到应用程序",
|
"SUBSCRIPTION_APP_NOT_FOUND":"❌未找到应用程序",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER":"",
|
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER":"</blockquote>",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE":"📱<b>已连接设备:</b>\n",
|
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE":"<blockquote>📱<b>已连接设备:</b>\n",
|
||||||
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE":"🚀<b>连接订阅</b>\n\n📱点击下方按钮打开应用程序:",
|
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE":"🚀<b>连接订阅</b>\n\n📱点击下方按钮打开应用程序:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE":"📱<b>连接订阅</b>\n\n🔗<b>订阅链接:</b>\n<code>{subscription_url}</code>\n\n💡<b>请选择您的设备</b>以获取详细设置说明:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE":"📱<b>连接订阅</b>\n\n🔗<b>订阅链接:</b>\n<code>{subscription_url}</code>\n\n💡<b>请选择您的设备</b>以获取详细设置说明:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN":"📱<b>连接订阅</b>\n\nℹ️订阅链接在下方按钮中或“我的订阅”部分可用。\n\n💡<b>请选择您的设备</b>以获取详细设置说明:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN":"📱<b>连接订阅</b>\n\nℹ️订阅链接在下方按钮中或“我的订阅”部分可用。\n\n💡<b>请选择您的设备</b>以获取详细设置说明:",
|
||||||
@@ -1606,8 +1606,8 @@
|
|||||||
"SUBSCRIPTION_APPS_PROMPT":"请选择要连接的应用程序:",
|
"SUBSCRIPTION_APPS_PROMPT":"请选择要连接的应用程序:",
|
||||||
"SUBSCRIPTION_APPS_TITLE":"📱<b>适用于{device_name}的应用程序</b>",
|
"SUBSCRIPTION_APPS_TITLE":"📱<b>适用于{device_name}的应用程序</b>",
|
||||||
"SUBSCRIPTION_APP_NOT_FOUND":"❌未找到应用程序",
|
"SUBSCRIPTION_APP_NOT_FOUND":"❌未找到应用程序",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER":"",
|
"SUBSCRIPTION_CONNECTED_DEVICES_FOOTER":"</blockquote>",
|
||||||
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE":"📱<b>已连接设备:</b>\n",
|
"SUBSCRIPTION_CONNECTED_DEVICES_TITLE":"<blockquote>📱<b>已连接设备:</b>\n",
|
||||||
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE":"🚀<b>连接订阅</b>\n\n📱点击下方按钮打开应用程序:",
|
"SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE":"🚀<b>连接订阅</b>\n\n📱点击下方按钮打开应用程序:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE":"📱<b>连接订阅</b>\n\n🔗<b>订阅链接:</b>\n<code>{subscription_url}</code>\n\n💡<b>请选择您的设备</b>以获取详细设置说明:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE":"📱<b>连接订阅</b>\n\n🔗<b>订阅链接:</b>\n<code>{subscription_url}</code>\n\n💡<b>请选择您的设备</b>以获取详细设置说明:",
|
||||||
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN":"📱<b>连接订阅</b>\n\nℹ️订阅链接在下方按钮中或“我的订阅”部分可用。\n\n💡<b>请选择您的设备</b>以获取详细设置说明:",
|
"SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN":"📱<b>连接订阅</b>\n\nℹ️订阅链接在下方按钮中或“我的订阅”部分可用。\n\n💡<b>请选择您的设备</b>以获取详细设置说明:",
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import html
|
|
||||||
import re
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
@@ -65,14 +63,6 @@ def append_privacy_hint(text: str | None, language: str | None) -> str:
|
|||||||
return hint
|
return hint
|
||||||
|
|
||||||
|
|
||||||
def _strip_html(text: str | None) -> str:
|
|
||||||
if not text:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
plain_text = html.unescape(re.sub(r"<[^>]+>", "", text))
|
|
||||||
return plain_text.strip()
|
|
||||||
|
|
||||||
|
|
||||||
def prepare_privacy_safe_kwargs(kwargs: Dict[str, Any] | None = None) -> Dict[str, Any]:
|
def prepare_privacy_safe_kwargs(kwargs: Dict[str, Any] | None = None) -> Dict[str, Any]:
|
||||||
safe_kwargs: Dict[str, Any] = dict(kwargs or {})
|
safe_kwargs: Dict[str, Any] = dict(kwargs or {})
|
||||||
safe_kwargs.pop("reply_markup", None)
|
safe_kwargs.pop("reply_markup", None)
|
||||||
@@ -110,10 +100,7 @@ async def _answer_with_photo(self: Message, text: str = None, **kwargs):
|
|||||||
safe_kwargs = prepare_privacy_safe_kwargs(kwargs)
|
safe_kwargs = prepare_privacy_safe_kwargs(kwargs)
|
||||||
return await _original_answer(self, fallback_text, **safe_kwargs)
|
return await _original_answer(self, fallback_text, **safe_kwargs)
|
||||||
# Фоллбек, если Telegram ругается на caption или другое ограничение: отправим как текст
|
# Фоллбек, если Telegram ругается на caption или другое ограничение: отправим как текст
|
||||||
fallback_text = _strip_html(text)
|
return await _original_answer(self, text, **kwargs)
|
||||||
safe_kwargs = dict(kwargs)
|
|
||||||
safe_kwargs.pop("parse_mode", None)
|
|
||||||
return await _original_answer(self, fallback_text, **safe_kwargs)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return await _original_answer(self, text, **kwargs)
|
return await _original_answer(self, text, **kwargs)
|
||||||
return await _original_answer(self, text, **kwargs)
|
return await _original_answer(self, text, **kwargs)
|
||||||
@@ -166,10 +153,7 @@ async def _edit_with_photo(self: Message, text: str, **kwargs):
|
|||||||
await self.delete()
|
await self.delete()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
fallback_text = _strip_html(text)
|
return await _original_answer(self, text, **kwargs)
|
||||||
safe_kwargs = dict(kwargs)
|
|
||||||
safe_kwargs.pop("parse_mode", None)
|
|
||||||
return await _original_answer(self, fallback_text, **safe_kwargs)
|
|
||||||
return await _original_edit_text(self, text, **kwargs)
|
return await _original_edit_text(self, text, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@@ -178,3 +162,4 @@ def patch_message_methods():
|
|||||||
return
|
return
|
||||||
Message.answer = _answer_with_photo
|
Message.answer = _answer_with_photo
|
||||||
Message.edit_text = _edit_with_photo
|
Message.edit_text = _edit_with_photo
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
import html
|
|
||||||
import re
|
|
||||||
|
|
||||||
from aiogram import types
|
from aiogram import types
|
||||||
from aiogram.exceptions import TelegramBadRequest
|
from aiogram.exceptions import TelegramBadRequest
|
||||||
from aiogram.types import FSInputFile, InputMediaPhoto
|
from aiogram.types import FSInputFile, InputMediaPhoto
|
||||||
@@ -36,14 +33,6 @@ def _get_language(callback: types.CallbackQuery) -> str | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _strip_html(text: str | None) -> str:
|
|
||||||
if not text:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
plain_text = html.unescape(re.sub(r"<[^>]+>", "", text))
|
|
||||||
return plain_text.strip()
|
|
||||||
|
|
||||||
|
|
||||||
def _build_base_kwargs(keyboard: types.InlineKeyboardMarkup | None, parse_mode: str | None):
|
def _build_base_kwargs(keyboard: types.InlineKeyboardMarkup | None, parse_mode: str | None):
|
||||||
kwargs: dict[str, object] = {}
|
kwargs: dict[str, object] = {}
|
||||||
if parse_mode is not None:
|
if parse_mode is not None:
|
||||||
@@ -68,19 +57,6 @@ async def _answer_text(
|
|||||||
kwargs = prepare_privacy_safe_kwargs(kwargs)
|
kwargs = prepare_privacy_safe_kwargs(kwargs)
|
||||||
|
|
||||||
kwargs.setdefault("parse_mode", parse_mode or "HTML")
|
kwargs.setdefault("parse_mode", parse_mode or "HTML")
|
||||||
try:
|
|
||||||
await callback.message.answer(
|
|
||||||
caption,
|
|
||||||
**kwargs,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
except TelegramBadRequest as send_error:
|
|
||||||
if is_privacy_restricted_error(send_error):
|
|
||||||
caption = append_privacy_hint(caption, language)
|
|
||||||
kwargs = prepare_privacy_safe_kwargs(kwargs)
|
|
||||||
else:
|
|
||||||
caption = _strip_html(caption)
|
|
||||||
kwargs.pop("parse_mode", None)
|
|
||||||
|
|
||||||
await callback.message.answer(
|
await callback.message.answer(
|
||||||
caption,
|
caption,
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ from datetime import datetime
|
|||||||
import html
|
import html
|
||||||
|
|
||||||
ALLOWED_HTML_TAGS = {
|
ALLOWED_HTML_TAGS = {
|
||||||
'b', 'strong',
|
'b', 'strong',
|
||||||
'i', 'em',
|
'i', 'em',
|
||||||
'u', 'ins',
|
'u', 'ins',
|
||||||
's', 'strike', 'del',
|
's', 'strike', 'del',
|
||||||
'code',
|
'code',
|
||||||
'pre',
|
'pre',
|
||||||
'a'
|
'a',
|
||||||
|
'blockquote'
|
||||||
}
|
}
|
||||||
|
|
||||||
SELF_CLOSING_TAGS = {
|
SELF_CLOSING_TAGS = {
|
||||||
@@ -145,24 +146,6 @@ def sanitize_html(text: str) -> str:
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
def strip_blockquote_tags(text: str) -> str:
|
|
||||||
"""Remove Telegram-unsupported blockquote tags (both raw and escaped)."""
|
|
||||||
if not text:
|
|
||||||
return text
|
|
||||||
|
|
||||||
without_tags = re.sub(r"</?blockquote>\s*", "", text, flags=re.IGNORECASE)
|
|
||||||
without_escaped = re.sub(r"</?blockquote[^&]*>\s*", "", without_tags, flags=re.IGNORECASE)
|
|
||||||
return without_escaped
|
|
||||||
|
|
||||||
|
|
||||||
def format_telegram_quote(text: str | None) -> str:
|
|
||||||
"""Format text as a lightweight quote safe for Telegram HTML parse mode."""
|
|
||||||
clean_text = strip_blockquote_tags(text or "").strip()
|
|
||||||
if not clean_text:
|
|
||||||
return "—"
|
|
||||||
return f"<i>❝ {clean_text} ❞</i>"
|
|
||||||
|
|
||||||
|
|
||||||
def sanitize_telegram_name(name: Optional[str]) -> Optional[str]:
|
def sanitize_telegram_name(name: Optional[str]) -> Optional[str]:
|
||||||
"""Санитизация Telegram-имени для безопасной вставки в HTML и хранения.
|
"""Санитизация Telegram-имени для безопасной вставки в HTML и хранения.
|
||||||
Заменяет угловые скобки и амперсанд на безопасные визуальные аналоги.
|
Заменяет угловые скобки и амперсанд на безопасные визуальные аналоги.
|
||||||
|
|||||||
Reference in New Issue
Block a user