From 69d55a68b9629831890eed77e8168f18fcce24e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B2=D0=B3=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=A5=D1=80?= =?UTF-8?q?=D0=B0=D0=BC=D0=BE=D0=B2?= Date: Mon, 13 Oct 2025 14:20:18 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B?= =?UTF-8?q?=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=BE=D0=B2=20=D1=81=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D0=B1=D1=80=D0=BE=D1=81=D0=B0=20=D1=81?= =?UTF-8?q?=D1=87=D1=91=D1=82=D1=87=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=BD=D0=B0?= =?UTF-8?q?=D1=80=D1=83=D1=88=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.py | 12 ++++ src/database.py | 13 ++++ src/main.py | 1 + src/modules/auto_mute.py | 18 ++++- src/modules/reset_violations.py | 120 ++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 src/modules/reset_violations.py diff --git a/src/config.py b/src/config.py index 5ec5140..0d7df63 100644 --- a/src/config.py +++ b/src/config.py @@ -123,6 +123,18 @@ COMMAND_MESSAGES = { "Прочее:\n" "• /badwords reload - Перезагрузить из файла\n\n" "💡 Все изменения применяются немедленно" + ), + 'reset_violations_help': ( + "🔄 Команда /reset_violations\n\n" + "Сбрасывает счётчик нарушений пользователя\n\n" + "🎯 Способы использования:\n" + "1. Ответ на сообщение:\n" + " /reset_violations\n" + "2. По тегу пользователя:\n" + " /reset_violations @username\n" + "3. По ID пользователя:\n" + " /reset_violations 123456789\n\n" + "ℹ️ Сбрасывает все записи об автомутах пользователя" ) } \ No newline at end of file diff --git a/src/database.py b/src/database.py index 9cd2169..6c21a18 100644 --- a/src/database.py +++ b/src/database.py @@ -143,5 +143,18 @@ class Database: # Инициализация класса logger.info(f"Удалено старых нарушений: {deleted_count}") return deleted_count + # Сбрасывает все нарушения пользователя в чате + def reset_user_violations(self, user_id: int, chat_id: int): + with self._get_connection() as connect: + cursor = connect.cursor() + cursor.execute(''' + DELETE FROM violations + WHERE user_id = ? AND chat_id = ? + ''', (user_id, chat_id)) + deleted_count = cursor.rowcount + connect.commit() + logger.info(f"Сброшено {deleted_count} нарушений пользователя {user_id} в чате {chat_id}") + return deleted_count + # Создаем экземпляр базы данных для импорта в других модулях db = Database() \ No newline at end of file diff --git a/src/main.py b/src/main.py index 02e2914..98c0290 100644 --- a/src/main.py +++ b/src/main.py @@ -124,6 +124,7 @@ async def setup_bot_commands(): BotCommand("mute", "Замутить пользователя. Использование: /mute help"), BotCommand("unmute", "Размутить пользователя. Использование: /unmute help"), BotCommand("badwords", "Управление списком бранных слов. /badwords help"), + BotCommand("reset_violations", "Сбросить счётчик нарушений пользователя"), BotCommand("botdata", "Получить данные бота (только для админов)"), ] diff --git a/src/modules/auto_mute.py b/src/modules/auto_mute.py index e6e904e..0829b35 100644 --- a/src/modules/auto_mute.py +++ b/src/modules/auto_mute.py @@ -56,7 +56,7 @@ def get_mute_duration(violations_count: int) -> int: return MUTE_LEVELS[level_index] -async def apply_mute(bot: AsyncTeleBot, message: Message, user_id: int, duration: int, violations_count: int): +async def apply_mute(bot: AsyncTeleBot, message: Message, user_id: int, duration: int, violations_count: int, bad_words_found: list = None): """ Применяет мут к пользователю. @@ -66,6 +66,7 @@ async def apply_mute(bot: AsyncTeleBot, message: Message, user_id: int, duration user_id: ID пользователя duration: Длительность мута в секундах (None для перманентного) violations_count: Количество нарушений + bad_words_found: Список найденных плохих слов """ try: # Устанавливаем ограничения (только чтение) @@ -97,6 +98,14 @@ async def apply_mute(bot: AsyncTeleBot, message: Message, user_id: int, duration except Exception as e: logger.warning(f"Не удалось удалить сообщение: {e}") + # Формируем информацию о найденных словах + words_info = "" + if bad_words_found: + words_list = ", ".join([f"«{word}»" for word in bad_words_found]) + words_info = f"Найдено слов: {words_list}" + else: + words_info = "Использование нецензурной лексики" + # Формируем сообщение о муте if duration is None: time_display = "навсегда" @@ -127,7 +136,7 @@ async def apply_mute(bot: AsyncTeleBot, message: Message, user_id: int, duration action="АВТОМУТ", user_id=user_id, admin_id=None, # Автоматическое действие - reason=f"Использование нецензурной лексики (нарушение #{violations_count})", + reason=f"{words_info} (нарушение #{violations_count})", duration=time_display, ) @@ -160,6 +169,9 @@ async def check_message_for_profanity(bot: AsyncTeleBot, message: Message): if not contains_bad_word(message.text): return + # Получаем список найденных плохих слов + bad_words_found = get_bad_words_from_text(message.text) + # Получаем ID пользователя и чата user_id = message.from_user.id chat_id = message.chat.id @@ -184,7 +196,7 @@ async def check_message_for_profanity(bot: AsyncTeleBot, message: Message): mute_duration = get_mute_duration(violations_count) # Применяем мут - await apply_mute(bot, message, user_id, mute_duration, violations_count) + await apply_mute(bot, message, user_id, mute_duration, violations_count, bad_words_found) def register_handlers(bot: AsyncTeleBot): """ diff --git a/src/modules/reset_violations.py b/src/modules/reset_violations.py new file mode 100644 index 0000000..c160204 --- /dev/null +++ b/src/modules/reset_violations.py @@ -0,0 +1,120 @@ +from telebot.async_telebot import AsyncTeleBot +from telebot.types import Message +import logging + +from database import db +from utils import check_admin_status, delete_messages +from config import COMMAND_MESSAGES + +logger = logging.getLogger(__name__) + +def register_handlers(bot: AsyncTeleBot): + """Регистрирует обработчик команды сброса нарушений""" + + @bot.message_handler(commands=['reset_violations']) + async def reset_violations_command(message: Message): + """Команда для сброса счётчика нарушений пользователя""" + + logger.info(f"Команда /reset_violations получена от пользователя {message.from_user.id}") + + # Проверяем права администратора + admin_check = await check_admin_status(bot, message) + if admin_check == 1: + logger.info(f"Пользователь {message.from_user.id} не является администратором") + return + + logger.info(f"Пользователь {message.from_user.id} прошел проверку прав администратора") + + # Определяем целевого пользователя + target_user = None + target_user_id = None + + # Обработка ответа на сообщение + if message.reply_to_message: + target_user = message.reply_to_message.from_user + target_user_id = target_user.id + + # Обработка по username или ID + else: + parts = message.text.split(maxsplit=1) + + if len(parts) < 2: + await send_temp_message( + bot, + message, + COMMAND_MESSAGES['reset_violations_help'] + ) + return + + identifier = parts[1].strip() + + # Попытка получить по username + if identifier.startswith('@'): + username = identifier[1:] + user_data = db.get_user_by_username(username) + if user_data: + target_user_id = user_data[0] + else: + await send_temp_message( + bot, + message, + COMMAND_MESSAGES['user_not_found'] + ) + return + + # Попытка получить по ID + else: + try: + target_user_id = int(identifier) + except ValueError: + await send_temp_message( + bot, + message, + COMMAND_MESSAGES['user_not_found'] + ) + return + + # Проверяем, что нашли пользователя + if not target_user_id: + await send_temp_message( + bot, + message, + COMMAND_MESSAGES['user_not_found'] + ) + return + + # Получаем информацию о пользователе из базы + user_info = db.get_user(target_user_id) + + # Получаем текущее количество нарушений + violations_count = db.get_violations_count(target_user_id, message.chat.id) + + # Сбрасываем нарушения + deleted_count = db.reset_user_violations(target_user_id, message.chat.id) + + # Формируем сообщение + if user_info: + _, nickname, tag = user_info + user_display = f"{nickname}" + if tag: + user_display += f" (@{tag})" + else: + user_display = f"{target_user_id}" + + response = ( + f"✅ Счётчик нарушений сброшен\n\n" + f"👤 Пользователь: {user_display}\n" + f"📊 Удалено нарушений: {deleted_count}" + ) + + await send_temp_message(bot, message, response, time_sleep=30) + logger.info(f"Администратор {message.from_user.id} сбросил счётчик нарушений пользователя {target_user_id}") + +async def send_temp_message(bot: AsyncTeleBot, message: Message, text: str, time_sleep: int = 10): + """Отправляет временное сообщение, которое удаляется через указанное время""" + await bot.send_message( + chat_id=message.chat.id, + text=text, + message_thread_id=message.message_thread_id, + ) + await delete_messages(bot, message, time_sleep=time_sleep, number_message=2) \ No newline at end of file