Enhance private handlers structure and add database support

- Introduced a new `PrivateHandlers` class to encapsulate private message handling logic, improving organization and maintainability.
- Added new dependencies in `requirements.txt` for database support with `aiosqlite`.
- Updated the private handlers to utilize modular components for better separation of concerns and easier testing.
- Implemented error handling and logging for improved robustness in message processing.
This commit is contained in:
2025-08-28 01:41:19 +03:00
parent e17a9f9c29
commit f75e7f82c9
9 changed files with 1830 additions and 451 deletions

995
database/async_db.py Normal file
View File

@@ -0,0 +1,995 @@
import os
import aiosqlite
from datetime import datetime
from typing import Optional, List, Dict, Any, Tuple
from logs.custom_logger import logger
class AsyncBotDB:
"""Асинхронный класс для работы с базой данных."""
def __init__(self, db_path: str):
self.db_path = os.path.abspath(db_path)
self.logger = logger
self.logger.info(f'Инициация асинхронной базы данных: {self.db_path}')
async def _get_connection(self):
"""Получение асинхронного соединения с базой данных."""
try:
# Используем connect вместо connect с контекстным менеджером
conn = await aiosqlite.connect(self.db_path)
# Включаем поддержку внешних ключей
await conn.execute("PRAGMA foreign_keys = ON")
# Включаем WAL режим для лучшей производительности
await conn.execute("PRAGMA journal_mode = WAL")
await conn.execute("PRAGMA synchronous = NORMAL")
await conn.execute("PRAGMA cache_size = 10000")
await conn.execute("PRAGMA temp_store = MEMORY")
return conn
except Exception as e:
self.logger.error(f"Ошибка при получении асинхронного соединения: {e}")
raise
async def create_tables(self):
"""Создание таблиц в базе данных."""
conn = None
try:
conn = await self._get_connection()
# Таблица пользователей
await conn.execute('''
CREATE TABLE IF NOT EXISTS our_users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER UNIQUE NOT NULL,
first_name TEXT NOT NULL,
full_name TEXT NOT NULL,
username TEXT,
is_bot BOOLEAN DEFAULT FALSE,
language_code TEXT DEFAULT 'ru',
emoji TEXT DEFAULT '😊',
has_stickers BOOLEAN DEFAULT FALSE,
date_added TEXT NOT NULL,
date_changed TEXT NOT NULL
)
''')
# Таблица черного списка
await conn.execute('''
CREATE TABLE IF NOT EXISTS blacklist (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER UNIQUE NOT NULL,
user_name TEXT,
message_for_user TEXT,
date_to_unban TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
)
''')
# Таблица сообщений пользователей
await conn.execute('''
CREATE TABLE IF NOT EXISTS user_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message_text TEXT NOT NULL,
user_id INTEGER NOT NULL,
message_id INTEGER UNIQUE NOT NULL,
date TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES our_users (user_id)
)
''')
# Таблица постов из Telegram
await conn.execute('''
CREATE TABLE IF NOT EXISTS post_from_telegram_suggest (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message_id INTEGER UNIQUE NOT NULL,
text TEXT NOT NULL,
author_id INTEGER NOT NULL,
helper_text_message_id INTEGER,
created_at TEXT NOT NULL,
FOREIGN KEY (author_id) REFERENCES our_users (user_id)
)
''')
# Таблица контента постов (создаем ПЕРЕД таблицей связей)
await conn.execute('''
CREATE TABLE IF NOT EXISTS content_post_from_telegram (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message_id INTEGER UNIQUE NOT NULL,
content_name TEXT NOT NULL,
content_type TEXT NOT NULL
)
''')
# Таблица связи сообщений с контентом
await conn.execute('''
CREATE TABLE IF NOT EXISTS message_link_to_content (
id INTEGER PRIMARY KEY AUTOINCREMENT,
post_id INTEGER NOT NULL,
message_id INTEGER NOT NULL,
FOREIGN KEY (post_id) REFERENCES post_from_telegram_suggest (message_id),
FOREIGN KEY (message_id) REFERENCES content_post_from_telegram (message_id)
)
''')
# Таблица администраторов
await conn.execute('''
CREATE TABLE IF NOT EXISTS admins (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER UNIQUE NOT NULL,
role TEXT NOT NULL DEFAULT 'admin',
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES our_users (user_id)
)
''')
# Таблица миграций
await conn.execute('''
CREATE TABLE IF NOT EXISTS migrations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
version INTEGER UNIQUE NOT NULL,
script_name TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
)
''')
# Таблица аудио сообщений
await conn.execute('''
CREATE TABLE IF NOT EXISTS audio_message_reference (
id INTEGER PRIMARY KEY AUTOINCREMENT,
file_name TEXT NOT NULL,
author_id INTEGER NOT NULL,
date_added TEXT NOT NULL,
listen_count INTEGER DEFAULT 0,
file_id TEXT NOT NULL,
FOREIGN KEY (author_id) REFERENCES our_users (user_id)
)
''')
# Таблица прослушивания аудио
await conn.execute('''
CREATE TABLE IF NOT EXISTS listen_audio_users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
file_name TEXT NOT NULL,
user_id INTEGER NOT NULL,
is_listen BOOLEAN DEFAULT FALSE,
FOREIGN KEY (user_id) REFERENCES our_users (user_id)
)
''')
# Таблица для voice bot
await conn.execute('''
CREATE TABLE IF NOT EXISTS audio_moderate (
id INTEGER PRIMARY KEY AUTOINCREMENT,
message_id INTEGER UNIQUE NOT NULL,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES our_users (user_id)
)
''')
await conn.commit()
self.logger.info("Таблицы успешно созданы")
except Exception as e:
self.logger.error(f"Ошибка при создании таблиц: {e}")
raise
finally:
if conn:
await conn.close()
async def user_exists(self, user_id: int) -> bool:
"""Проверка существования пользователя."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute("SELECT 1 FROM our_users WHERE user_id = ?", (user_id,)) as cursor:
result = await cursor.fetchone()
return bool(result)
except Exception as e:
self.logger.error(f"Ошибка при проверке существования пользователя: {e}")
raise
finally:
if conn:
await conn.close()
async def add_new_user(self, user_id: int, first_name: str, full_name: str, username: str = None,
is_bot: bool = False, language_code: str = "ru", emoji: str = "😊"):
"""Добавление нового пользователя."""
conn = None
try:
date_added = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
date_changed = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
conn = await self._get_connection()
await conn.execute(
"INSERT INTO our_users (user_id, first_name, full_name, username, is_bot, "
"language_code, emoji, date_added, date_changed) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
(user_id, first_name, full_name, username, is_bot, language_code, emoji, date_added, date_changed)
)
await conn.commit()
self.logger.info(f"Новый пользователь добавлен: {user_id}")
except Exception as e:
self.logger.error(f"Ошибка при добавлении пользователя: {e}")
raise
finally:
if conn:
await conn.close()
async def get_user_info(self, user_id: int) -> Optional[Dict[str, Any]]:
"""Получение информации о пользователе."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT username, full_name, has_stickers, emoji FROM our_users WHERE user_id = ?",
(user_id,)
) as cursor:
result = await cursor.fetchone()
if result:
return {
'username': result[0],
'full_name': result[1],
'has_stickers': bool(result[2]) if result[2] is not None else False,
'emoji': result[3]
}
return None
except Exception as e:
self.logger.error(f"Ошибка при получении информации о пользователе: {e}")
raise
finally:
if conn:
await conn.close()
async def update_user_date(self, user_id: int):
"""Обновление даты последнего изменения пользователя."""
conn = None
try:
date_changed = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
conn = await self._get_connection()
await conn.execute(
"UPDATE our_users SET date_changed = ? WHERE user_id = ?",
(date_changed, user_id)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при обновлении даты пользователя: {e}")
raise
finally:
if conn:
await conn.close()
async def update_user_info(self, user_id: int, username: str = None, full_name: str = None):
"""Обновление информации о пользователе."""
conn = None
try:
conn = await self._get_connection()
if username and full_name:
await conn.execute(
"UPDATE our_users SET username = ?, full_name = ? WHERE user_id = ?",
(username, full_name, user_id)
)
elif username:
await conn.execute(
"UPDATE our_users SET username = ? WHERE user_id = ?",
(username, user_id)
)
elif full_name:
await conn.execute(
"UPDATE our_users SET full_name = ? WHERE user_id = ?",
(full_name, user_id)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при обновлении информации о пользователе: {e}")
raise
finally:
if conn:
await conn.close()
async def update_user_emoji(self, user_id: int, emoji: str):
"""Обновление эмодзи пользователя."""
conn = None
try:
conn = await self._get_connection()
await conn.execute(
"UPDATE our_users SET emoji = ? WHERE user_id = ?",
(emoji, user_id)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при обновлении эмодзи: {e}")
raise
finally:
if conn:
await conn.close()
async def get_user_emoji(self, user_id: int) -> Optional[str]:
"""Получение эмодзи пользователя."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT emoji FROM our_users WHERE user_id = ?", (user_id,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении эмодзи: {e}")
raise
finally:
if conn:
await conn.close()
async def check_emoji_exists(self, emoji: str) -> bool:
"""Проверка существования эмодзи."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT 1 FROM our_users WHERE emoji = ?", (emoji,)
) as cursor:
result = await cursor.fetchone()
return bool(result)
except Exception as e:
self.logger.error(f"Ошибка при проверке эмодзи: {e}")
raise
finally:
if conn:
await conn.close()
async def update_stickers_info(self, user_id: int):
"""Обновление информации о стикерах."""
conn = None
try:
conn = await self._get_connection()
await conn.execute(
"UPDATE our_users SET has_stickers = 1 WHERE user_id = ?",
(user_id,)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при обновлении информации о стикерах: {e}")
raise
finally:
if conn:
await conn.close()
async def get_stickers_info(self, user_id: int) -> bool:
"""Получение информации о стикерах."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT has_stickers FROM our_users WHERE user_id = ?", (user_id,)
) as cursor:
result = await cursor.fetchone()
return bool(result[0]) if result and result[0] is not None else False
except Exception as e:
self.logger.error(f"Ошибка при получении информации о стикерах: {e}")
return False
finally:
if conn:
await conn.close()
async def add_message(self, message_text: str, user_id: int, message_id: int):
"""Добавление сообщения пользователя."""
conn = None
try:
date = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
conn = await self._get_connection()
await conn.execute(
"INSERT INTO user_messages (message_text, user_id, message_id, date) VALUES (?, ?, ?, ?)",
(message_text, user_id, message_id, date)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при добавлении сообщения: {e}")
raise
finally:
if conn:
await conn.close()
async def add_post(self, message_id: int, text: str, author_id: int):
"""Добавление поста."""
conn = None
try:
created_at = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
conn = await self._get_connection()
await conn.execute(
"INSERT INTO post_from_telegram_suggest (message_id, text, author_id, created_at) VALUES (?, ?, ?, ?)",
(message_id, text, author_id, created_at)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при добавлении поста: {e}")
raise
finally:
if conn:
await conn.close()
async def update_helper_message(self, message_id: int, helper_message_id: int):
"""Обновление helper сообщения."""
conn = None
try:
conn = await self._get_connection()
await conn.execute(
"UPDATE post_from_telegram_suggest SET helper_text_message_id = ? WHERE message_id = ?",
(helper_message_id, message_id)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при обновлении helper сообщения: {e}")
raise
finally:
if conn:
await conn.close()
async def add_post_content(self, post_id: int, message_id: int, content_name: str, content_type: str):
"""Добавление контента поста."""
conn = None
try:
conn = await self._get_connection()
# Сначала добавляем связь
await conn.execute(
"INSERT INTO message_link_to_content (post_id, message_id) VALUES (?, ?)",
(post_id, message_id)
)
# Затем добавляем контент
await conn.execute(
"INSERT INTO content_post_from_telegram (message_id, content_name, content_type) VALUES (?, ?, ?)",
(message_id, content_name, content_type)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при добавлении контента поста: {e}")
raise
finally:
if conn:
await conn.close()
async def get_post_content(self, last_post_id: int) -> List[Tuple[str, str]]:
"""Получение контента поста."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute("""
SELECT cpft.content_name, cpft.content_type
FROM post_from_telegram_suggest pft
JOIN message_link_to_content mltc ON pft.message_id = mltc.post_id
JOIN content_post_from_telegram cpft ON cpft.message_id = mltc.message_id
WHERE pft.helper_text_message_id = ?
""", (last_post_id,)) as cursor:
return await cursor.fetchall()
except Exception as e:
self.logger.error(f"Ошибка при получении контента поста: {e}")
raise
finally:
if conn:
await conn.close()
async def get_post_text(self, last_post_id: int) -> Optional[str]:
"""Получение текста поста."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT text FROM post_from_telegram_suggest WHERE helper_text_message_id = ?",
(last_post_id,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении текста поста: {e}")
raise
finally:
if conn:
await conn.close()
async def get_post_ids(self, last_post_id: int) -> List[int]:
"""Получение ID постов."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute("""
SELECT mltc.message_id
FROM post_from_telegram_suggest pft
JOIN message_link_to_content mltc ON pft.message_id = mltc.post_id
WHERE pft.helper_text_message_id = ?
""", (last_post_id,)) as cursor:
result = await cursor.fetchall()
return [row[0] for row in result]
except Exception as e:
self.logger.error(f"Ошибка при получении ID постов: {e}")
raise
finally:
if conn:
await conn.close()
async def get_author_id_by_message(self, message_id: int) -> Optional[int]:
"""Получение ID автора по message_id."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT author_id FROM post_from_telegram_suggest WHERE message_id = ?",
(message_id,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении ID автора: {e}")
raise
finally:
if conn:
await conn.close()
async def get_author_id_by_helper_message(self, helper_message_id: int) -> Optional[int]:
"""Получение ID автора по helper_message_id."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT author_id FROM post_from_telegram_suggest WHERE helper_text_message_id = ?",
(helper_message_id,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении ID автора по helper сообщению: {e}")
raise
finally:
if conn:
await conn.close()
async def get_last_users(self, limit: int = 30) -> List[Tuple[str, int]]:
"""Получение последних пользователей."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT full_name, user_id FROM our_users ORDER BY date_changed DESC LIMIT ?",
(limit,)
) as cursor:
return await cursor.fetchall()
except Exception as e:
self.logger.error(f"Ошибка при получении последних пользователей: {e}")
raise
finally:
if conn:
await conn.close()
async def get_user_by_message_id(self, message_id: int) -> Optional[int]:
"""Получение пользователя по message_id."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT user_id FROM user_messages WHERE message_id = ?",
(message_id,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении пользователя по message_id: {e}")
raise
finally:
if conn:
await conn.close()
# Методы для работы с черным списком
async def add_to_blacklist(self, user_id: int, user_name: str = None,
message_for_user: str = None, date_to_unban: str = None):
"""Добавление пользователя в черный список."""
conn = None
try:
conn = await self._get_connection()
await conn.execute(
"INSERT INTO blacklist (user_id, user_name, message_for_user, date_to_unban) VALUES (?, ?, ?, ?)",
(user_id, user_name, message_for_user, date_to_unban)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при добавлении в черный список: {e}")
raise
finally:
if conn:
await conn.close()
async def remove_from_blacklist(self, user_id: int) -> bool:
"""Удаление пользователя из черного списка."""
conn = None
try:
conn = await self._get_connection()
await conn.execute("DELETE FROM blacklist WHERE user_id = ?", (user_id,))
await conn.commit()
return True
except Exception as e:
self.logger.error(f"Ошибка при удалении из черного списка: {e}")
return False
finally:
if conn:
await conn.close()
async def check_blacklist(self, user_id: int) -> bool:
"""Проверка пользователя в черном списке."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT 1 FROM blacklist WHERE user_id = ?", (user_id,)
) as cursor:
result = await cursor.fetchone()
return bool(result)
except Exception as e:
self.logger.error(f"Ошибка при проверке черного списка: {e}")
raise
finally:
if conn:
await conn.close()
async def get_blacklist_users(self, offset: int = 0, limit: int = 10) -> List[Tuple[str, int, str, str]]:
"""Получение пользователей из черного списка."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT user_name, user_id, message_for_user, date_to_unban FROM blacklist LIMIT ?, ?",
(offset, limit)
) as cursor:
return await cursor.fetchall()
except Exception as e:
self.logger.error(f"Ошибка при получении пользователей из черного списка: {e}")
raise
finally:
if conn:
await conn.close()
async def get_blacklist_count(self) -> int:
"""Получение количества пользователей в черном списке."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute("SELECT COUNT(*) FROM blacklist") as cursor:
result = await cursor.fetchone()
return result[0] if result else 0
except Exception as e:
self.logger.error(f"Ошибка при получении количества пользователей в черном списке: {e}")
raise
finally:
if conn:
await conn.close()
async def get_users_for_unban_today(self, date_to_unban: str) -> List[Tuple[int, str]]:
"""Получение пользователей для разблокировки сегодня."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT user_id, user_name FROM blacklist WHERE date_to_unban = ?",
(date_to_unban,)
) as cursor:
return await cursor.fetchall()
except Exception as e:
self.logger.error(f"Ошибка при получении пользователей для разблокировки: {e}")
raise
finally:
if conn:
await conn.close()
# Методы для работы с администраторами
async def add_admin(self, user_id: int, role: str = "admin"):
"""Добавление администратора."""
conn = None
try:
conn = await self._get_connection()
await conn.execute(
"INSERT INTO admins (user_id, role) VALUES (?, ?)",
(user_id, role)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при добавлении администратора: {e}")
raise
finally:
if conn:
await conn.close()
async def remove_admin(self, user_id: int):
"""Удаление администратора."""
conn = None
try:
conn = await self._get_connection()
await conn.execute("DELETE FROM admins WHERE user_id = ?", (user_id,))
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при удалении администратора: {e}")
raise
finally:
if conn:
await conn.close()
async def is_admin(self, user_id: int) -> bool:
"""Проверка, является ли пользователь администратором."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT 1 FROM admins WHERE user_id = ?", (user_id,)
) as cursor:
result = await cursor.fetchone()
return bool(result)
except Exception as e:
self.logger.error(f"Ошибка при проверке прав администратора: {e}")
return False
finally:
if conn:
await conn.close()
# Методы для работы с аудио
async def add_audio_record(self, file_name: str, author_id: int, file_id: str):
"""Добавление аудио записи."""
conn = None
try:
date_added = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
conn = await self._get_connection()
await conn.execute(
"INSERT INTO audio_message_reference (file_name, author_id, date_added, file_id) VALUES (?, ?, ?, ?)",
(file_name, author_id, date_added, file_id)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при добавлении аудио записи: {e}")
raise
finally:
if conn:
await conn.close()
async def get_last_audio_date(self) -> Optional[str]:
"""Получение даты последнего аудио."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT date_added FROM audio_message_reference ORDER BY date_added DESC LIMIT 1"
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении даты последнего аудио: {e}")
raise
finally:
if conn:
await conn.close()
async def get_user_audio_records(self, user_id: int) -> bool:
"""Проверка наличия аудио записей у пользователя."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT 1 FROM audio_message_reference WHERE author_id = ? LIMIT 1",
(user_id,)
) as cursor:
result = await cursor.fetchone()
return bool(result)
except Exception as e:
self.logger.error(f"Ошибка при проверке аудио записей пользователя: {e}")
raise
finally:
if conn:
await conn.close()
async def get_audio_file_id(self, user_id: int) -> Optional[str]:
"""Получение file_id последнего аудио пользователя."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT file_id FROM audio_message_reference WHERE author_id = ? ORDER BY date_added DESC LIMIT 1",
(user_id,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении file_id аудио: {e}")
raise
finally:
if conn:
await conn.close()
async def get_audio_file_name(self, user_id: int) -> Optional[str]:
"""Получение имени файла последнего аудио пользователя."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT file_name FROM audio_message_reference WHERE author_id = ? ORDER BY date_added DESC LIMIT 1",
(user_id,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении имени файла аудио: {e}")
raise
finally:
if conn:
await conn.close()
async def check_audio_listened(self, user_id: int) -> List[str]:
"""Проверка прослушанных аудио пользователем."""
conn = None
try:
conn = await self._get_connection()
# Получаем все аудио файлы
async with conn.execute(
"SELECT file_name FROM audio_message_reference WHERE author_id != ?",
(user_id,)
) as cursor:
all_audio = await cursor.fetchall()
# Получаем прослушанные пользователем
async with conn.execute("""
SELECT l.file_name
FROM audio_message_reference a
LEFT JOIN listen_audio_users l ON l.file_name = a.file_name
WHERE l.user_id = ? AND l.file_name IS NOT NULL
""", (user_id,)) as cursor:
listened_audio = await cursor.fetchall()
# Находим непрослушанные
all_audio_names = {row[0] for row in all_audio}
listened_names = {row[0] for row in listened_audio}
return list(all_audio_names - listened_names)
except Exception as e:
self.logger.error(f"Ошибка при проверке прослушанных аудио: {e}")
raise
finally:
if conn:
await conn.close()
async def mark_audio_listened(self, file_name: str, user_id: int):
"""Отметка аудио как прослушанного."""
conn = None
try:
conn = await self._get_connection()
await conn.execute(
"INSERT INTO listen_audio_users (file_name, user_id, is_listen) VALUES (?, ?, ?)",
(file_name, user_id, 1)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при отметке аудио как прослушанного: {e}")
raise
finally:
if conn:
await conn.close()
async def clear_user_audio_listen(self, user_id: int):
"""Очистка данных о прослушивании аудио пользователем."""
conn = None
try:
conn = await self._get_connection()
await conn.execute(
"DELETE FROM listen_audio_users WHERE user_id = ?",
(user_id,)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при очистке данных о прослушивании: {e}")
raise
finally:
if conn:
await conn.close()
async def get_user_by_audio_file(self, file_name: str) -> Optional[int]:
"""Получение пользователя по имени аудио файла."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT author_id FROM audio_message_reference WHERE file_name = ?",
(file_name,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении пользователя по имени файла: {e}")
raise
finally:
if conn:
await conn.close()
async def get_audio_date(self, file_name: str) -> Optional[str]:
"""Получение даты аудио файла."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT date_added FROM audio_message_reference WHERE file_name = ?",
(file_name,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении даты аудио файла: {e}")
raise
finally:
if conn:
await conn.close()
# Методы для voice bot
async def set_voice_bot_message(self, message_id: int, user_id: int):
"""Установка связи message_id и user_id для voice bot."""
conn = None
try:
conn = await self._get_connection()
await conn.execute(
"INSERT INTO audio_moderate (message_id, user_id) VALUES (?, ?)",
(message_id, user_id)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при установке связи для voice bot: {e}")
raise
finally:
if conn:
await conn.close()
async def get_voice_bot_user(self, message_id: int) -> Optional[int]:
"""Получение пользователя voice bot по message_id."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT user_id FROM audio_moderate WHERE message_id = ?",
(message_id,)
) as cursor:
result = await cursor.fetchone()
return result[0] if result else None
except Exception as e:
self.logger.error(f"Ошибка при получении пользователя voice bot: {e}")
raise
finally:
if conn:
await conn.close()
# Методы для миграций
async def get_migration_version(self) -> int:
"""Получение текущей версии миграции."""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT version FROM migrations ORDER BY version DESC LIMIT 1"
) as cursor:
result = await cursor.fetchone()
return result[0] if result else 0
except Exception as e:
self.logger.error(f"Ошибка при получении версии миграции: {e}")
raise
finally:
if conn:
await conn.close()
async def update_migration_version(self, version: int, script_name: str):
"""Обновление версии миграции."""
conn = None
try:
created_at = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
conn = await self._get_connection()
await conn.execute(
"INSERT INTO migrations (version, script_name, created_at) VALUES (?, ?, ?)",
(version, script_name, created_at)
)
await conn.commit()
except Exception as e:
self.logger.error(f"Ошибка при обновлении версии миграции: {e}")
raise
finally:
if conn:
await conn.close()
async def close(self):
"""Закрытие соединений."""
# Соединения закрываются в каждом методе
pass