Handle supergroup joins via chat_member updates
Send verification challenges when Telegram hides join service messages, and subscribe to chat_member polling updates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
1aa6aa006c
commit
e84f748889
2 changed files with 66 additions and 10 deletions
|
|
@ -31,7 +31,10 @@ async def main() -> None:
|
||||||
|
|
||||||
asyncio.create_task(sweeper_loop(bot=bot, cfg=cfg, db=db))
|
asyncio.create_task(sweeper_loop(bot=bot, cfg=cfg, db=db))
|
||||||
try:
|
try:
|
||||||
await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types())
|
allowed_updates = list(dp.resolve_used_update_types())
|
||||||
|
if "chat_member" not in allowed_updates:
|
||||||
|
allowed_updates.append("chat_member")
|
||||||
|
await dp.start_polling(bot, allowed_updates=allowed_updates)
|
||||||
finally:
|
finally:
|
||||||
await db.close()
|
await db.close()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ from aiogram.types import (
|
||||||
CallbackQuery,
|
CallbackQuery,
|
||||||
ChatMemberAdministrator,
|
ChatMemberAdministrator,
|
||||||
ChatMemberOwner,
|
ChatMemberOwner,
|
||||||
|
ChatMemberUpdated,
|
||||||
InlineKeyboardButton,
|
InlineKeyboardButton,
|
||||||
InlineKeyboardMarkup,
|
InlineKeyboardMarkup,
|
||||||
Message,
|
Message,
|
||||||
|
|
@ -87,6 +88,32 @@ def _challenge_kb(chat_id: int, user_id: int) -> InlineKeyboardMarkup:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def _on_user_joined(
|
||||||
|
*,
|
||||||
|
bot: Bot,
|
||||||
|
cfg: Config,
|
||||||
|
db: Database,
|
||||||
|
chat_id: int,
|
||||||
|
user_id: int,
|
||||||
|
user_full_name: str,
|
||||||
|
) -> None:
|
||||||
|
try:
|
||||||
|
if await _is_admin(bot, chat_id, user_id):
|
||||||
|
return
|
||||||
|
except TelegramBadRequest:
|
||||||
|
return
|
||||||
|
|
||||||
|
await db.delete_verified(chat_id=chat_id, user_id=user_id)
|
||||||
|
await _ensure_challenge(
|
||||||
|
bot=bot,
|
||||||
|
cfg=cfg,
|
||||||
|
db=db,
|
||||||
|
chat_id=chat_id,
|
||||||
|
user_id=user_id,
|
||||||
|
user_full_name=user_full_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _ensure_challenge(
|
async def _ensure_challenge(
|
||||||
*,
|
*,
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
|
|
@ -162,15 +189,7 @@ async def on_new_members(message: Message, bot: Bot, cfg: Config, db: Database)
|
||||||
for user in message.new_chat_members:
|
for user in message.new_chat_members:
|
||||||
if user.is_bot:
|
if user.is_bot:
|
||||||
continue
|
continue
|
||||||
try:
|
await _on_user_joined(
|
||||||
if await _is_admin(bot, chat_id, user.id):
|
|
||||||
continue
|
|
||||||
except TelegramBadRequest:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Force verification on every (re)join: prevents bypass if user was verified earlier.
|
|
||||||
await db.delete_verified(chat_id=chat_id, user_id=user.id)
|
|
||||||
await _ensure_challenge(
|
|
||||||
bot=bot,
|
bot=bot,
|
||||||
cfg=cfg,
|
cfg=cfg,
|
||||||
db=db,
|
db=db,
|
||||||
|
|
@ -180,6 +199,40 @@ async def on_new_members(message: Message, bot: Bot, cfg: Config, db: Database)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.chat_member()
|
||||||
|
async def on_chat_member_updated(
|
||||||
|
event: ChatMemberUpdated,
|
||||||
|
bot: Bot,
|
||||||
|
cfg: Config,
|
||||||
|
db: Database,
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Supergroups (especially linked discussion groups) often hide join service messages.
|
||||||
|
In that case Telegram sends chat_member updates instead of new_chat_members.
|
||||||
|
"""
|
||||||
|
chat_id = event.chat.id
|
||||||
|
if not _is_allowed_chat(cfg, chat_id):
|
||||||
|
return
|
||||||
|
|
||||||
|
user = event.new_chat_member.user
|
||||||
|
if user.is_bot:
|
||||||
|
return
|
||||||
|
|
||||||
|
old_status = event.old_chat_member.status
|
||||||
|
new_status = event.new_chat_member.status
|
||||||
|
if old_status not in ("left", "kicked") or new_status not in ("member", "restricted"):
|
||||||
|
return
|
||||||
|
|
||||||
|
await _on_user_joined(
|
||||||
|
bot=bot,
|
||||||
|
cfg=cfg,
|
||||||
|
db=db,
|
||||||
|
chat_id=chat_id,
|
||||||
|
user_id=user.id,
|
||||||
|
user_full_name=user.full_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data.startswith("verify:"))
|
@router.callback_query(F.data.startswith("verify:"))
|
||||||
async def on_verify(
|
async def on_verify(
|
||||||
callback: CallbackQuery,
|
callback: CallbackQuery,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue