Enhance bot functionality and refactor database interactions

- Added `ca-certificates` installation to Dockerfile for improved network security.
- Updated health check command in Dockerfile to include better timeout handling.
- Refactored `run_helper.py` to implement proper signal handling and logging during shutdown.
- Transitioned database operations to an asynchronous model in `async_db.py`, improving performance and responsiveness.
- Updated database schema to support new foreign key relationships and optimized indexing for better query performance.
- Enhanced various bot handlers to utilize async database methods, improving overall efficiency and user experience.
- Removed obsolete database and fix scripts to streamline the project structure.
This commit is contained in:
2025-09-02 18:22:02 +03:00
parent 013892dcb7
commit 1c6a37bc12
59 changed files with 5682 additions and 4204 deletions

View File

@@ -29,10 +29,10 @@ class AdminService:
def __init__(self, bot_db):
self.bot_db = bot_db
def get_last_users(self) -> List[User]:
async def get_last_users(self) -> List[User]:
"""Получить список последних пользователей"""
try:
users_data = self.bot_db.get_last_users_from_db()
users_data = await self.bot_db.get_last_users(30)
return [
User(
user_id=user[1],
@@ -45,31 +45,37 @@ class AdminService:
logger.error(f"Ошибка при получении списка последних пользователей: {e}")
raise
def get_banned_users(self) -> List[BannedUser]:
async def get_banned_users(self) -> List[BannedUser]:
"""Получить список заблокированных пользователей"""
try:
banned_users_data = self.bot_db.get_banned_users_from_db()
return [
BannedUser(
user_id=user[1], # user_id
username=user[0], # user_name
reason=user[2], # message_for_user
unban_date=user[3] # date_to_unban
)
for user in banned_users_data
]
banned_users_data = await self.bot_db.get_banned_users_from_db()
banned_users = []
for user_data in banned_users_data:
user_id, reason, unban_date = user_data
# Получаем username и full_name из таблицы users
username = await self.bot_db.get_username(user_id)
full_name = await self.bot_db.get_full_name_by_id(user_id)
user_name = username or full_name or f"User_{user_id}"
banned_users.append(BannedUser(
user_id=user_id,
username=user_name,
reason=reason,
unban_date=unban_date
))
return banned_users
except Exception as e:
logger.error(f"Ошибка при получении списка заблокированных пользователей: {e}")
raise
def get_user_by_username(self, username: str) -> Optional[User]:
async def get_user_by_username(self, username: str) -> Optional[User]:
"""Получить пользователя по username"""
try:
user_id = self.bot_db.get_user_id_by_username(username)
user_id = await self.bot_db.get_user_id_by_username(username)
if not user_id:
return None
full_name = self.bot_db.get_full_name_by_id(user_id)
full_name = await self.bot_db.get_full_name_by_id(user_id)
return User(
user_id=user_id,
username=username,
@@ -79,27 +85,27 @@ class AdminService:
logger.error(f"Ошибка при поиске пользователя по username {username}: {e}")
raise
def get_user_by_id(self, user_id: int) -> Optional[User]:
async def get_user_by_id(self, user_id: int) -> Optional[User]:
"""Получить пользователя по ID"""
try:
user_info = self.bot_db.get_user_info_by_id(user_id)
user_info = await self.bot_db.get_user_by_id(user_id)
if not user_info:
return None
return User(
user_id=user_id,
username=user_info.get('username', 'Неизвестно'),
full_name=user_info.get('full_name', 'Неизвестно')
username=user_info.username or 'Неизвестно',
full_name=user_info.full_name or 'Неизвестно'
)
except Exception as e:
logger.error(f"Ошибка при поиске пользователя по ID {user_id}: {e}")
raise
def ban_user(self, user_id: int, username: str, reason: str, ban_days: Optional[int]) -> None:
async def ban_user(self, user_id: int, username: str, reason: str, ban_days: Optional[int]) -> None:
"""Заблокировать пользователя"""
try:
# Проверяем, не заблокирован ли уже пользователь
if self.bot_db.check_user_in_blacklist(user_id):
if await self.bot_db.check_user_in_blacklist(user_id):
raise UserAlreadyBannedError(f"Пользователь {user_id} уже заблокирован")
# Рассчитываем дату разблокировки
@@ -107,8 +113,8 @@ class AdminService:
if ban_days is not None:
date_to_unban = add_days_to_date(ban_days)
# Сохраняем в БД
self.bot_db.set_user_blacklist(user_id, username, reason, date_to_unban)
# Сохраняем в БД (username больше не передается, так как не используется в новой схеме)
await self.bot_db.set_user_blacklist(user_id, None, reason, date_to_unban)
logger.info(f"Пользователь {user_id} ({username}) заблокирован. Причина: {reason}, срок: {ban_days} дней")
@@ -116,16 +122,16 @@ class AdminService:
logger.error(f"Ошибка при блокировке пользователя {user_id}: {e}")
raise
def unban_user(self, user_id: int) -> None:
async def unban_user(self, user_id: int) -> None:
"""Разблокировать пользователя"""
try:
self.bot_db.delete_user_blacklist(user_id)
await self.bot_db.delete_user_blacklist(user_id)
logger.info(f"Пользователь {user_id} разблокирован")
except Exception as e:
logger.error(f"Ошибка при разблокировке пользователя {user_id}: {e}")
raise
def validate_user_input(self, input_text: str) -> int:
async def validate_user_input(self, input_text: str) -> int:
"""Валидация введенного ID пользователя"""
try:
user_id = int(input_text.strip())
@@ -135,11 +141,12 @@ class AdminService:
except ValueError:
raise InvalidInputError("ID пользователя должен быть числом")
def get_banned_users_for_display(self, page: int = 0) -> tuple[str, list]:
async def get_banned_users_for_display(self, page: int = 0) -> tuple[str, list]:
"""Получить данные заблокированных пользователей для отображения"""
try:
message_text = get_banned_users_list(page, self.bot_db)
buttons_list = get_banned_users_buttons(self.bot_db)
message_text = await get_banned_users_list(page, self.bot_db)
buttons_list = await get_banned_users_buttons(self.bot_db)
return message_text, buttons_list
except Exception as e:
logger.error(f"Ошибка при получении данных заблокированных пользователей: {e}")