@@ -69,6 +69,65 @@ async def _handle_force_group_registration(
6969 await message .reply_text (strings .GROUP_REGISTERED .format (chat_id = chat .id ))
7070
7171
72+ async def _handle_multi_ban (
73+ update : Update ,
74+ context : ContextTypes .DEFAULT_TYPE ,
75+ moderation_service : ModerationService ,
76+ message ,
77+ chat ,
78+ multi_match : re .Match [str ],
79+ raw_text : str ,
80+ ) -> None :
81+ """Ban multiple users by ID. Usage: /ban [id1, id2, id3] [reason]."""
82+ inner = multi_match .group (1 )
83+ parts = [p .strip () for p in inner .split ("," ) if p .strip ()]
84+
85+ # Validate all parts are numeric IDs
86+ if not parts or not all (re .match (r"^-?\d+$" , p ) for p in parts ):
87+ await message .reply_text (strings .BAN_USAGE )
88+ return
89+
90+ user_ids = list (dict .fromkeys (int (p ) for p in parts )) # deduplicate, preserve order
91+
92+ # Extract reason from text after the closing bracket
93+ after_bracket = raw_text [multi_match .end () :].strip ()
94+ reason = after_bracket if after_bracket else None
95+
96+ # Fetch chat list once (same for all users)
97+ chat_ids : list [int ] | None = None
98+ total_success = 0
99+ total_fail = 0
100+
101+ for user_id in user_ids :
102+ ban_chat_ids = await moderation_service .add_global_ban (
103+ user_id , message .from_user .id , reason
104+ )
105+ if chat_ids is None :
106+ chat_ids = ban_chat_ids
107+
108+ for cid in ban_chat_ids :
109+ try :
110+ await context .bot .ban_chat_member (cid , user_id )
111+ total_success += 1
112+ except Exception as e :
113+ logger .debug ("Ban user %s in chat %s failed: %s" , user_id , cid , e )
114+ total_fail += 1
115+
116+ await message .reply_text (
117+ strings .ban_multi_success (len (user_ids ), total_success , total_fail , reason )
118+ )
119+
120+ # Notify admins of the multi-ban
121+ await _notify_admins_of_multi_ban (
122+ context = context ,
123+ chat = chat ,
124+ admin = message .from_user ,
125+ banned_ids = user_ids ,
126+ success_count = total_success ,
127+ reason = reason ,
128+ )
129+
130+
72131async def _handle_ban (update : Update , context : ContextTypes .DEFAULT_TYPE ) -> None :
73132 """Ban a user globally. Usage: /ban user_id|@username [reason] or reply with /ban [reason]."""
74133 moderation_service : ModerationService = context .bot_data ["moderation_service" ]
@@ -84,7 +143,17 @@ async def _handle_ban(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
84143 await message .reply_text (strings .ONLY_ADMINS )
85144 return
86145
87- args = message .text .split (maxsplit = 2 )[1 :] if message .text else []
146+ raw_text = message .text or ""
147+
148+ # Multi-ban: /ban [id1, id2, id3] [reason]
149+ multi_match = re .search (r"\[([^\]]+)\]" , raw_text )
150+ if multi_match :
151+ await _handle_multi_ban (
152+ update , context , moderation_service , message , chat , multi_match , raw_text
153+ )
154+ return
155+
156+ args = raw_text .split (maxsplit = 2 )[1 :]
88157
89158 user_id : int | None = None
90159 reason : str | None = None
@@ -565,6 +634,52 @@ async def _notify_admins_of_ban(
565634 )
566635
567636
637+ async def _notify_admins_of_multi_ban (
638+ context : ContextTypes .DEFAULT_TYPE ,
639+ chat ,
640+ admin ,
641+ banned_ids : list [int ],
642+ success_count : int ,
643+ reason : str | None ,
644+ ) -> None :
645+ """Send multi-ban notification to all chat admins via private message."""
646+ try :
647+ chat_admins = await context .bot .get_chat_administrators (chat .id )
648+ except Exception as e :
649+ logger .warning ("Failed to get admins for multi-ban notification: %s" , e )
650+ return
651+
652+ chat_title = chat .title or "Chat"
653+ admin_name = _get_user_display_name (admin )
654+
655+ notification = strings .ban_multi_notification (
656+ chat_title = chat_title ,
657+ banned_ids = banned_ids ,
658+ admin_name = admin_name ,
659+ admin_id = admin .id ,
660+ success_count = success_count ,
661+ reason = reason ,
662+ )
663+
664+ for member in chat_admins :
665+ if member .user .is_bot :
666+ continue
667+ if member .user .id == admin .id :
668+ continue
669+ try :
670+ await context .bot .send_message (
671+ chat_id = member .user .id ,
672+ text = notification ,
673+ parse_mode = "HTML" ,
674+ )
675+ except Exception as e :
676+ logger .debug (
677+ "Could not send multi-ban notification to admin %s: %s" ,
678+ member .user .id ,
679+ e ,
680+ )
681+
682+
568683async def _resolve_user_id (
569684 context : ContextTypes .DEFAULT_TYPE ,
570685 chat_id : int ,
0 commit comments