В логах выводится id чата, для которого был сформирован лог

parent 9086dd88
import asyncio
from aiogram import Bot, Dispatcher, Router
from aiogram.types import ChatMemberUpdated, Message
#from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext
#from aiogram.middleware.BaseMiddleware import BaseMiddlewarefrom
from aiogram.exceptions import AiogramError
from pymorphy2 import MorphAnalyzer
from aiogram.types import ChatMember
......@@ -85,10 +87,10 @@ SPAM_KEYWORDS = [
"🎁", "🔥", "💸", "💰", "💲", "💎", "🤑", "🤩", "⚡", "⭐", "💥", "✅", "🏆", "✋", "💖", "💝", "⚔️", "🥇", "💯", "💳", "🔞", "🥳", "😱"
]
def preprocess_spam_keywords(keywords):
def preprocess_spam_keywords(keywords, chat_id):
"""Приводит ключевые слова к нормализованной форме."""
logger.debug("preprocess_spam_keywords: keyword conversion")
return set(' '.join(normalize_text_to_infinitive(keyword)) for keyword in keywords)
return set(' '.join(normalize_text_to_infinitive(keyword, chat_id)) for keyword in keywords)
# Загрузка переменных из файла .env
......@@ -115,14 +117,21 @@ class TelegramLogHandler(logging.Handler):
self.bot = bot
self.chat_id = chat_id
async def send_log(self, message):
await self.bot.send_message(self.chat_id, message)
async def send_log(self, message, chat_id):
await self.bot.send_message(chat_id, message)
def emit(self, record):
log_message = f"Chat ID: {main_chat_id}\n{self.format(record)}"
loop = asyncio.get_event_loop()
loop.create_task(self.send_log(log_message))
#asyncio.create_task(self.send_log(log_message)) # создаем асинхронную задачу
log_message = self.format(record)
# Используем глобальный `log_chat_id` вместо получения его из extra
#log_message = f"Log Message: {log_message}"
chat_id = getattr(record, 'chat_id', self.chat_id)
log_message = f"Chat ID: {chat_id}\n{log_message}"
loop = asyncio.get_event_loop()
loop.create_task(self.send_log(log_message, log_chat_id))
......@@ -142,9 +151,10 @@ tg_log_handler.setFormatter(formatter)
# Добавляем обработчик в логгер
logger.addHandler(tg_log_handler)
morph = MorphAnalyzer()
def has_mixed_layout(text):
def has_mixed_layout(text, chat_id):
chat_id = chat_id
"""
Проверяет, содержит ли текст слова, написанные на смешанной раскладке.
Например: "пр1в3т", "teст", "нeт".
......@@ -165,13 +175,13 @@ def has_mixed_layout(text):
mixed_words.append(word) # Добавляем слово в список
if len(mixed_words) > 1:
logger.info("Words with mixed layout: %s", ", ".join(mixed_words))
logger.info("Words with mixed layout: %s", ", ".join(mixed_words), extra={"chat_id": chat_id})
return True # Найдено больше одного слова
return False
except Exception as e:
logger.error("Checking error: %s", e)
logger.error("Checking error: %s", e, extra={"chat_id": chat_id})
return False
# Проверка на арабские символы в имени
......@@ -195,7 +205,10 @@ emoji_pattern = re.compile("["
u"\U0001F004-\U0001F0CF" # Playing Cards
"]+", flags=re.UNICODE)
def normalize_text_to_infinitive(text):
def normalize_text_to_infinitive(text, chat_id):
chat_id = chat_id
"""
Приводит текст к нижнему регистру, нормализует слова до начальной формы,
удаляет лишние символы и обрабатывает смешанные раскладки.
......@@ -227,27 +240,33 @@ def normalize_text_to_infinitive(text):
normalized_words.append(morph.parse(word)[0].normal_form)
except Exception as e:
# Если слово не удалось обработать, добавляем его как есть
logger.error("Normalisation error '%s': %s", word, e)
logger.error("Normalisation error '%s': %s", word, e, extra={"chat_id": chat_id})
normalized_words.append(word)
return normalized_words
def extract_emojis(text):
def extract_emojis(text, chat_id):
chat_id = chat_id
try:
return ''.join(c for c in text if emoji.is_emoji(c))
except Exception as e:
logger.error("Extracting emojis error: %s", e)
logger.error("Extracting emojis error: %s", e, extra={"chat_id": chat_id})
return ''
def is_spam(text):
def is_spam(text, chat_id):
if text is None: # Проверяем, что текст не None
return False
chat_id = chat_id
# Нормализуем текст
normalized_words = normalize_text_to_infinitive(text)
normalized_words = normalize_text_to_infinitive(text, chat_id)
# Извлекаем эмодзи
emojis = extract_emojis(text)
emojis = extract_emojis(text, chat_id)
# Проверка, состоит ли сообщение только из эмодзи и длина >= 10
if len(text) >= 9 and all(char in emojis for char in text):
......@@ -273,7 +292,7 @@ def is_spam(text):
matched_keywords.append(keyword) # Добавляем совпавшее слово в список
if matched_keywords:
logger.debug(f"Spam-words found in text: {', '.join(matched_keywords)}")
logger.debug(f"Spam-words found in text: {', '.join(matched_keywords)}", extra={"chat_id": chat_id})
spam_count += emoji_count # Учитываем только спам-эмодзи
......@@ -290,6 +309,7 @@ def generate_math_problem():
@router.chat_member()
async def welcome_new_user(event: ChatMemberUpdated):
"""Обработчик новых участников группы."""
if event.new_chat_member.status == "member" and event.old_chat_member.status not in ["member", "administrator", "creator"]:
new_user = event.new_chat_member.user
......@@ -298,20 +318,20 @@ async def welcome_new_user(event: ChatMemberUpdated):
try:
# Немедленно удаляем пользователя
await bot.ban_chat_member(event.chat.id, new_user.id)
logger.info(f"User {new_user.first_name} ({new_user.id}) banned due to Arabic name.")
logger.info(f"User {new_user.first_name} ({new_user.id}) banned due to Arabic name.", extra={"chat_id": event.chat_id})
return # Прерываем дальнейшую обработку
except AiogramError as e:
logger.error(f"Failed to ban user {new_user.id}. Error: {e}")
logger.error(f"Failed to ban user {new_user.id}. Error: {e}", extra={"chat_id": event.chat_id})
except Exception as e:
logger.error(f"Error banning user {new_user.id}: {e}")
logger.error(f"Error banning user {new_user.id}: {e}", extra={"chat_id": event.chat_id})
return
math_problem, correct_answer = generate_math_problem()
try:
# Отправляем приветственное сообщение
logger.info(f"Sending welcome message to {new_user.first_name} ({new_user.id}) in chat {event.chat.id}")
logger.info(f"Sending welcome message to {new_user.first_name} ({new_user.id}) in chat {event.chat.id}", extra={"chat_id": event.chat.id})
welcome_message = await bot.send_message(
chat_id=event.chat.id,
text=f"Здравствуйте, {new_user.first_name}! Добро пожаловать в группу!\n\n"
......@@ -328,10 +348,10 @@ async def welcome_new_user(event: ChatMemberUpdated):
"user_answered": False,
"chat_id": event.chat.id,
}
logger.info(f"User {new_user.first_name} ({new_user.id}) added to active users.")
logger.info(f"User {new_user.first_name} ({new_user.id}) added to active users.", extra={"chat_id": event.chat_id})
except Exception as e:
logger.error(f"Failed sending a message to the group {event.chat.id}. Error: {e}")
logger.error(f"Failed sending a message to the group {event.chat.id}. Error: {e}", extra={"chat_id": event.chat_id})
# Ожидание ответа пользователя
await check_answer(new_user.id)
......@@ -361,6 +381,7 @@ async def unban_user(callback_query: types.CallbackQuery):
async def check_answer(user_id):
"""Проверка ответа пользователя через 1 минуту."""
chat_id = user_data["chat_id"]
await asyncio.sleep(60)
user_data = active_users.get(user_id)
......@@ -388,37 +409,39 @@ async def check_answer(user_id):
)
except AiogramError as e:
logger.error(f"User deletion error {user_id}. Error: {e}")
logger.error(f"User deletion error {user_id}. Error: {e}", extra={"chat_id": chat_id})
except Exception as e:
logger.error(f"User deletion error {user_id}. Error: {e}")
logger.error(f"User deletion error {user_id}. Error: {e}", extra={"chat_id": chat_id})
async def cleanup_messages(user_data):
"""Удаление всех сообщений пользователя и бота."""
chat_id = user_data["chat_id"] # Получаем ID чата
try:
# Удаляем все сообщения бота
for message_id in user_data["message_ids"]:
try:
await bot.delete_message(chat_id=user_data["chat_id"], message_id=message_id)
logger.info(f"Message with ID {message_id} successfully deleted from chat.")
logger.info(f"Message with ID {message_id} successfully deleted from chat.", extra={"chat_id": chat_id})
except Exception as e:
logger.error(f"Bot message deletion error. Error: {e}")
logger.error(f"Bot message deletion error. Error: {e}", extra={"chat_id": chat_id})
# Удаляем сообщения пользователя
for user_message in user_data["user_messages"]:
try:
if user_message:
await bot.delete_message(chat_id=user_data["chat_id"], message_id=user_message.message_id)
logger.info(f"Message с ID {message_id} successfully deleted from chat.")
logger.info(f"Message с ID {message_id} successfully deleted from chat.", extra={"chat_id": chat_id})
except Exception as e:
logger.error(f"User message deletion error. Error: {e}")
logger.error(f"User message deletion error. Error: {e}", extra={"chat_id": chat_id})
except Exception as e:
logger.error(f"Message deletion error. Error: {e}")
logger.error(f"Message deletion error. Error: {e}", extra={"chat_id": chat_id})
@router.message()
async def handle_message(message: Message):
"""Обработчик сообщений от пользователей для проверки ответа."""
chat_id = message.chat.id # Получаем ID чата
# Получаем статус пользователя в чате (администратор, участник и т.д.)
try:
chat_member = await bot.get_chat_member(message.chat.id, message.from_user.id)
......@@ -432,28 +455,28 @@ async def handle_message(message: Message):
await message.delete()
return
except AiogramError as e:
logger.error(f"User status verification error {message.from_user.id}. Error: {e}")
logger.error(f"User status verification error {message.from_user.id}. Error: {e}", extra={"chat_id": chat_id})
text = message.text or message.caption or ""
text = " ".join(normalize_text_to_infinitive(text)) # Убедимся, что это строка
text = " ".join(normalize_text_to_infinitive(text, chat_id)) # Убедимся, что это строка
# Проверка на смешанную раскладку
if text and has_mixed_layout(text):
if text and has_mixed_layout(text, chat_id):
try:
await message.delete()
logger.debug(f"Message with a mixed layout successfully deleted from group.")
logger.debug(f"Message with a mixed layout successfully deleted from group.", extra={"chat_id": chat_id})
return
except Exception as e:
logger.error(f"Error deleting a message with a mixed layout. Error: {e}")
logger.error(f"Error deleting a message with a mixed layout. Error: {e}", extra={"chat_id": chat_id})
# Проверка на мультимедиа (фото/видео) и его подпись
if (message.photo or message.video or message.document) and text.strip() and is_spam(text):
if (message.photo or message.video or message.document) and text.strip() and is_spam(text, chat_id):
try:
await message.delete()
logger.info(f"Multimedia message with ID {message.message_id} successfully deleted from group.")
logger.info(f"Multimedia message with ID {message.message_id} successfully deleted from group.", extra={"chat_id": chat_id})
return
except Exception as e:
logger.error(f"Error deleting a multimedia message. Error: {e}")
logger.error(f"Error deleting a multimedia message. Error: {e}", extra={"chat_id": chat_id})
# Проверка на кнопки/ссылки
if message.reply_markup and hasattr(message.reply_markup, 'inline_keyboard'):
......@@ -461,19 +484,19 @@ async def handle_message(message: Message):
if button.url and any(spam_word in button.url.lower() for spam_word in SPAM_KEYWORDS):
try:
await message.delete()
logger.info(f"Message with links/buttons with ID {message.message_id} successfully deleted from group.")
logger.info(f"Message with links/buttons with ID {message.message_id} successfully deleted from group.", extra={"chat_id": chat_id})
return
except Exception as e:
logger.error(f"Error when deleting a message with a button. Error: {e}")
logger.error(f"Error when deleting a message with a button. Error: {e}", extra={"chat_id": chat_id})
# Проверка на спам
if is_spam(message.text):
if is_spam(text, chat_id):
try:
await message.delete()
logger.info(f"Message wiht spam {message.message_id} successfully deleted from group.")
logger.info(f"Message wiht spam {message.message_id} successfully deleted from group.", extra={"chat_id": chat_id})
return
except Exception as e:
logger.error(f"Error when trying to delete spam messages. Error: {e}")
logger.error(f"Error when trying to delete spam messages. Error: {e}", extra={"chat_id": chat_id})
user_data = active_users.get(message.from_user.id)
......@@ -490,17 +513,17 @@ async def handle_message(message: Message):
user_data["message_ids"].append(correct_message.message_id) # Добавляем в список ID сообщений
# Удаляем сообщения после правильного ответа
await cleanup_messages(user_data)
logger.info(f"User {message.from_user.id} answered correctly with {user_answer}. Correct answer.")
logger.info(f"User {message.from_user.id} answered correctly with {user_answer}. Correct answer.", extra={"chat_id": chat_id})
else:
# Ответ неправильный, добавляем новое сообщение бота
incorrect_message = await message.reply("Неправильный ответ. Попробуйте еще раз.")
user_data["message_ids"].append(incorrect_message.message_id)
logger.warning(f"User {message.from_user.id} answered incorrectly with {user_answer}. Correct answer was {user_data['correct_answer']}.")
logger.warning(f"User {message.from_user.id} answered incorrectly with {user_answer}. Correct answer was {user_data['correct_answer']}.", extra={"chat_id": chat_id})
else:
# Если ответ не число
invalid_message = await message.reply("Пожалуйста, отправьте числовой ответ.")
user_data["message_ids"].append(invalid_message.message_id)
logger.warning(f"User {message.from_user.id} sent an invalid answer: {message.text}")
logger.warning(f"User {message.from_user.id} sent an invalid answer: {message.text}", extra={"chat_id": chat_id})
......@@ -540,5 +563,6 @@ async def main():
await dp.start_polling(bot)
if __name__ == "__main__":
SPAM_KEYWORDS = preprocess_spam_keywords(SPAM_KEYWORDS)
SPAM_KEYWORDS = preprocess_spam_keywords(SPAM_KEYWORDS, log_chat_id)
asyncio.run(main())
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment