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

parent 9086dd88
import asyncio import asyncio
from aiogram import Bot, Dispatcher, Router from aiogram import Bot, Dispatcher, Router
from aiogram.types import ChatMemberUpdated, Message 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 aiogram.exceptions import AiogramError
from pymorphy2 import MorphAnalyzer from pymorphy2 import MorphAnalyzer
from aiogram.types import ChatMember from aiogram.types import ChatMember
...@@ -85,10 +87,10 @@ SPAM_KEYWORDS = [ ...@@ -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") 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 # Загрузка переменных из файла .env
...@@ -115,14 +117,21 @@ class TelegramLogHandler(logging.Handler): ...@@ -115,14 +117,21 @@ class TelegramLogHandler(logging.Handler):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
async def send_log(self, message): async def send_log(self, message, chat_id):
await self.bot.send_message(self.chat_id, message) await self.bot.send_message(chat_id, message)
def emit(self, record): def emit(self, record):
log_message = f"Chat ID: {main_chat_id}\n{self.format(record)}" log_message = self.format(record)
loop = asyncio.get_event_loop()
loop.create_task(self.send_log(log_message)) # Используем глобальный `log_chat_id` вместо получения его из extra
#asyncio.create_task(self.send_log(log_message)) # создаем асинхронную задачу #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) ...@@ -142,9 +151,10 @@ tg_log_handler.setFormatter(formatter)
# Добавляем обработчик в логгер # Добавляем обработчик в логгер
logger.addHandler(tg_log_handler) logger.addHandler(tg_log_handler)
morph = MorphAnalyzer() morph = MorphAnalyzer()
def has_mixed_layout(text): def has_mixed_layout(text, chat_id):
chat_id = chat_id
""" """
Проверяет, содержит ли текст слова, написанные на смешанной раскладке. Проверяет, содержит ли текст слова, написанные на смешанной раскладке.
Например: "пр1в3т", "teст", "нeт". Например: "пр1в3т", "teст", "нeт".
...@@ -165,13 +175,13 @@ def has_mixed_layout(text): ...@@ -165,13 +175,13 @@ def has_mixed_layout(text):
mixed_words.append(word) # Добавляем слово в список mixed_words.append(word) # Добавляем слово в список
if len(mixed_words) > 1: 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 True # Найдено больше одного слова
return False return False
except Exception as e: except Exception as e:
logger.error("Checking error: %s", e) logger.error("Checking error: %s", e, extra={"chat_id": chat_id})
return False return False
# Проверка на арабские символы в имени # Проверка на арабские символы в имени
...@@ -195,7 +205,10 @@ emoji_pattern = re.compile("[" ...@@ -195,7 +205,10 @@ emoji_pattern = re.compile("["
u"\U0001F004-\U0001F0CF" # Playing Cards u"\U0001F004-\U0001F0CF" # Playing Cards
"]+", flags=re.UNICODE) "]+", 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): ...@@ -227,27 +240,33 @@ def normalize_text_to_infinitive(text):
normalized_words.append(morph.parse(word)[0].normal_form) normalized_words.append(morph.parse(word)[0].normal_form)
except Exception as e: 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) normalized_words.append(word)
return normalized_words return normalized_words
def extract_emojis(text): def extract_emojis(text, chat_id):
chat_id = chat_id
try: try:
return ''.join(c for c in text if emoji.is_emoji(c)) return ''.join(c for c in text if emoji.is_emoji(c))
except Exception as e: except Exception as e:
logger.error("Extracting emojis error: %s", e) logger.error("Extracting emojis error: %s", e, extra={"chat_id": chat_id})
return '' return ''
def is_spam(text): def is_spam(text, chat_id):
if text is None: # Проверяем, что текст не None if text is None: # Проверяем, что текст не None
return False 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 # Проверка, состоит ли сообщение только из эмодзи и длина >= 10
if len(text) >= 9 and all(char in emojis for char in text): if len(text) >= 9 and all(char in emojis for char in text):
...@@ -273,7 +292,7 @@ def is_spam(text): ...@@ -273,7 +292,7 @@ def is_spam(text):
matched_keywords.append(keyword) # Добавляем совпавшее слово в список matched_keywords.append(keyword) # Добавляем совпавшее слово в список
if matched_keywords: 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 # Учитываем только спам-эмодзи spam_count += emoji_count # Учитываем только спам-эмодзи
...@@ -290,6 +309,7 @@ def generate_math_problem(): ...@@ -290,6 +309,7 @@ def generate_math_problem():
@router.chat_member() @router.chat_member()
async def welcome_new_user(event: ChatMemberUpdated): 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"]: 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 new_user = event.new_chat_member.user
...@@ -298,20 +318,20 @@ async def welcome_new_user(event: ChatMemberUpdated): ...@@ -298,20 +318,20 @@ async def welcome_new_user(event: ChatMemberUpdated):
try: try:
# Немедленно удаляем пользователя # Немедленно удаляем пользователя
await bot.ban_chat_member(event.chat.id, new_user.id) 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 # Прерываем дальнейшую обработку return # Прерываем дальнейшую обработку
except AiogramError as e: 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: 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 return
math_problem, correct_answer = generate_math_problem() math_problem, correct_answer = generate_math_problem()
try: 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( welcome_message = await bot.send_message(
chat_id=event.chat.id, chat_id=event.chat.id,
text=f"Здравствуйте, {new_user.first_name}! Добро пожаловать в группу!\n\n" text=f"Здравствуйте, {new_user.first_name}! Добро пожаловать в группу!\n\n"
...@@ -328,10 +348,10 @@ async def welcome_new_user(event: ChatMemberUpdated): ...@@ -328,10 +348,10 @@ async def welcome_new_user(event: ChatMemberUpdated):
"user_answered": False, "user_answered": False,
"chat_id": event.chat.id, "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: 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) await check_answer(new_user.id)
...@@ -361,6 +381,7 @@ async def unban_user(callback_query: types.CallbackQuery): ...@@ -361,6 +381,7 @@ async def unban_user(callback_query: types.CallbackQuery):
async def check_answer(user_id): async def check_answer(user_id):
"""Проверка ответа пользователя через 1 минуту.""" """Проверка ответа пользователя через 1 минуту."""
chat_id = user_data["chat_id"]
await asyncio.sleep(60) await asyncio.sleep(60)
user_data = active_users.get(user_id) user_data = active_users.get(user_id)
...@@ -388,37 +409,39 @@ async def check_answer(user_id): ...@@ -388,37 +409,39 @@ async def check_answer(user_id):
) )
except AiogramError as e: 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: 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): async def cleanup_messages(user_data):
"""Удаление всех сообщений пользователя и бота.""" """Удаление всех сообщений пользователя и бота."""
chat_id = user_data["chat_id"] # Получаем ID чата
try: try:
# Удаляем все сообщения бота # Удаляем все сообщения бота
for message_id in user_data["message_ids"]: for message_id in user_data["message_ids"]:
try: try:
await bot.delete_message(chat_id=user_data["chat_id"], message_id=message_id) 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: 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"]: for user_message in user_data["user_messages"]:
try: try:
if user_message: if user_message:
await bot.delete_message(chat_id=user_data["chat_id"], message_id=user_message.message_id) 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: 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: 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() @router.message()
async def handle_message(message: Message): async def handle_message(message: Message):
"""Обработчик сообщений от пользователей для проверки ответа.""" """Обработчик сообщений от пользователей для проверки ответа."""
chat_id = message.chat.id # Получаем ID чата
# Получаем статус пользователя в чате (администратор, участник и т.д.) # Получаем статус пользователя в чате (администратор, участник и т.д.)
try: try:
chat_member = await bot.get_chat_member(message.chat.id, message.from_user.id) chat_member = await bot.get_chat_member(message.chat.id, message.from_user.id)
...@@ -432,28 +455,28 @@ async def handle_message(message: Message): ...@@ -432,28 +455,28 @@ async def handle_message(message: Message):
await message.delete() await message.delete()
return return
except AiogramError as e: 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 = 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: try:
await message.delete() 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 return
except Exception as e: 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: try:
await message.delete() 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 return
except Exception as e: 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'): if message.reply_markup and hasattr(message.reply_markup, 'inline_keyboard'):
...@@ -461,19 +484,19 @@ async def handle_message(message: Message): ...@@ -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): if button.url and any(spam_word in button.url.lower() for spam_word in SPAM_KEYWORDS):
try: try:
await message.delete() 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 return
except Exception as e: 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: try:
await message.delete() 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 return
except Exception as e: 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) user_data = active_users.get(message.from_user.id)
...@@ -490,17 +513,17 @@ async def handle_message(message: Message): ...@@ -490,17 +513,17 @@ async def handle_message(message: Message):
user_data["message_ids"].append(correct_message.message_id) # Добавляем в список ID сообщений user_data["message_ids"].append(correct_message.message_id) # Добавляем в список ID сообщений
# Удаляем сообщения после правильного ответа # Удаляем сообщения после правильного ответа
await cleanup_messages(user_data) 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: else:
# Ответ неправильный, добавляем новое сообщение бота # Ответ неправильный, добавляем новое сообщение бота
incorrect_message = await message.reply("Неправильный ответ. Попробуйте еще раз.") incorrect_message = await message.reply("Неправильный ответ. Попробуйте еще раз.")
user_data["message_ids"].append(incorrect_message.message_id) 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: else:
# Если ответ не число # Если ответ не число
invalid_message = await message.reply("Пожалуйста, отправьте числовой ответ.") invalid_message = await message.reply("Пожалуйста, отправьте числовой ответ.")
user_data["message_ids"].append(invalid_message.message_id) 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(): ...@@ -540,5 +563,6 @@ async def main():
await dp.start_polling(bot) await dp.start_polling(bot)
if __name__ == "__main__": if __name__ == "__main__":
SPAM_KEYWORDS = preprocess_spam_keywords(SPAM_KEYWORDS) SPAM_KEYWORDS = preprocess_spam_keywords(SPAM_KEYWORDS, log_chat_id)
asyncio.run(main()) 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