diff --git a/database/db.py b/database/db.py index ce6621d..999b796 100644 --- a/database/db.py +++ b/database/db.py @@ -100,27 +100,8 @@ class BotDB: finally: self.close() - # TODO: Deprecated. Остался только в voice боте, удалить и оттуда - def get_error_message_from_db(self, id: int): - """ - @deprecated - Функция для запроса к базе данных и получения сообщений ошибки. В аргументы передаются: - id - идентификатор ошибки - """ - # Подключаемся к базе - try: - self.connect() - self.cursor.execute(f"SELECT * FROM error_messages WHERE id=?", (id,)) - response_from_database = str(self.cursor.fetchone()[1]) - return response_from_database - except sqlite3.Error as error: - self.logger.error(f"Ошибка при получении сообщения об ошибка voice_bot: {error}") - finally: - self.close() - def add_new_user_in_db(self, user_id: int, first_name: str, full_name: str, username: str, is_bot: bool, - language_code: str, date_added: str, - date_changed: str): + language_code: str, emoji: str, date_added: str, date_changed: str): """ Добавляет нового пользователя в базу данных. @@ -131,6 +112,7 @@ class BotDB: username (str): Username пользователя в Telegram. is_bot (bool): Флаг, указывающий, является ли пользователь ботом. language_code (str): Код языка пользователя. + emoji (str): Эмодзи закрепленная за пользователем date_added (str): Дата добавления пользователя в базу. date_changed (str): Дата последнего изменения данных пользователя. @@ -142,11 +124,12 @@ class BotDB: try: self.connect() self.cursor.execute("INSERT INTO 'our_users' ('user_id', 'first_name', 'full_name', 'username', 'is_bot', " - "'language_code', 'date_added', 'date_changed') VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + "'language_code', 'emoji', 'date_added', 'date_changed') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", (user_id, first_name, full_name, - username, is_bot, language_code, date_added, date_changed)) + username, is_bot, language_code, emoji, date_added, date_changed)) self.conn.commit() - self.logger.info(f"Новый пользователь добавлен в базу: user_id={user_id}, first_name={first_name}") + self.logger.info( + f"Новый пользователь добавлен в базу: user_id={user_id}, first_name={first_name}, emoji={emoji}") return None except sqlite3.Error as error: self.logger.error(f"Ошибка при добавлении пользователя в базу: {error}. " @@ -675,15 +658,15 @@ class BotDB: def update_date_for_user(self, date: str, user_id: int): """ #TODO: Не возвращается ошибка sqlite3. Error. Тест не перехватывает. Возвращается no such table: our_users - Обновляет дату последнего изменения данных пользователя в базе. + Обновляет дату последнего изменения данных пользователя в базе Args: - date (str): Новая дата изменения. - user_id (int): Идентификатор пользователя в Telegram. + date (str): Новая дата изменения + user_id (int): Идентификатор пользователя в Telegram Returns: - None: Если обновление прошло успешно. - sqlite3. Error: Если произошла ошибка при выполнении запроса. + None: Если обновление прошло успешно + sqlite3. Error: Если произошла ошибка при выполнении запроса """ self.logger.info(f"Запуск функции update_date_for_user: user_id={user_id}, date={date}") try: @@ -699,6 +682,106 @@ class BotDB: finally: self.close() + def check_emoji(self, emoji: str): + """ + Проверяет, есть ли уже такой emoji в таблице. + + Args: + emoji: emoji для проверки. + + Returns: + True, если эмодзи уже есть, иначе False. + + Raises: + None: В случае ошибки возвращается None + """ + self.logger.info(f"Запуск функции check_emoji: emoji={emoji}") + try: + self.connect() + self.cursor.execute("SELECT 1 FROM our_users WHERE emoji = ?", (emoji,)) + result = self.cursor.fetchone() + return bool(result) + except sqlite3.Error as error: + self.logger.error(f"Ошибка проверки эмодзи в базе: {error}") + return None + finally: + self.close() + + def update_emoji_for_user(self, user_id: int, emoji: str): + """ + Обновляет эмодзи для пользователя в базе если его ранее не было установлено + + Args: + user_id (int): Идентификатор пользователя в Telegram + emoji (str): Эмодзи пользователя + + Returns: + None: Если обновление прошло успешно + sqlite3. Error: Если произошла ошибка при выполнении запроса + """ + self.logger.info(f"Запуск функции update_date_for_user: user_id={user_id}, emoji={emoji}") + try: + self.connect() + self.cursor.execute("UPDATE our_users SET emoji = ? WHERE user_id = ?", + (emoji, user_id,)) + self.conn.commit() + self.logger.info(f"Эмоджи обновлен для пользователя: user_id={user_id}") + return None + except sqlite3.Error as error: + self.logger.error(f"Ошибка обновления эмодзи для пользователя: {error}") + return error + finally: + self.close() + + def check_emoji_for_user(self, user_id: int): + """ + Проверяет, есть ли уже у пользователя назначенный emoji. + + Args: + user_id: user_id пользователя. + + Returns: + True, если эмодзи такого нет, иначе False. + + Raises: + None: В случае ошибки возвращается None + """ + self.logger.info(f"Запуск функции check_emoji_for_user: user_id={user_id}") + try: + self.connect() + self.cursor.execute("SELECT emoji FROM our_users WHERE user_id = ?", (user_id,)) + result = self.cursor.fetchone()[0] + return result + except sqlite3.Error as error: + self.logger.error(f"Ошибка проверки эмодзи в базе: {error}") + return None + finally: + self.close() + + def refresh_listen_audio(self, user_id: int): + """ + Очищает всю информацию о прослушанных аудио пользователем + + Args: + user_id: user_id пользователя. + + Returns: + None - если все очищено успешно + + Raises: + error: В случае ошибки возвращается error + """ + self.logger.info(f"Запуск функции check_emoji_for_user: user_id={user_id}") + try: + self.connect() + self.cursor.execute("DELETE FROM listen_audio_users WHERE user_id = ?", (user_id,)) + return None + except sqlite3.Error as error: + self.logger.error(f"Ошибка проверки эмодзи в базе: {error}") + return error + finally: + self.close() + def is_admin(self, user_id: int): """ Проверяет, является ли пользователь администратором. @@ -719,7 +802,7 @@ class BotDB: result = self.cursor.fetchone() return bool(result) except sqlite3.Error as error: - self.logger.error(f"Ошибка добавления сообщения в базу данных: {error}") + self.logger.error(f"Ошибка проверки прав пользователя админа: {error}") return None finally: self.close() diff --git a/helper_bot/handlers/private/private_handlers.py b/helper_bot/handlers/private/private_handlers.py index d0ab731..22b2381 100644 --- a/helper_bot/handlers/private/private_handlers.py +++ b/helper_bot/handlers/private/private_handlers.py @@ -17,8 +17,9 @@ from helper_bot.middlewares.blacklist_middleware import BlacklistMiddleware from helper_bot.utils import messages from helper_bot.utils.base_dependency_factory import BaseDependencyFactory from helper_bot.utils.helper_func import get_first_name, get_text_message, send_text_message, send_photo_message, \ - send_media_group_message_to_private_chat, prepare_media_group_from_middlewares, check_username_and_full_name, \ - send_video_message, send_video_note_message, send_audio_message, send_voice_message, add_in_db_media + send_media_group_message_to_private_chat, prepare_media_group_from_middlewares, send_video_message, \ + send_video_note_message, send_audio_message, send_voice_message, add_in_db_media, \ + update_user_info, check_user_emoji from logs.custom_logger import logger private_router = Router() @@ -39,6 +40,24 @@ TEST = bdf.settings['Settings']['test'] BotDB = bdf.get_db() +@private_router.message( + ChatTypeFilter(chat_type=["private"]), + Command("restart") +) +async def handle_restart_message(message: types.Message, state: FSMContext): + try: + markup = get_reply_keyboard(BotDB, message.from_user.id) + await message.forward(chat_id=GROUP_FOR_LOGS) + await state.set_state("START") + await update_user_info('love', message) + check_user_emoji(message.from_user.id) + await message.answer('Я перезапущен!', reply_markup=markup, parse_mode='HTML') + except Exception as e: + logger.error(f"Произошла ошибка handle_restart_message. Ошибка:{str(e)}") + await message.bot.send_message(chat_id=IMPORTANT_LOGS, + text=f"Произошла ошибка handle_restart_message: {str(e)}\n\nTraceback:\n{traceback.format_exc()}") + + @private_router.message( ChatTypeFilter(chat_type=["private"]), Command("start") @@ -50,27 +69,8 @@ BotDB = bdf.get_db() async def handle_start_message(message: types.Message, state: FSMContext): try: await message.forward(chat_id=GROUP_FOR_LOGS) - full_name = message.from_user.full_name - username = message.from_user.username - first_name = get_first_name(message) - is_bot = message.from_user.is_bot - language_code = message.from_user.language_code - user_id = message.from_user.id - current_date = datetime.now() - date = current_date.strftime("%Y-%m-%d %H:%M:%S") - if not BotDB.user_exists(user_id): - BotDB.add_new_user_in_db(user_id, first_name, full_name, username, is_bot, language_code, date, - date) - else: - is_need_update = check_username_and_full_name(user_id, username, full_name) - if is_need_update: - BotDB.update_username_and_full_name(user_id, username, full_name) - await message.answer( - f"Давно не виделись! Вижу что ты изменился;) Теперь буду звать тебя: {full_name} и ник @{username}") - await message.bot.send_message(chat_id=GROUP_FOR_LOGS, - text=f'Для пользователя: {user_id} обновлены данные в БД.\nНовое имя: {full_name}\nНовый ник:{username}') - sleep(1) - BotDB.update_date_for_user(date, user_id) + await update_user_info('love', message) + check_user_emoji(message.from_user.id) await state.set_state("START") logger.info( f"Формирование приветственного сообщения для пользователя. Сообщение: {message.text} " diff --git a/helper_bot/keyboards/__pycache__/__init__.cpython-312.pyc b/helper_bot/keyboards/__pycache__/__init__.cpython-312.pyc index f1c797e..3e943c6 100644 Binary files a/helper_bot/keyboards/__pycache__/__init__.cpython-312.pyc and b/helper_bot/keyboards/__pycache__/__init__.cpython-312.pyc differ diff --git a/helper_bot/utils/__pycache__/base_dependency_factory.cpython-312.pyc b/helper_bot/utils/__pycache__/base_dependency_factory.cpython-312.pyc index f818b5d..89519d6 100644 Binary files a/helper_bot/utils/__pycache__/base_dependency_factory.cpython-312.pyc and b/helper_bot/utils/__pycache__/base_dependency_factory.cpython-312.pyc differ diff --git a/helper_bot/utils/__pycache__/helper_func.cpython-312.pyc b/helper_bot/utils/__pycache__/helper_func.cpython-312.pyc index 52f8de6..d158870 100644 Binary files a/helper_bot/utils/__pycache__/helper_func.cpython-312.pyc and b/helper_bot/utils/__pycache__/helper_func.cpython-312.pyc differ diff --git a/helper_bot/utils/__pycache__/state.cpython-312.pyc b/helper_bot/utils/__pycache__/state.cpython-312.pyc index 9b45a9d..79328a9 100644 Binary files a/helper_bot/utils/__pycache__/state.cpython-312.pyc and b/helper_bot/utils/__pycache__/state.cpython-312.pyc differ diff --git a/helper_bot/utils/helper_func.py b/helper_bot/utils/helper_func.py index 185308f..42b5d09 100644 --- a/helper_bot/utils/helper_func.py +++ b/helper_bot/utils/helper_func.py @@ -1,7 +1,10 @@ import html import os +import random from datetime import datetime, timedelta +from time import sleep +import emoji from aiogram import types from aiogram.types import InputMediaPhoto, FSInputFile, InputMediaVideo, InputMediaAudio @@ -9,6 +12,9 @@ from helper_bot.utils.base_dependency_factory import BaseDependencyFactory from logs.custom_logger import logger bdf = BaseDependencyFactory() +GROUP_FOR_LOGS = bdf.settings['Telegram']['group_for_logs'] + +emoji_list = list(emoji.EMOJI_DATA.keys()) BotDB = bdf.get_db() @@ -387,3 +393,50 @@ def unban_notifier(self): # Отправка сообщения в канал self.bot.send_message(self.GROUP_FOR_MESSAGE, message) + + +async def update_user_info(source: str, message: types.Message): + # Собираем данные + full_name = message.from_user.full_name + username = message.from_user.username + first_name = get_first_name(message) + is_bot = message.from_user.is_bot + language_code = message.from_user.language_code + user_id = message.from_user.id + current_date = datetime.now() + date = current_date.strftime("%Y-%m-%d %H:%M:%S") + # Выбираем эмодзю, пробегаемся циклом и смотрим что в базе такого еще не было + user_emoji = get_random_emoji() + + if not BotDB.user_exists(user_id): + BotDB.add_new_user_in_db(user_id, first_name, full_name, username, is_bot, language_code, user_emoji, date, + date) + else: + is_need_update = check_username_and_full_name(user_id, username, full_name) + if is_need_update: + BotDB.update_username_and_full_name(user_id, username, full_name) + if source != 'voice': + await message.answer( + f"Давно не виделись! Вижу что ты изменился;) Теперь буду звать тебя: {full_name}") + await message.bot.send_message(chat_id=GROUP_FOR_LOGS, + text=f'Для пользователя: {user_id} обновлены данные в БД.\nНовое имя: {full_name}\nНовый ник:{username}. Новый эмодзи:{user_emoji}') + sleep(1) + BotDB.update_date_for_user(date, user_id) + + +def check_user_emoji(user_id: int): + if not BotDB.check_emoji_for_user(user_id=user_id): + user_emoji = get_random_emoji() + BotDB.update_emoji_for_user(user_id=user_id, emoji=user_emoji) + + +def get_random_emoji(): + attempts = 0 + while attempts < 100: + print(attempts) + user_emoji = random.choice(emoji_list) + if not BotDB.check_emoji(user_emoji): + return user_emoji + attempts += 1 + logger.error("Не удалось найти уникальный эмодзи после нескольких попыток.") + return None diff --git a/tests/test_db.py b/tests/test_db.py index 56489a8..c901f37 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -252,12 +252,13 @@ def test_add_new_user_in_db(bot): username = "@petr_ivanov" is_bot = False language_code = "ru" + emoji = '🦀' date_added = "2024-07-09" date_changed = "2024-07-09" # Вызываем функцию add_new_user_in_db bot.add_new_user_in_db( - user_id, first_name, full_name, username, is_bot, language_code, date_added, date_changed + user_id, first_name, full_name, username, is_bot, language_code, emoji, date_added, date_changed ) # Проверяем наличие записи в базе данных @@ -285,7 +286,7 @@ def test_add_new_user_in_db_duplicate_user_id(bot, setup_db): # Попытка добавить пользователя с тем же user_id with pytest.raises(sqlite3.IntegrityError): bot.add_new_user_in_db( - user_id, "Марина", "Марина Альфредовна", "marina", False, "bg", "2024-07-09", "2024-07-09" + user_id, "Марина", "Марина Альфредовна", "marina", False, "bg", "🦀", "2024-07-09", "2024-07-09" ) @@ -297,12 +298,13 @@ def test_add_new_user_in_db_empty_first_name(bot): username = "@boris" is_bot = False language_code = "fr" + emoji = "🦀" date_added = "2024-07-09" date_changed = "2024-07-09" # Вызываем функцию add_new_user_in_db bot.add_new_user_in_db( - user_id, first_name, full_name, username, is_bot, language_code, date_added, date_changed + user_id, first_name, full_name, username, is_bot, language_code, emoji, date_added, date_changed ) # Проверяем наличие записи в базе данных diff --git a/voice_bot/voice_handler/__init__.py b/voice_bot/handlers/__init__.py similarity index 100% rename from voice_bot/voice_handler/__init__.py rename to voice_bot/handlers/__init__.py diff --git a/voice_bot/voice_handler/voice_handler.py b/voice_bot/handlers/voice_handler.py similarity index 93% rename from voice_bot/voice_handler/voice_handler.py rename to voice_bot/handlers/voice_handler.py index 75f9205..bdd385d 100644 --- a/voice_bot/voice_handler/voice_handler.py +++ b/voice_bot/handlers/voice_handler.py @@ -9,7 +9,9 @@ from aiogram.fsm.context import FSMContext from aiogram.types import FSInputFile from helper_bot.filters.main import ChatTypeFilter +from helper_bot.middlewares.blacklist_middleware import BlacklistMiddleware from helper_bot.utils.base_dependency_factory import BaseDependencyFactory +from helper_bot.utils.helper_func import update_user_info, check_user_emoji from logs.custom_logger import logger from voice_bot.keyboards.keyboards import get_main_keyboard from voice_bot.utils.helper_func import last_message @@ -25,6 +27,7 @@ LOGS = bdf.settings['Settings']['logs'] TEST = bdf.settings['Settings']['test'] BotDB = bdf.get_db() +voice_router.message.middleware(BlacklistMiddleware()) @voice_router.message( @@ -33,6 +36,8 @@ BotDB = bdf.get_db() ) async def restart_function(message: types.Message, state: FSMContext): await message.forward(chat_id=GROUP_FOR_LOGS) + await update_user_info('voice', message) + check_user_emoji(message.from_user.id) markup = get_main_keyboard() await message.answer(text='Я перезапущен!', reply_markup=markup) @@ -45,9 +50,11 @@ async def restart_function(message: types.Message, state: FSMContext): ) async def help_function(message: types.Message, state: FSMContext): await message.forward(chat_id=GROUP_FOR_LOGS) + await update_user_info('voice', message) + check_user_emoji(message.from_user.id) await message.answer( text='Скорее всего ответы на твои вопросы есть здесь, ознакомься: https://telegra.ph/Instrukciya-k-botu-Golosa-Bijsk-10-11-2' - '\nЕсли это не поможет, пиши в тг: @Kerrad1', disable_web_page_preview=not PREVIEW_LINK) + '\nЕсли это не поможет, пиши в личку: @Kerrad1', disable_web_page_preview=not PREVIEW_LINK) await state.set_state('START') @@ -58,6 +65,8 @@ async def help_function(message: types.Message, state: FSMContext): async def start(message: types.Message, state: FSMContext): await state.set_state("START") await message.forward(chat_id=GROUP_FOR_LOGS) + await update_user_info('voice', message) + check_user_emoji(message.from_user.id) try: name_stick_hello = list(Path('Stick').rglob('Hello_*')) random_stick_hello = random.choice(name_stick_hello) @@ -153,12 +162,6 @@ async def save_voice_message(message: types.Message, state: FSMContext): # Сохраняем в базку BotDB.add_audio_record(file_name, author_id, date_added, 0, file_id) - # Сохраняем файл на сервер - # file_info = message.bot.get_file(file_id=message.voice.file_id) - # downloaded_file = message.bot.download_file(file_path=file_info.file_path) - # with open(f'voice_users/{file_name}.ogg', 'wb') as new_file: - # new_file.write(downloaded_file) - file_info = await message.bot.get_file(file_id=message.voice.file_id) downloaded_file = await message.bot.download_file(file_path=file_info.file_path) with open(f'voice_users/{file_name}.ogg', 'wb') as new_file: @@ -181,12 +184,11 @@ async def standup_listen_audio(message: types.Message, state: FSMContext): check_audio = BotDB.check_listen_audio(user_id=message.from_user.id) list_audio = list(check_audio) markup = get_main_keyboard() - await message.forward(chat_id=GROUP_FOR_LOGS) if not list_audio: await message.answer(text='Прости, ты прослушал все аудио😔. Возвращайся позже, возможно наша база пополнится', reply_markup=markup) message_with_date = last_message() - message.send_message(chat_id=message.chat.id, text=message_with_date, parse_mode="html") + await message.answer(text=message_with_date, parse_mode="html") else: number_element = random.randint(0, len(list_audio) - 1) audio_for_user = check_audio[number_element] @@ -196,5 +198,5 @@ async def standup_listen_audio(message: types.Message, state: FSMContext): # Маркируем сообщение как прослушанное BotDB.mark_listened_audio(audio_for_user, user_id=message.from_user.id) await message.bot.send_voice(message.chat.id, voice=voice, reply_markup=markup) - await message.forward(chat_id=GROUP_FOR_LOGS) + await message.answer(text=f'Осталось непрослушанных: {len(check_audio)}', reply_markup=markup) await state.set_state('START') diff --git a/voice_bot/main.py b/voice_bot/main.py index 199d2f7..c2990f2 100644 --- a/voice_bot/main.py +++ b/voice_bot/main.py @@ -3,7 +3,7 @@ from aiogram.client.default import DefaultBotProperties from aiogram.fsm.storage.memory import MemoryStorage from aiogram.fsm.strategy import FSMStrategy -from voice_bot.voice_handler.voice_handler import voice_router +from voice_bot.handlers.voice_handler import voice_router async def start_bot(bdf):