moderation: add chat bans for groups/channels with web actions
All checks were successful
CI / test (push) Successful in 26s

This commit is contained in:
2026-03-08 14:29:21 +03:00
parent 76cc5e0f12
commit db700bcbcd
10 changed files with 224 additions and 3 deletions

View File

@@ -350,6 +350,8 @@ async def add_chat_member_for_user(
chat, membership = await _get_chat_and_membership(db, chat_id=chat_id, user_id=actor_user_id)
_ensure_group_or_channel(chat.type)
_ensure_manage_permission(membership.role)
if await repository.is_user_banned_in_chat(db, chat_id=chat_id, user_id=target_user_id):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="User is banned from this chat")
if target_user_id == actor_user_id:
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="User is already in chat")
target_user = await get_user_by_id(db, target_user_id)
@@ -427,6 +429,45 @@ async def remove_chat_member_for_user(
await db.commit()
async def ban_chat_member_for_user(
db: AsyncSession,
*,
chat_id: int,
actor_user_id: int,
target_user_id: int,
) -> None:
chat, actor_membership = await _get_chat_and_membership(db, chat_id=chat_id, user_id=actor_user_id)
_ensure_group_or_channel(chat.type)
if actor_membership.role not in {ChatMemberRole.OWNER, ChatMemberRole.ADMIN}:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Insufficient permissions")
if target_user_id == actor_user_id:
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Cannot ban yourself")
target_membership = await repository.get_chat_member(db, chat_id=chat_id, user_id=target_user_id)
if target_membership:
if target_membership.role == ChatMemberRole.OWNER:
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Owner cannot be banned")
if actor_membership.role == ChatMemberRole.ADMIN and target_membership.role != ChatMemberRole.MEMBER:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin can ban only members")
await repository.delete_chat_member(db, target_membership)
await repository.upsert_chat_ban(db, chat_id=chat_id, user_id=target_user_id, banned_by_user_id=actor_user_id)
await db.commit()
async def unban_chat_member_for_user(
db: AsyncSession,
*,
chat_id: int,
actor_user_id: int,
target_user_id: int,
) -> None:
chat, actor_membership = await _get_chat_and_membership(db, chat_id=chat_id, user_id=actor_user_id)
_ensure_group_or_channel(chat.type)
if actor_membership.role not in {ChatMemberRole.OWNER, ChatMemberRole.ADMIN}:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Insufficient permissions")
await repository.remove_chat_ban(db, chat_id=chat_id, user_id=target_user_id)
await db.commit()
async def leave_chat_for_user(db: AsyncSession, *, chat_id: int, user_id: int) -> None:
chat, membership = await _get_chat_and_membership(db, chat_id=chat_id, user_id=user_id)
_ensure_group_or_channel(chat.type)
@@ -514,6 +555,8 @@ async def join_public_chat_for_user(db: AsyncSession, *, chat_id: int, user_id:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Chat not found")
if not chat.is_public or chat.type not in {ChatType.GROUP, ChatType.CHANNEL}:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Chat is not joinable")
if await repository.is_user_banned_in_chat(db, chat_id=chat_id, user_id=user_id):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You are banned from this chat")
membership = await repository.get_chat_member(db, chat_id=chat_id, user_id=user_id)
if membership:
return chat
@@ -650,6 +693,8 @@ async def join_chat_by_invite_for_user(
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Chat not found")
if chat.type not in {ChatType.GROUP, ChatType.CHANNEL}:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Invite link is not valid for this chat")
if await repository.is_user_banned_in_chat(db, chat_id=chat.id, user_id=user_id):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="You are banned from this chat")
membership = await repository.get_chat_member(db, chat_id=chat.id, user_id=user_id)
if membership:
return chat