Files
telegram-helper-bot/database/async_db.py
Andrey 3a7b0f6219 Add voice bot welcome tracking functionality
- Implemented methods to check and mark if a user has received a welcome message from the voice bot in both async and synchronous database classes.
- Updated database schema to include a new field for tracking welcome message status.
- Enhanced voice handler to utilize the new tracking methods, improving user interaction flow and engagement metrics.
2025-09-01 19:43:46 +03:00

1040 lines
43 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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:
"""Получение контента поста."""
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:
"""Получение 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:
"""Получение последних пользователей."""
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:
"""Получение пользователей из черного списка."""
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:
"""Получение пользователей для разблокировки сегодня."""
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):
"""Добавление аудио записи."""
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) VALUES (?, ?, ?)",
(file_name, author_id, date_added)
)
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_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
# Методы для voice bot welcome tracking
async def check_voice_bot_welcome_received(self, user_id: int) -> bool:
"""
Проверяет, получал ли пользователь приветственное сообщение от voice_bot.
Args:
user_id (int): Идентификатор пользователя в Telegram.
Returns:
bool: True, если пользователь получал приветствие, False - иначе.
"""
conn = None
try:
conn = await self._get_connection()
async with conn.execute(
"SELECT voice_bot_welcome_received FROM our_users WHERE user_id = ?",
(user_id,)
) as cursor:
result = await cursor.fetchone()
if result:
welcome_received = bool(result[0])
self.logger.info(f"Пользователь {user_id} получал приветствие: {welcome_received}")
return welcome_received
else:
self.logger.info(f"Пользователь {user_id} не найден в базе")
return False
except Exception as e:
self.logger.error(f"Ошибка при проверке получения приветствия: {e}")
return False
finally:
if conn:
await conn.close()
async def mark_voice_bot_welcome_received(self, user_id: int) -> bool:
"""
Отмечает, что пользователь получил приветственное сообщение от voice_bot.
Args:
user_id (int): Идентификатор пользователя в Telegram.
Returns:
bool: True, если обновление прошло успешно, False - в случае ошибки.
"""
conn = None
try:
conn = await self._get_connection()
await conn.execute(
"UPDATE our_users SET voice_bot_welcome_received = 1 WHERE user_id = ?",
(user_id,)
)
await conn.commit()
self.logger.info(f"Пользователь {user_id} отмечен как получивший приветствие")
return True
except Exception as e:
self.logger.error(f"Ошибка при отметке получения приветствия: {e}")
return False
finally:
if conn:
await conn.close()