Skip to content

✨ feat: add multi-group support#1

Merged
rezhajulio merged 11 commits intomainfrom
multi-groups-clean
Feb 21, 2026
Merged

✨ feat: add multi-group support#1
rezhajulio merged 11 commits intomainfrom
multi-groups-clean

Conversation

@rezhajulio
Copy link
Owner

@rezhajulio rezhajulio commented Feb 21, 2026

Summary

Add multi-group support so a single bot instance can manage multiple Telegram groups.

This work builds upon the multi-group foundation from jvmdeveloperid/PythonID-bot by Hendy Santika (@hendisantika).

Multi-group infrastructure

  • GroupConfig (Pydantic model) and GroupRegistry for per-group configuration
  • groups.json file support with automatic fallback to .env for single-group backward compatibility
  • Per-group settings: warning topic, restriction, captcha, thresholds, rules link

Handler refactoring

  • All 7 handlers refactored to use get_group_config_for_update() instead of settings.group_id
  • Scheduler and captcha recovery iterate per-group with per-group thresholds
  • Admin IDs fetched per-group with union set for DM-based commands

Robustness fixes

  • Encode group_id in captcha callback data to deterministically resolve the correct group instead of scanning all groups
  • Wrap scheduler per-group warning query in try/except so one failing group does not abort the entire auto-restriction job
  • Removed RuntimeError in DM handler that could disrupt bot operation
  • Added per-group exception isolation in DM membership scan and verify flow
  • Made get_group_config_for_update() resilient to uninitialized registry
  • Fixed Pydantic Settings rejecting extra env vars (e.g. OTEL_PYTHON_DISABLED_INSTRUMENTATIONS)

Backward compatible

No groups.json? Bot works exactly as before using .env values.

Tests

All 442 tests pass, 99% coverage.

hendisantika and others added 10 commits February 21, 2026 09:30
…astructure

Introduces the foundation for multi-group support:
- GroupConfig (Pydantic BaseModel) with per-group settings
- GroupRegistry for O(1) group lookup
- JSON file loading and backward-compatible fallback from .env
- get_group_config_for_update() helper for handlers
- Module-level singleton with init/get/reset
Adds configurable path for groups.json file (defaults to "groups.json").
Existing .env fields kept for backward compatibility when no groups.json exists.
…rvice

Per-group variant that filters by group_id AND uses group-specific
threshold, enabling different auto-restriction timing per group.
Universal pattern change across all group-facing handlers:
- topic_guard: uses get_group_config_for_update for guard check
- anti_spam: per-group probation thresholds and violation tracking
- message: per-group warning/restriction with group-specific settings
- captcha: accepts GroupConfig, looks up group from registry on callback
- verify: iterates all groups for unrestrict/delete-warnings
- check: sends warnings to all monitored groups
- dm: iterates all groups for membership check and cross-group unrestriction
- Scheduler iterates per-group with group-specific thresholds
- Captcha recovery uses per-group timeout from GroupConfig
- Skips captchas for groups no longer in registry
- Initialize group registry from settings (groups.json or .env fallback)
- Fetch admin IDs per-group and store union for DM commands
- Captcha recovery checks all groups with captcha enabled
- Log per-group config summary at startup
- groups.json.example with sample multi-group configuration
- .env.example documents GROUPS_CONFIG_PATH option
- .gitignore excludes groups.json (contains group IDs)
🔄 Replace get_settings() patches with get_group_config_for_update() and
get_group_registry() patches across all test files.
🆕 Add test_group_config.py for GroupConfig, GroupRegistry, JSON loading,
and singleton management.
🎯 All 440 tests pass.
OTEL_PYTHON_DISABLED_INSTRUMENTATIONS from .env was rejected by Pydantic
Settings as an unknown field. Added extra="ignore" to SettingsConfigDict.
- Remove RuntimeError in dm.py when all unrestriction attempts fail,
  replace with error log and friendly user message
- Add try/except around get_user_status() in dm.py membership scan so
  one inaccessible group doesn't abort the entire DM handler
- Add per-group try/except in verify_user() so a failure in one group
  doesn't prevent verification in other groups
- Make get_group_config_for_update() resilient to uninitialized registry
  by catching RuntimeError and returning None
- Fix ruff lint: remove unused imports and variables
…tion

- Encode group_id in captcha callback data (captcha_verify_{group_id}_{user_id})
  to deterministically resolve the correct group instead of scanning all groups
- Wrap scheduler per-group warning query in try/except so one failing group
  does not abort the entire auto-restriction job
@rezhajulio rezhajulio force-pushed the multi-groups-clean branch 2 times, most recently from fc42ceb to 747f818 Compare February 21, 2026 10:08
@rezhajulio rezhajulio merged commit 311543b into main Feb 21, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants