Модуль кика пользователя (в бета!)
This commit is contained in:
277
bot/handlers/commands/admins/kick_cmd.py
Normal file
277
bot/handlers/commands/admins/kick_cmd.py
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
from aiogram import Router
|
||||||
|
from aiogram.filters import Command
|
||||||
|
from aiogram.fsm.context import FSMContext
|
||||||
|
from aiogram.types import Message, User
|
||||||
|
from html import escape
|
||||||
|
|
||||||
|
from bot import bot
|
||||||
|
from bot.filters import IsAdmin
|
||||||
|
from bot.utils import status_clear
|
||||||
|
from configs import COMMANDS
|
||||||
|
|
||||||
|
# Настройки роутера
|
||||||
|
__all__ = ("router",)
|
||||||
|
|
||||||
|
from middleware import logger
|
||||||
|
|
||||||
|
CMD: str = "kick"
|
||||||
|
router: Router = Router(name=f"{CMD}_cmd_router")
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(Command(*COMMANDS[CMD], ignore_case=True), IsAdmin())
|
||||||
|
async def kick_user_cmd(message: Message, state: FSMContext) -> None:
|
||||||
|
"""
|
||||||
|
Команда /kick для кика пользователей из чата.
|
||||||
|
Использование: /kick <user_id> или ответ на сообщение пользователя + /kick
|
||||||
|
"""
|
||||||
|
await status_clear(update=message, state=state)
|
||||||
|
|
||||||
|
# Проверяем, что команда используется в группе/супергруппе
|
||||||
|
if message.chat.type not in ["group", "supergroup"]:
|
||||||
|
await message.answer("❌ Эта команда работает только в группах и супергруппах!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Проверяем есть ли ответ на сообщение
|
||||||
|
if message.reply_to_message:
|
||||||
|
# Кик по ответу на сообщение
|
||||||
|
target_user: User | None = message.reply_to_message.from_user
|
||||||
|
target_user_id: int = target_user.id
|
||||||
|
target_username: str = target_user.username or target_user.full_name or f"ID{target_user_id}"
|
||||||
|
|
||||||
|
# Кикаем пользователя
|
||||||
|
success: bool = await _kick_user(target_user_id, target_username, message)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
safe_username: str = escape(target_username)
|
||||||
|
await message.answer(
|
||||||
|
text=f"👢 Пользователь {safe_username} (ID: {target_user_id}) кикнут из чата!",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await message.answer("❌ Не удалось кикнуть пользователя")
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Кик по ID пользователя
|
||||||
|
command_parts: list[str] = message.text.split()
|
||||||
|
if len(command_parts) < 2:
|
||||||
|
await message.answer(
|
||||||
|
"ℹ️ Использование команды:\n"
|
||||||
|
"• Ответьте на сообщение пользователя командой /kick\n"
|
||||||
|
"• Или укажите ID: /kick <user_id>"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
target_user_id: int = int(command_parts[1])
|
||||||
|
success: bool = await _kick_user(target_user_id, f"ID{target_user_id}", message)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
await message.answer(
|
||||||
|
text=f"👢 Пользователь (ID: {target_user_id}) кикнут из чата!",
|
||||||
|
parse_mode=None # Отключаем разметку
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await message.answer("❌ Пользователь не найден или не удалось кикнуть")
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
await message.answer("❌ Неверный формат ID пользователя")
|
||||||
|
|
||||||
|
|
||||||
|
async def _kick_user(user_id: int, username: str, message: Message) -> bool:
|
||||||
|
"""
|
||||||
|
Внутренняя функция для кика пользователя из чата.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id: ID пользователя для кика
|
||||||
|
username: Имя пользователя для логов
|
||||||
|
message: Объект сообщения для контекста
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: Успешно ли кикнут пользователь
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Проверяем, что бот имеет права администратора в чате
|
||||||
|
bot_member = await bot.get_chat_member(message.chat.id, bot.id)
|
||||||
|
if not bot_member.can_restrict_members:
|
||||||
|
await message.answer("❌ У меня нет прав для кика пользователей!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Проверяем, что целевой пользователь не является администратором/владельцем
|
||||||
|
target_member = await bot.get_chat_member(message.chat.id, user_id)
|
||||||
|
if target_member.status in ["creator", "administrator"]:
|
||||||
|
await message.answer("❌ Нельзя кикнуть администратора или создателя чата!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Проверяем, что отправитель команды имеет права администратора
|
||||||
|
admin_member = await bot.get_chat_member(message.chat.id, message.from_user.id)
|
||||||
|
if admin_member.status not in ["creator", "administrator"]:
|
||||||
|
await message.answer("❌ У вас нет прав для кика пользователей!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Кикаем пользователя из чата
|
||||||
|
await bot.ban_chat_member(
|
||||||
|
chat_id=message.chat.id,
|
||||||
|
user_id=user_id,
|
||||||
|
revoke_messages=False # Не удаляем сообщения пользователя
|
||||||
|
)
|
||||||
|
|
||||||
|
# Сразу разбаниваем, чтобы пользователь мог вернуться по приглашению
|
||||||
|
await bot.unban_chat_member(
|
||||||
|
chat_id=message.chat.id,
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
|
||||||
|
# Логируем действие
|
||||||
|
admin_username = message.from_user.username or message.from_user.full_name
|
||||||
|
logger.info(
|
||||||
|
f"👢 Админ @{admin_username} кикнул пользователя @{username} (ID: {user_id}) из чата {message.chat.title}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Ошибка при кике пользователя {user_id}: {e}")
|
||||||
|
await message.answer(f"❌ Ошибка при кике пользователя: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(Command("kick_ban", ignore_case=True), IsAdmin())
|
||||||
|
async def kick_ban_user_cmd(message: Message, state: FSMContext) -> None:
|
||||||
|
"""
|
||||||
|
Команда /kick_ban для кика пользователя с удалением сообщений.
|
||||||
|
Использование: /kick_ban <user_id> или ответ на сообщение пользователя + /kick_ban
|
||||||
|
"""
|
||||||
|
await status_clear(update=message, state=state)
|
||||||
|
|
||||||
|
# Проверяем, что команда используется в группе/супергруппе
|
||||||
|
if message.chat.type not in ["group", "supergroup"]:
|
||||||
|
await message.answer("❌ Эта команда работает только в группах и супергруппах!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Проверяем есть ли ответ на сообщение
|
||||||
|
if message.reply_to_message:
|
||||||
|
# Кик по ответу на сообщение
|
||||||
|
target_user: User | None = message.reply_to_message.from_user
|
||||||
|
target_user_id: int = target_user.id
|
||||||
|
target_username: str = target_user.username or target_user.full_name or f"ID{target_user_id}"
|
||||||
|
|
||||||
|
# Кикаем пользователя с удалением сообщений
|
||||||
|
success: bool = await _kick_ban_user(target_user_id, target_username, message)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
safe_username: str = escape(target_username)
|
||||||
|
await message.answer(
|
||||||
|
text=f"💥 Пользователь {safe_username} (ID: {target_user_id}) кикнут с удалением сообщений!",
|
||||||
|
parse_mode=None # Отключаем разметку
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await message.answer("❌ Не удалось кикнуть пользователя")
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Кик по ID пользователя
|
||||||
|
command_parts: list[str] = message.text.split()
|
||||||
|
if len(command_parts) < 2:
|
||||||
|
await message.answer(
|
||||||
|
"ℹ️ Использование команды:\n"
|
||||||
|
"• Ответьте на сообщение пользователя командой /kick_ban\n"
|
||||||
|
"• Или укажите ID: /kick_ban <user_id>"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
target_user_id: int = int(command_parts[1])
|
||||||
|
success: bool = await _kick_ban_user(target_user_id, f"ID{target_user_id}", message)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
await message.answer(
|
||||||
|
text=f"💥 Пользователь (ID: {target_user_id}) кикнут с удалением сообщений!",
|
||||||
|
parse_mode=None # Отключаем разметку
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await message.answer("❌ Пользователь не найден или не удалось кикнуть")
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
await message.answer("❌ Неверный формат ID пользователя")
|
||||||
|
|
||||||
|
|
||||||
|
async def _kick_ban_user(user_id: int, username: str, message: Message) -> bool:
|
||||||
|
"""
|
||||||
|
Внутренняя функция для кика пользователя с удалением сообщений.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id: ID пользователя для кика
|
||||||
|
username: Имя пользователя для логов
|
||||||
|
message: Объект сообщения для контекста
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: Успешно ли кикнут пользователь
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Проверяем, что бот имеет права администратора в чате
|
||||||
|
bot_member = await bot.get_chat_member(message.chat.id, bot.id)
|
||||||
|
if not bot_member.can_restrict_members:
|
||||||
|
await message.answer("❌ У меня нет прав для кика пользователей!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Проверяем, что целевой пользователь не является администратором/владельцем
|
||||||
|
target_member = await bot.get_chat_member(message.chat.id, user_id)
|
||||||
|
if target_member.status in ["creator", "administrator"]:
|
||||||
|
await message.answer("❌ Нельзя кикнуть администратора или создателя чата!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Проверяем, что отправитель команды имеет права администратора
|
||||||
|
admin_member = await bot.get_chat_member(message.chat.id, message.from_user.id)
|
||||||
|
if admin_member.status not in ["creator", "administrator"]:
|
||||||
|
await message.answer("❌ У вас нет прав для кика пользователей!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Кикаем пользователя из чата с удалением сообщений
|
||||||
|
await bot.ban_chat_member(
|
||||||
|
chat_id=message.chat.id,
|
||||||
|
user_id=user_id,
|
||||||
|
revoke_messages=True # Удаляем сообщения пользователя
|
||||||
|
)
|
||||||
|
|
||||||
|
# Сразу разбаниваем, чтобы пользователь мог вернуться по приглашению
|
||||||
|
await bot.unban_chat_member(
|
||||||
|
chat_id=message.chat.id,
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
|
||||||
|
# Логируем действие
|
||||||
|
admin_username = message.from_user.username or message.from_user.full_name
|
||||||
|
logger.info(
|
||||||
|
f"💥 Админ @{admin_username} кикнул пользователя @{username} (ID: {user_id}) из чата {message.chat.title} с удалением сообщений")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Ошибка при кике пользователя {user_id} с удалением сообщений: {e}")
|
||||||
|
await message.answer(f"❌ Ошибка при кике пользователя: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(Command("kick_list", ignore_case=True), IsAdmin())
|
||||||
|
async def kick_help_cmd(message: Message, state: FSMContext) -> None:
|
||||||
|
"""
|
||||||
|
Команда /kick_list для показа справки по командам кика.
|
||||||
|
"""
|
||||||
|
await status_clear(update=message, state=state)
|
||||||
|
|
||||||
|
help_text = """
|
||||||
|
🤖 **Команды модерации:**
|
||||||
|
|
||||||
|
**👢 /kick** - Кикнуть пользователя (может вернуться по приглашению)
|
||||||
|
• Ответьте на сообщение пользователя с командой /kick
|
||||||
|
• Или используйте: /kick <user_id>
|
||||||
|
|
||||||
|
**💥 /kick_ban** - Кикнуть пользователя с удалением сообщений
|
||||||
|
• Ответьте на сообщение пользователя с командой /kick_ban
|
||||||
|
• Или используйте: /kick_ban <user_id>
|
||||||
|
|
||||||
|
**🚫 /ban** - Полностью забанить пользователя
|
||||||
|
**🔓 /unban** - Разбанить пользователя
|
||||||
|
**📋 /banned_list** - Список забаненных
|
||||||
|
|
||||||
|
⚠️ *Команды работают только в группах и требуют прав администратора*
|
||||||
|
"""
|
||||||
|
|
||||||
|
await message.answer(help_text, parse_mode=None)
|
||||||
Reference in New Issue
Block a user