You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Indonesian Telegram bot for multi-group profile enforcement (photo + username), captcha verification, and anti-spam protection. Built with python-telegram-bot v20+, SQLModel, Pydantic, and Logfire.
Commands
# Install dependencies
uv sync
# Run tests (100% coverage maintained)
uv run pytest
# Run single test file
uv run pytest tests/test_check.py
# Run single test function
uv run pytest tests/test_check.py::TestHandleCheckCommand::test_check_command_non_admin
# Run with coverage
uv run pytest --cov=bot --cov-report=term-missing
# Run linter
uv run ruff check .# Run the bot
uv run pythonid-bot
# Run staging
BOT_ENV=staging uv run pythonid-bot
Handles both message and edited_message updates (combined filter)
Raises ApplicationHandlerStop after handling ANY warning-topic message (allows or deletes)
This prevents downstream spam/profile handlers from processing warning-topic traffic
Fail-closed: On get_chat_member API error, deletes the message (scoped to confirmed warning-topic only)
Early returns (no message, wrong group, wrong topic) happen OUTSIDE the try/except block
Singletons
get_settings() — Pydantic settings, @lru_cache
get_database() — DatabaseService, lazy init
BotInfoCache — Class-level cache for bot username/ID
Admin Cache
Fetched at startup in post_init() and stored in bot_data["group_admin_ids"] (per-group) and bot_data["admin_ids"] (union)
Refreshed every 10 minutes via refresh_admin_ids JobQueue job
On refresh failure for a group, falls back to existing cached data (not empty list)
Spam handlers use cached admin IDs; topic_guard uses live get_chat_member API call
Multi-Group Support
GroupConfig — Pydantic model for per-group settings (warning thresholds, captcha, probation)
GroupRegistry — O(1) lookup by group_id, manages all monitored groups
groups.json — Per-group config file; falls back to .env for single-group mode
get_group_config_for_update() — Helper to resolve config for incoming Telegram updates
Exception-isolated loops — Per-group API calls wrapped in try/except to prevent cross-group failures
State Machine (Progressive Restriction)
1st violation → Warning with threshold info
2nd to (N-1) → Silent increment (no spam)
Nth violation → Restrict + notification
Time threshold → Auto-restrict via scheduler (parallel path)