diff --git a/src/bot/constants.py b/src/bot/constants.py index d543f4c..a10d641 100644 --- a/src/bot/constants.py +++ b/src/bot/constants.py @@ -87,7 +87,8 @@ def format_hours_display(hours: int) -> str: "🚫 {user_mention} telah dibatasi setelah {message_count} pesan.\n" "Mohon lengkapi {missing_text} kamu untuk mematuhi aturan grup.\n\n" "📖 [Baca aturan grup]({rules_link})\n" - "✉️ [Hubungi langsung robot untuk membuka pembatasan (mohon pertimbangkan bahwa percakapan dengan robot saat ini sebagian besar belum direkam)]({dm_link})" + "✉️ [Hubungi langsung robot untuk membuka pembatasan]({dm_link}) " + "(mohon pertimbangkan bahwa percakapan dengan robot saat ini sebagian besar belum direkam)" ) # Restriction message when user reaches time threshold (scheduler) @@ -95,7 +96,8 @@ def format_hours_display(hours: int) -> str: "🚫 {user_mention} telah dibatasi karena tidak melengkapi profil " "dalam {threshold_display}.\n\n" "📖 [Baca aturan grup]({rules_link})\n" - "✉️ [Hubungi langsung robot untuk membuka pembatasan (mohon pertimbangkan bahwa percakapan dengan robot saat ini sebagian besar belum direkam)]({dm_link})" + "✉️ [Hubungi langsung robot untuk membuka pembatasan]({dm_link}) " + "(mohon pertimbangkan bahwa percakapan dengan robot saat ini sebagian besar belum direkam)" ) # Captcha verification message templates diff --git a/src/bot/services/telegram_utils.py b/src/bot/services/telegram_utils.py index 823e8ec..fa5334e 100644 --- a/src/bot/services/telegram_utils.py +++ b/src/bot/services/telegram_utils.py @@ -10,7 +10,7 @@ from telegram import Bot, Chat, Message, User from telegram.constants import ChatMemberStatus from telegram.error import BadRequest, Forbidden -from telegram.helpers import mention_markdown +from telegram.helpers import escape_markdown, mention_markdown logger = logging.getLogger(__name__) @@ -28,11 +28,10 @@ def get_user_mention(user: User | Chat) -> str: Returns: str: Formatted user mention (either @username or markdown mention). """ - return ( - f"@{user.username.lstrip('@')}" - if user.username - else mention_markdown(user.id, user.full_name, version=1) - ) + if user.username: + escaped = escape_markdown(user.username.lstrip("@"), version=1) + return f"@{escaped}" + return mention_markdown(user.id, user.full_name, version=1) def get_user_mention_by_id( @@ -54,7 +53,8 @@ def get_user_mention_by_id( str: Formatted mention string. """ if username: - return f"@{username.lstrip('@')}" + escaped = escape_markdown(username.lstrip("@"), version=1) + return f"@{escaped}" return mention_markdown(user_id, user_full_name, version=1) diff --git a/tests/test_captcha.py b/tests/test_captcha.py index d475201..f537b7a 100644 --- a/tests/test_captcha.py +++ b/tests/test_captcha.py @@ -647,6 +647,7 @@ def create_chat_member_update(self, old_status, new_status, user_id=12345, group new_member.user.id = user_id new_member.user.is_bot = False new_member.user.full_name = "Test User" + new_member.user.username = "testuser" update.chat_member.new_chat_member = new_member update.effective_chat = MagicMock() diff --git a/tests/test_check.py b/tests/test_check.py index d19fbff..1e3bf5c 100644 --- a/tests/test_check.py +++ b/tests/test_check.py @@ -413,6 +413,7 @@ async def test_warn_callback_success( mock_chat = MagicMock() mock_chat.full_name = "Test User" + mock_chat.username = "testuser" mock_context.bot.get_chat.return_value = mock_chat with ( diff --git a/tests/test_telegram_utils.py b/tests/test_telegram_utils.py index 6b52ab8..dfe0ea0 100644 --- a/tests/test_telegram_utils.py +++ b/tests/test_telegram_utils.py @@ -67,7 +67,7 @@ def test_get_user_mention_special_characters_in_username(self): result = get_user_mention(user) - assert result == "@user_name_123" + assert result == r"@user\_name\_123" @patch("bot.services.telegram_utils.mention_markdown") def test_get_user_mention_special_characters_in_full_name(self, mock_mention_markdown): @@ -106,7 +106,7 @@ def test_get_user_mention_with_prefixed_username(self): result = get_user_mention(user) - assert result == "@already_prefixed" + assert result == r"@already\_prefixed" def test_get_user_mention_chat_with_username(self): """Test getting mention for Chat object with username.""" @@ -117,7 +117,7 @@ def test_get_user_mention_chat_with_username(self): result = get_user_mention(chat) - assert result == "@john_doe" + assert result == r"@john\_doe" def test_get_user_mention_chat_with_prefixed_username(self): """Test that Chat with @ prefixed username is normalized.""" @@ -128,7 +128,7 @@ def test_get_user_mention_chat_with_prefixed_username(self): result = get_user_mention(chat) - assert result == "@prefixed_chat" + assert result == r"@prefixed\_chat" @patch("bot.services.telegram_utils.mention_markdown") def test_get_user_mention_chat_without_username(self, mock_mention_markdown): @@ -231,7 +231,7 @@ def test_get_user_mention_by_id_with_username_special_chars(self): """Test mention by ID with username containing underscores.""" result = get_user_mention_by_id(123456, "John Doe", username="john_doe_123") - assert result == "@john_doe_123" + assert result == r"@john\_doe\_123" def test_get_user_mention_by_id_with_prefixed_username(self): """Test that username with @ prefix is normalized.""" diff --git a/tests/test_verify_handler.py b/tests/test_verify_handler.py index 3dd493c..480b0e5 100644 --- a/tests/test_verify_handler.py +++ b/tests/test_verify_handler.py @@ -308,7 +308,7 @@ async def test_verify_sends_clearance_message_when_warnings_deleted( call_kwargs = mock_context.bot.send_message.call_args.kwargs assert call_kwargs["chat_id"] == gc.group_id assert call_kwargs["message_thread_id"] == gc.warning_topic_id - assert "@verified_user" in call_kwargs["text"] + assert r"@verified\_user" in call_kwargs["text"] assert call_kwargs["parse_mode"] == "Markdown" async def test_verify_handles_non_restricted_user_gracefully(