Skip to content

Commit 78f48f3

Browse files
committed
Add user mention helpers and expand telegram utilities
- Add get_user_mention() to generate formatted mentions (@username or markdown link) - Add get_user_mention_by_id() for markdown mentions with just ID and name - Update handlers (captcha, message, verify) to use new mention utilities - Add comprehensive tests for mention generation functions (16 new test cases) - Update README with current test coverage statistics (224 tests, 100% coverage, 702 statements)
1 parent 1f2841c commit 78f48f3

8 files changed

Lines changed: 258 additions & 28 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ uv run pytest -v
135135
### Test Coverage
136136

137137
The project maintains comprehensive test coverage:
138-
- **Coverage**: 100% across all modules (700 statements, 0 missed)
139-
- **Tests**: 208 total
140-
- **Pass Rate**: 100% (208/208 passed)
138+
- **Coverage**: 100% across all modules (702 statements, 0 missed)
139+
- **Tests**: 224 total
140+
- **Pass Rate**: 100% (224/224 passed)
141141
- **All modules**: 100% coverage including JobQueue scheduler integration and captcha verification
142142
- Services: `bot_info.py`, `scheduler.py`, `user_checker.py`, `telegram_utils.py`, `captcha_recovery.py`
143143
- Handlers: `captcha.py`, `dm.py`, `message.py`, `topic_guard.py`, `verify.py`

src/bot/handlers/captcha.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
MessageHandler,
1919
filters,
2020
)
21-
from telegram.helpers import mention_markdown
2221

2322
from bot.config import Settings, get_settings
2423
from bot.constants import (
@@ -29,7 +28,7 @@
2928
RESTRICTED_PERMISSIONS,
3029
)
3130
from bot.database.service import get_database
32-
from bot.services.telegram_utils import unrestrict_user
31+
from bot.services.telegram_utils import get_user_mention, unrestrict_user
3332

3433
logger = logging.getLogger(__name__)
3534

@@ -66,7 +65,7 @@ async def _initiate_captcha_challenge(
6665
settings: Bot settings.
6766
"""
6867
user_id = user.id
69-
user_mention = mention_markdown(user_id, user.full_name, version=2)
68+
user_mention = get_user_mention(user)
7069

7170
try:
7271
await context.bot.restrict_chat_member(
@@ -283,7 +282,7 @@ async def captcha_callback_handler(
283282
db = get_database()
284283
db.remove_pending_captcha(target_user_id, settings.group_id)
285284

286-
user_mention = mention_markdown(target_user_id, query.from_user.full_name, version=2)
285+
user_mention = get_user_mention(query.from_user)
287286

288287
try:
289288
await query.edit_message_text(

src/bot/handlers/message.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from telegram import Update
1313
from telegram.ext import ContextTypes
14-
from telegram.helpers import mention_markdown
14+
1515

1616
from bot.config import get_settings
1717
from bot.constants import (
@@ -24,6 +24,7 @@
2424
)
2525
from bot.database.service import get_database
2626
from bot.services.bot_info import BotInfoCache
27+
from bot.services.telegram_utils import get_user_mention
2728
from bot.services.user_checker import check_user_profile
2829

2930
logger = logging.getLogger(__name__)
@@ -69,11 +70,7 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
6970
# Build warning message components
7071
missing = result.get_missing_items()
7172
missing_text = MISSING_ITEMS_SEPARATOR.join(missing)
72-
user_mention = (
73-
f"@{user.username}"
74-
if user.username
75-
else mention_markdown(user.id, user.full_name, version=2)
76-
)
73+
user_mention = get_user_mention(user)
7774

7875
# Warning mode: just send warning, don't restrict
7976
if not settings.restrict_failed_users:

src/bot/handlers/verify.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@
1111
from telegram import Update
1212
from telegram.error import BadRequest
1313
from telegram.ext import ContextTypes
14-
from telegram.helpers import mention_markdown
1514

1615
from bot.config import get_settings
1716
from bot.constants import VERIFICATION_CLEARANCE_MESSAGE
1817
from bot.database.service import get_database
19-
from bot.services.telegram_utils import unrestrict_user
18+
from bot.services.telegram_utils import get_user_mention_by_id, unrestrict_user
2019

2120
logger = logging.getLogger(__name__)
2221

@@ -92,7 +91,7 @@ async def handle_verify_command(
9291
if deleted_count > 0:
9392
# Get user info for proper mention
9493
user_info = await context.bot.get_chat(target_user_id)
95-
user_mention = mention_markdown(target_user_id, user_info.full_name, version=2)
94+
user_mention = get_user_mention_by_id(target_user_id, user_info.full_name)
9695

9796
# Send clearance message to warning topic
9897
clearance_message = VERIFICATION_CLEARANCE_MESSAGE.format(

src/bot/services/captcha_recovery.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111

1212
from telegram import Bot
1313
from telegram.ext import Application
14-
from telegram.helpers import mention_markdown
1514

1615
from bot.config import get_settings
1716
from bot.constants import CAPTCHA_TIMEOUT_MESSAGE
1817
from bot.database.service import get_database
1918
from bot.handlers.captcha import captcha_timeout_callback, get_captcha_job_name
2019
from bot.services.bot_info import BotInfoCache
20+
from bot.services.telegram_utils import get_user_mention_by_id
2121

2222
logger = logging.getLogger(__name__)
2323

@@ -60,7 +60,7 @@ async def handle_captcha_expiration(
6060

6161
bot_username = await BotInfoCache.get_username(bot)
6262
dm_link = f"[hubungi robot](https://t.me/{bot_username})"
63-
user_mention = mention_markdown(user_id, user_full_name, version=2)
63+
user_mention = get_user_mention_by_id(user_id, user_full_name)
6464

6565
try:
6666
await bot.edit_message_text(

src/bot/services/scheduler.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from telegram.constants import ChatMemberStatus
1111
from telegram.ext import ContextTypes
12-
from telegram.helpers import mention_markdown
12+
1313

1414
from bot.config import get_settings
1515
from bot.constants import (
@@ -19,7 +19,7 @@
1919
)
2020
from bot.database.service import get_database
2121
from bot.services.bot_info import BotInfoCache
22-
from bot.services.telegram_utils import get_user_status
22+
from bot.services.telegram_utils import get_user_mention, get_user_status
2323

2424
logger = logging.getLogger(__name__)
2525

@@ -81,11 +81,7 @@ async def auto_restrict_expired_warnings(context: ContextTypes.DEFAULT_TYPE) ->
8181
user_id=warning.user_id,
8282
)
8383
user = user_member.user
84-
user_mention = (
85-
f"@{user.username}"
86-
if user.username
87-
else mention_markdown(user.id, user.full_name, version=2)
88-
)
84+
user_mention = get_user_mention(user)
8985
except Exception:
9086
# Fallback to user ID if we can't get user info
9187
user_mention = f"User {warning.user_id}"

src/bot/services/telegram_utils.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,46 @@
55
Telegram's API across different handlers and services.
66
"""
77

8-
from telegram import Bot
8+
from telegram import Bot, User
99
from telegram.constants import ChatMemberStatus
1010
from telegram.error import BadRequest, Forbidden
11+
from telegram.helpers import mention_markdown
12+
13+
14+
def get_user_mention(user: User) -> str:
15+
"""
16+
Get a formatted mention string for a user.
17+
18+
Returns `@username` if the user has a username, otherwise returns
19+
a markdown mention using the user's full name and ID.
20+
21+
Args:
22+
user: Telegram User object.
23+
24+
Returns:
25+
str: Formatted user mention (either @username or markdown mention).
26+
"""
27+
return (
28+
f"@{user.username}"
29+
if user.username
30+
else mention_markdown(user.id, user.full_name, version=2)
31+
)
32+
33+
34+
def get_user_mention_by_id(user_id: int, user_full_name: str) -> str:
35+
"""
36+
Get a formatted markdown mention for a user by ID and name.
37+
38+
Used when only user ID and full name are available (not a full User object).
39+
40+
Args:
41+
user_id: Telegram user ID.
42+
user_full_name: User's full name.
43+
44+
Returns:
45+
str: Markdown mention string.
46+
"""
47+
return mention_markdown(user_id, user_full_name, version=2)
1148

1249

1350
async def get_user_status(

0 commit comments

Comments
 (0)