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

@@ -26,12 +26,19 @@ from logs.custom_logger import logger
class PostPublishService:
def __init__(self, bot: Bot, db, settings: Dict[str, Any]):
# bot может быть None - в этом случае используем бота из контекста сообщения
self.bot = bot
self.db = db
self.settings = settings
self.group_for_posts = settings['Telegram']['group_for_posts']
self.main_public = settings['Telegram']['main_public']
self.important_logs = settings['Telegram']['important_logs']
def _get_bot(self, message) -> Bot:
"""Получает бота из контекста сообщения или использует переданного"""
if self.bot:
return self.bot
return message.bot
async def publish_post(self, call: CallbackQuery) -> None:
"""Основной метод публикации поста"""
@@ -57,7 +64,7 @@ class PostPublishService:
async def _publish_text_post(self, call: CallbackQuery) -> None:
"""Публикация текстового поста"""
text_post = html.escape(str(call.message.text))
author_id = self._get_author_id(call.message.message_id)
author_id = await self._get_author_id(call.message.message_id)
await send_text_message(self.main_public, call.message, text_post)
await self._delete_post_and_notify_author(call, author_id)
@@ -66,7 +73,7 @@ class PostPublishService:
async def _publish_photo_post(self, call: CallbackQuery) -> None:
"""Публикация поста с фото"""
text_post_with_photo = html.escape(str(call.message.caption))
author_id = self._get_author_id(call.message.message_id)
author_id = await self._get_author_id(call.message.message_id)
await send_photo_message(self.main_public, call.message, call.message.photo[-1].file_id, text_post_with_photo)
await self._delete_post_and_notify_author(call, author_id)
@@ -75,7 +82,7 @@ class PostPublishService:
async def _publish_video_post(self, call: CallbackQuery) -> None:
"""Публикация поста с видео"""
text_post_with_photo = html.escape(str(call.message.caption))
author_id = self._get_author_id(call.message.message_id)
author_id = await self._get_author_id(call.message.message_id)
await send_video_message(self.main_public, call.message, call.message.video.file_id, text_post_with_photo)
await self._delete_post_and_notify_author(call, author_id)
@@ -83,7 +90,7 @@ class PostPublishService:
async def _publish_video_note_post(self, call: CallbackQuery) -> None:
"""Публикация поста с кружком"""
author_id = self._get_author_id(call.message.message_id)
author_id = await self._get_author_id(call.message.message_id)
await send_video_note_message(self.main_public, call.message, call.message.video_note.file_id)
await self._delete_post_and_notify_author(call, author_id)
@@ -92,7 +99,7 @@ class PostPublishService:
async def _publish_audio_post(self, call: CallbackQuery) -> None:
"""Публикация поста с аудио"""
text_post_with_photo = html.escape(str(call.message.caption))
author_id = self._get_author_id(call.message.message_id)
author_id = await self._get_author_id(call.message.message_id)
await send_audio_message(self.main_public, call.message, call.message.audio.file_id, text_post_with_photo)
await self._delete_post_and_notify_author(call, author_id)
@@ -100,7 +107,7 @@ class PostPublishService:
async def _publish_voice_post(self, call: CallbackQuery) -> None:
"""Публикация поста с войсом"""
author_id = self._get_author_id(call.message.message_id)
author_id = await self._get_author_id(call.message.message_id)
await send_voice_message(self.main_public, call.message, call.message.voice.file_id)
await self._delete_post_and_notify_author(call, author_id)
@@ -108,12 +115,12 @@ class PostPublishService:
async def _publish_media_group(self, call: CallbackQuery) -> None:
"""Публикация медиагруппы"""
post_content = self.db.get_post_content_from_telegram_by_last_id(call.message.message_id)
pre_text = self.db.get_post_text_from_telegram_by_last_id(call.message.message_id)
post_content = await self.db.get_post_content_from_telegram_by_last_id(call.message.message_id)
pre_text = await self.db.get_post_text_from_telegram_by_last_id(call.message.message_id)
post_text = html.escape(str(pre_text))
author_id = self._get_author_id_for_media_group(call.message.message_id)
author_id = await self._get_author_id_for_media_group(call.message.message_id)
await send_media_group_to_channel(bot=self.bot, chat_id=self.main_public, post_content=post_content, post_text=post_text)
await send_media_group_to_channel(bot=self._get_bot(call.message), chat_id=self.main_public, post_content=post_content, post_text=post_text)
await self._delete_media_group_and_notify_author(call, author_id)
async def decline_post(self, call: CallbackQuery) -> None:
@@ -130,8 +137,8 @@ class PostPublishService:
async def _decline_single_post(self, call: CallbackQuery) -> None:
"""Отклонение одиночного поста"""
author_id = self._get_author_id(call.message.message_id)
await self.bot.delete_message(chat_id=self.group_for_posts, message_id=call.message.message_id)
author_id = await self._get_author_id(call.message.message_id)
await self._get_bot(call.message).delete_message(chat_id=self.group_for_posts, message_id=call.message.message_id)
try:
await send_text_message(author_id, call.message, MESSAGE_POST_DECLINED)
except Exception as e:
@@ -142,12 +149,12 @@ class PostPublishService:
async def _decline_media_group(self, call: CallbackQuery) -> None:
"""Отклонение медиагруппы"""
post_ids = self.db.get_post_ids_from_telegram_by_last_id(call.message.message_id)
post_ids = await self.db.get_post_ids_from_telegram_by_last_id(call.message.message_id)
message_ids = [row[0] for row in post_ids]
message_ids.append(call.message.message_id)
author_id = self._get_author_id_for_media_group(call.message.message_id)
await self.bot.delete_messages(chat_id=self.group_for_posts, message_ids=message_ids)
author_id = await self._get_author_id_for_media_group(call.message.message_id)
await self._get_bot(call.message).delete_messages(chat_id=self.group_for_posts, message_ids=message_ids)
try:
await send_text_message(author_id, call.message, MESSAGE_POST_DECLINED)
except Exception as e:
@@ -155,23 +162,24 @@ class PostPublishService:
raise UserBlockedBotError("Пользователь заблокировал бота")
raise
def _get_author_id(self, message_id: int) -> int:
async def _get_author_id(self, message_id: int) -> int:
"""Получение ID автора по ID сообщения"""
author_id = self.db.get_author_id_by_message_id(message_id)
author_id = await self.db.get_author_id_by_message_id(message_id)
if not author_id:
raise PostNotFoundError(f"Автор не найден для сообщения {message_id}")
return author_id
def _get_author_id_for_media_group(self, message_id: int) -> int:
async def _get_author_id_for_media_group(self, message_id: int) -> int:
"""Получение ID автора для медиагруппы"""
author_id = self.db.get_author_id_by_helper_message_id(message_id)
author_id = await self.db.get_author_id_by_helper_message_id(message_id)
if not author_id:
raise PostNotFoundError(f"Автор не найден для медиагруппы {message_id}")
return author_id
async def _delete_post_and_notify_author(self, call: CallbackQuery, author_id: int) -> None:
"""Удаление поста и уведомление автора"""
await self.bot.delete_message(chat_id=self.group_for_posts, message_id=call.message.message_id)
await self._get_bot(call.message).delete_message(chat_id=self.group_for_posts, message_id=call.message.message_id)
try:
await send_text_message(author_id, call.message, MESSAGE_POST_PUBLISHED)
except Exception as e:
@@ -181,10 +189,10 @@ class PostPublishService:
async def _delete_media_group_and_notify_author(self, call: CallbackQuery, author_id: int) -> None:
"""Удаление медиагруппы и уведомление автора"""
post_ids = self.db.get_post_ids_from_telegram_by_last_id(call.message.message_id)
post_ids = await self.db.get_post_ids_from_telegram_by_last_id(call.message.message_id)
message_ids = [row[0] for row in post_ids]
message_ids.append(call.message.message_id)
await self.bot.delete_messages(chat_id=self.group_for_posts, message_ids=message_ids)
await self._get_bot(call.message).delete_messages(chat_id=self.group_for_posts, message_ids=message_ids)
try:
await send_text_message(author_id, call.message, MESSAGE_POST_PUBLISHED)
except Exception as e:
@@ -203,24 +211,23 @@ class BanService:
async def ban_user_from_post(self, call: CallbackQuery) -> None:
"""Бан пользователя за спам"""
author_id = self.db.get_author_id_by_message_id(call.message.message_id)
author_id = await self.db.get_author_id_by_message_id(call.message.message_id)
if not author_id:
raise UserNotFoundError(f"Автор не найден для сообщения {call.message.message_id}")
user_name = self.db.get_username(user_id=author_id)
current_date = datetime.now()
date_to_unban = current_date + timedelta(days=7)
date_to_unban = int((current_date + timedelta(days=7)).timestamp())
self.db.set_user_blacklist(
await self.db.set_user_blacklist(
user_id=author_id,
user_name=user_name,
user_name=None,
message_for_user="Спам",
date_to_unban=date_to_unban
)
await self.bot.delete_message(chat_id=self.group_for_posts, message_id=call.message.message_id)
await self._get_bot(call.message).delete_message(chat_id=self.group_for_posts, message_id=call.message.message_id)
date_str = date_to_unban.strftime("%d.%m.%Y %H:%M")
date_str = (current_date + timedelta(days=7)).strftime("%d.%m.%Y %H:%M")
try:
await send_text_message(author_id, call.message, MESSAGE_USER_BANNED_SPAM.format(date=date_str))
except Exception as e:
@@ -232,7 +239,7 @@ class BanService:
async def ban_user(self, user_id: str, user_name: str) -> str:
"""Бан пользователя по ID"""
user_name = self.db.get_username(user_id=user_id)
user_name = await self.db.get_username(int(user_id))
if not user_name:
raise UserNotFoundError(f"Пользователь с ID {user_id} не найден в базе")
@@ -240,10 +247,10 @@ class BanService:
async def unlock_user(self, user_id: str) -> str:
"""Разблокировка пользователя"""
user_name = self.db.get_username(user_id=user_id)
user_name = await self.db.get_username(int(user_id))
if not user_name:
raise UserNotFoundError(f"Пользователь с ID {user_id} не найден в базе")
delete_user_blacklist(user_id, self.db)
await delete_user_blacklist(int(user_id), self.db)
logger.info(f"Разблокирован пользователь с ID: {user_id} username:{user_name}")
return user_name