279 lines
13 KiB
Python
279 lines
13 KiB
Python
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(message=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}) кикнут из чата!",
|
||
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\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(message=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(message=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)
|