Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/bot/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ def format_hours_display(hours: int) -> str:
# Captcha verification message templates
CAPTCHA_WELCOME_MESSAGE = (
"👋 Selamat datang {user_mention}!\n\n"
"Untuk memastikan kamu bukan robot, silakan klik tombol di bawah ini "
"dalam waktu {timeout} detik."
"Sebelum bergabung, pastikan kamu sudah memiliki *foto profil publik* dan *username*.\n"
"Setelah melengkapi profil, tekan tombol di bawah ini dalam waktu {timeout} detik."
)

CAPTCHA_VERIFIED_MESSAGE = "✅ Terima kasih {user_mention}, verifikasi berhasil! Selamat bergabung."
Expand All @@ -121,6 +121,10 @@ def format_hours_display(hours: int) -> str:
"Silakan cek grup dan tekan tombol verifikasi."
)

CAPTCHA_INCOMPLETE_PROFILE_MESSAGE = (
"❌ Lengkapi {missing_text} terlebih dahulu, lalu tekan tombol ini lagi."
)

CAPTCHA_FAILED_VERIFICATION_MESSAGE = "Gagal memverifikasi. Silakan coba lagi."

# DM handler message templates
Expand Down
52 changes: 38 additions & 14 deletions src/bot/handlers/captcha.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@

from bot.constants import (
CAPTCHA_FAILED_VERIFICATION_MESSAGE,
CAPTCHA_INCOMPLETE_PROFILE_MESSAGE,
CAPTCHA_VERIFIED_MESSAGE,
CAPTCHA_WELCOME_MESSAGE,
CAPTCHA_WRONG_USER_MESSAGE,
MISSING_ITEMS_SEPARATOR,
RESTRICTED_PERMISSIONS,
)
from bot.database.service import get_database
from bot.group_config import GroupConfig, get_group_config_for_update, get_group_registry
from bot.services.telegram_utils import get_user_mention, unrestrict_user
from bot.services.user_checker import check_user_profile

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -262,18 +265,20 @@ async def captcha_callback_handler(
if not query or not query.data:
return

await query.answer()

callback_user_id = query.from_user.id
parts = query.data.split("_")
target_user_id = int(parts[-1])
group_id = int(parts[-2])
try:
target_user_id = int(parts[-1])
group_id = int(parts[-2])
except (ValueError, IndexError):
logger.warning(f"Malformed captcha callback data: {query.data}")
await query.answer(CAPTCHA_FAILED_VERIFICATION_MESSAGE, show_alert=True)
return

if callback_user_id != target_user_id:
await query.answer(CAPTCHA_WRONG_USER_MESSAGE, show_alert=True)
return

# Look up group config directly using group_id from callback data
db = get_database()
registry = get_group_registry()

Expand All @@ -284,27 +289,46 @@ async def captcha_callback_handler(
await query.answer(CAPTCHA_FAILED_VERIFICATION_MESSAGE, show_alert=True)
return

job_name = get_captcha_job_name(group_config.group_id, target_user_id)
current_jobs = context.job_queue.get_jobs_by_name(job_name)
for job in current_jobs:
job.schedule_removal()
logger.info(f"Cancelled timeout job for user {target_user_id}")
try:
result = await check_user_profile(context.bot, query.from_user)
except Exception:
logger.error(f"Profile check failed during captcha for user {target_user_id}", exc_info=True)
await query.answer(CAPTCHA_FAILED_VERIFICATION_MESSAGE, show_alert=True)
return

if not result.is_complete:
missing_text = MISSING_ITEMS_SEPARATOR.join(result.get_missing_items())
await query.answer(
CAPTCHA_INCOMPLETE_PROFILE_MESSAGE.format(missing_text=missing_text),
show_alert=True,
)
return

try:
await unrestrict_user(context.bot, group_config.group_id, target_user_id)
logger.info(f"Unrestricted verified user {target_user_id}")
except Exception as e:
logger.error(f"Failed to unrestrict user {target_user_id}: {e}")
await query.answer(CAPTCHA_FAILED_VERIFICATION_MESSAGE, show_alert=True)
return # Stop execution here so user can retry
return

db.remove_pending_captcha(target_user_id, group_config.group_id)
try:
db.remove_pending_captcha(target_user_id, group_config.group_id)
db.start_new_user_probation(target_user_id, group_config.group_id)
except Exception:
logger.error(f"DB finalization failed for user {target_user_id}", exc_info=True)
await query.answer(CAPTCHA_FAILED_VERIFICATION_MESSAGE, show_alert=True)
return

# Start anti-spam probation for verified user
db.start_new_user_probation(target_user_id, group_config.group_id)
job_name = get_captcha_job_name(group_config.group_id, target_user_id)
for job in context.job_queue.get_jobs_by_name(job_name):
job.schedule_removal()
logger.info(f"Cancelled timeout job for user {target_user_id}")

user_mention = get_user_mention(query.from_user)

await query.answer()

try:
await query.edit_message_text(
text=CAPTCHA_VERIFIED_MESSAGE.format(user_mention=user_mention),
Expand Down
Loading
Loading