Реализован функцоинал хранения сырых текстов поста в базе данных. Оформление поста происходит непосредственно перед его отправкой в канал.

- Реализованы методы `get_post_text_and_anonymity_by_message_id` и `get_post_text_and_anonymity_by_helper_id` в `PostRepository` для получения текста поста и флага анонимности.
- Обновлена модель `TelegramPost`, добавлено поле `is_anonymous`.
- Изменена схема базы данных для включения поля `is_anonymous` в таблицу `post_from_telegram_suggest`.
- Обновлены функции публикации постов в `PostPublishService` для учета анонимности.
- Добавлены тесты для проверки новых функций и корректности работы с анонимностью.
This commit is contained in:
2026-01-23 12:12:21 +03:00
parent c6ba90552d
commit 89022aedaf
12 changed files with 1064 additions and 48 deletions

View File

@@ -8,7 +8,7 @@ from aiogram.types import CallbackQuery
from helper_bot.utils.helper_func import (
send_text_message, send_photo_message, send_video_message,
send_video_note_message, send_audio_message, send_voice_message,
send_media_group_to_channel, delete_user_blacklist
send_media_group_to_channel, delete_user_blacklist, get_text_message
)
from helper_bot.keyboards.keyboards import create_keyboard_for_ban_reason
from .exceptions import (
@@ -78,7 +78,6 @@ class PostPublishService:
@track_errors("post_publish_service", "_publish_text_post")
async def _publish_text_post(self, call: CallbackQuery) -> None:
"""Публикация текстового поста"""
text_post = html.escape(str(call.message.text))
author_id = await self._get_author_id(call.message.message_id)
updated_rows = await self.db.update_status_by_message_id(call.message.message_id, "approved")
@@ -86,7 +85,20 @@ class PostPublishService:
logger.error(f"Не удалось обновить статус поста message_id={call.message.message_id} на 'approved'")
raise PostNotFoundError(f"Пост с message_id={call.message.message_id} не найден в базе данных")
await send_text_message(self.main_public, call.message, text_post)
# Получаем сырой текст и is_anonymous из базы
raw_text, is_anonymous = await self.db.get_post_text_and_anonymity_by_message_id(call.message.message_id)
if raw_text is None:
raw_text = ""
# Получаем данные автора
user = await self.db.get_user_by_id(author_id)
if not user:
raise PostNotFoundError(f"Пользователь {author_id} не найден в базе данных")
# Формируем финальный текст с учетом is_anonymous
formatted_text = get_text_message(raw_text, user.first_name, user.username, is_anonymous)
await send_text_message(self.main_public, call.message, formatted_text)
await self._delete_post_and_notify_author(call, author_id)
logger.info(f'Текст сообщения опубликован в канале {self.main_public}.')
@@ -94,7 +106,6 @@ class PostPublishService:
@track_errors("post_publish_service", "_publish_photo_post")
async def _publish_photo_post(self, call: CallbackQuery) -> None:
"""Публикация поста с фото"""
text_post_with_photo = html.escape(str(call.message.caption))
author_id = await self._get_author_id(call.message.message_id)
updated_rows = await self.db.update_status_by_message_id(call.message.message_id, "approved")
@@ -102,7 +113,20 @@ class PostPublishService:
logger.error(f"Не удалось обновить статус поста message_id={call.message.message_id} на 'approved'")
raise PostNotFoundError(f"Пост с message_id={call.message.message_id} не найден в базе данных")
await send_photo_message(self.main_public, call.message, call.message.photo[-1].file_id, text_post_with_photo)
# Получаем сырой текст и is_anonymous из базы
raw_text, is_anonymous = await self.db.get_post_text_and_anonymity_by_message_id(call.message.message_id)
if raw_text is None:
raw_text = ""
# Получаем данные автора
user = await self.db.get_user_by_id(author_id)
if not user:
raise PostNotFoundError(f"Пользователь {author_id} не найден в базе данных")
# Формируем финальный текст с учетом is_anonymous
formatted_text = get_text_message(raw_text, user.first_name, user.username, is_anonymous)
await send_photo_message(self.main_public, call.message, call.message.photo[-1].file_id, formatted_text)
await self._delete_post_and_notify_author(call, author_id)
logger.info(f'Пост с фото опубликован в канале {self.main_public}.')
@@ -110,7 +134,6 @@ class PostPublishService:
@track_errors("post_publish_service", "_publish_video_post")
async def _publish_video_post(self, call: CallbackQuery) -> None:
"""Публикация поста с видео"""
text_post_with_photo = html.escape(str(call.message.caption))
author_id = await self._get_author_id(call.message.message_id)
updated_rows = await self.db.update_status_by_message_id(call.message.message_id, "approved")
@@ -118,7 +141,20 @@ class PostPublishService:
logger.error(f"Не удалось обновить статус поста message_id={call.message.message_id} на 'approved'")
raise PostNotFoundError(f"Пост с message_id={call.message.message_id} не найден в базе данных")
await send_video_message(self.main_public, call.message, call.message.video.file_id, text_post_with_photo)
# Получаем сырой текст и is_anonymous из базы
raw_text, is_anonymous = await self.db.get_post_text_and_anonymity_by_message_id(call.message.message_id)
if raw_text is None:
raw_text = ""
# Получаем данные автора
user = await self.db.get_user_by_id(author_id)
if not user:
raise PostNotFoundError(f"Пользователь {author_id} не найден в базе данных")
# Формируем финальный текст с учетом is_anonymous
formatted_text = get_text_message(raw_text, user.first_name, user.username, is_anonymous)
await send_video_message(self.main_public, call.message, call.message.video.file_id, formatted_text)
await self._delete_post_and_notify_author(call, author_id)
logger.info(f'Пост с видео опубликован в канале {self.main_public}.')
@@ -141,7 +177,6 @@ class PostPublishService:
@track_errors("post_publish_service", "_publish_audio_post")
async def _publish_audio_post(self, call: CallbackQuery) -> None:
"""Публикация поста с аудио"""
text_post_with_photo = html.escape(str(call.message.caption))
author_id = await self._get_author_id(call.message.message_id)
updated_rows = await self.db.update_status_by_message_id(call.message.message_id, "approved")
@@ -149,7 +184,20 @@ class PostPublishService:
logger.error(f"Не удалось обновить статус поста message_id={call.message.message_id} на 'approved'")
raise PostNotFoundError(f"Пост с message_id={call.message.message_id} не найден в базе данных")
await send_audio_message(self.main_public, call.message, call.message.audio.file_id, text_post_with_photo)
# Получаем сырой текст и is_anonymous из базы
raw_text, is_anonymous = await self.db.get_post_text_and_anonymity_by_message_id(call.message.message_id)
if raw_text is None:
raw_text = ""
# Получаем данные автора
user = await self.db.get_user_by_id(author_id)
if not user:
raise PostNotFoundError(f"Пользователь {author_id} не найден в базе данных")
# Формируем финальный текст с учетом is_anonymous
formatted_text = get_text_message(raw_text, user.first_name, user.username, is_anonymous)
await send_audio_message(self.main_public, call.message, call.message.audio.file_id, formatted_text)
await self._delete_post_and_notify_author(call, author_id)
logger.info(f'Пост с аудио опубликован в канале {self.main_public}.')
@@ -185,11 +233,12 @@ class PostPublishService:
logger.error(f"Контент медиагруппы не найден в базе данных для helper_message_id: {helper_message_id}")
raise PublishError("Контент медиагруппы не найден в базе данных")
# Получаем текст поста по helper_message_id
logger.debug(f"Получаю текст поста для helper_message_id: {helper_message_id}")
pre_text = await self.db.get_post_text_by_helper_id(helper_message_id)
post_text = html.escape(str(pre_text)) if pre_text else ""
logger.debug(f"Текст поста получен: {'пустой' if not post_text else f'длина: {len(post_text)} символов'}")
# Получаем сырой текст и is_anonymous по helper_message_id
logger.debug(f"Получаю текст и is_anonymous поста для helper_message_id: {helper_message_id}")
raw_text, is_anonymous = await self.db.get_post_text_and_anonymity_by_helper_id(helper_message_id)
if raw_text is None:
raw_text = ""
logger.debug(f"Текст поста получен: {'пустой' if not raw_text else f'длина: {len(raw_text)} символов'}, is_anonymous={is_anonymous}")
# Получаем ID автора по helper_message_id
logger.debug(f"Получаю ID автора для helper_message_id: {helper_message_id}")
@@ -199,13 +248,22 @@ class PostPublishService:
raise PostNotFoundError(f"Автор не найден для медиагруппы {helper_message_id}")
logger.debug(f"ID автора получен: {author_id}")
# Получаем данные автора
user = await self.db.get_user_by_id(author_id)
if not user:
raise PostNotFoundError(f"Пользователь {author_id} не найден в базе данных")
# Формируем финальный текст с учетом is_anonymous
formatted_text = get_text_message(raw_text, user.first_name, user.username, is_anonymous)
logger.debug(f"Сформирован финальный текст: {'пустой' if not formatted_text else f'длина: {len(formatted_text)} символов'}")
# Отправляем медиагруппу в канал
logger.info(f"Отправляю медиагруппу в канал {self.main_public}")
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
post_text=formatted_text
)
await self.db.update_status_for_media_group_by_helper_id(helper_message_id, "approved")

View File

@@ -13,11 +13,13 @@ from dataclasses import dataclass
from aiogram import types
from aiogram.types import FSInputFile
from database.models import TelegramPost, User
from logs.custom_logger import logger
# Local imports - utilities
from helper_bot.utils.helper_func import (
get_first_name,
get_text_message,
determine_anonymity,
send_text_message,
send_photo_message,
send_media_group_message_to_private_chat,
@@ -154,11 +156,17 @@ class PostService:
markup = get_reply_keyboard_for_post()
sent_message_id = await send_text_message(self.settings.group_for_posts, message, post_text, markup)
# Сохраняем сырой текст и определяем анонимность
raw_text = message.text or ""
is_anonymous = determine_anonymity(raw_text)
post = TelegramPost(
message_id=sent_message_id,
text=message.text,
text=raw_text,
author_id=message.from_user.id,
created_at=int(datetime.now().timestamp())
created_at=int(datetime.now().timestamp()),
is_anonymous=is_anonymous
)
await self.db.add_post(post)
@@ -176,11 +184,16 @@ class PostService:
self.settings.group_for_posts, message, message.photo[-1].file_id, post_caption, markup
)
# Сохраняем сырой caption и определяем анонимность
raw_caption = message.caption or ""
is_anonymous = determine_anonymity(raw_caption)
post = TelegramPost(
message_id=sent_message.message_id,
text=sent_message.caption or "",
text=raw_caption,
author_id=message.from_user.id,
created_at=int(datetime.now().timestamp())
created_at=int(datetime.now().timestamp()),
is_anonymous=is_anonymous
)
await self.db.add_post(post)
success = await add_in_db_media(sent_message, self.db)
@@ -201,11 +214,16 @@ class PostService:
self.settings.group_for_posts, message, message.video.file_id, post_caption, markup
)
# Сохраняем сырой caption и определяем анонимность
raw_caption = message.caption or ""
is_anonymous = determine_anonymity(raw_caption)
post = TelegramPost(
message_id=sent_message.message_id,
text=sent_message.caption or "",
text=raw_caption,
author_id=message.from_user.id,
created_at=int(datetime.now().timestamp())
created_at=int(datetime.now().timestamp()),
is_anonymous=is_anonymous
)
await self.db.add_post(post)
success = await add_in_db_media(sent_message, self.db)
@@ -222,11 +240,16 @@ class PostService:
self.settings.group_for_posts, message, message.video_note.file_id, markup
)
# Сохраняем пустую строку, так как video_note не имеет caption
raw_caption = ""
is_anonymous = determine_anonymity(raw_caption)
post = TelegramPost(
message_id=sent_message.message_id,
text=sent_message.caption or "",
text=raw_caption,
author_id=message.from_user.id,
created_at=int(datetime.now().timestamp())
created_at=int(datetime.now().timestamp()),
is_anonymous=is_anonymous
)
await self.db.add_post(post)
success = await add_in_db_media(sent_message, self.db)
@@ -247,11 +270,16 @@ class PostService:
self.settings.group_for_posts, message, message.audio.file_id, post_caption, markup
)
# Сохраняем сырой caption и определяем анонимность
raw_caption = message.caption or ""
is_anonymous = determine_anonymity(raw_caption)
post = TelegramPost(
message_id=sent_message.message_id,
text=sent_message.caption or "",
text=raw_caption,
author_id=message.from_user.id,
created_at=int(datetime.now().timestamp())
created_at=int(datetime.now().timestamp()),
is_anonymous=is_anonymous
)
await self.db.add_post(post)
success = await add_in_db_media(sent_message, self.db)
@@ -268,11 +296,16 @@ class PostService:
self.settings.group_for_posts, message, message.voice.file_id, markup
)
# Сохраняем пустую строку, так как voice не имеет caption
raw_caption = ""
is_anonymous = determine_anonymity(raw_caption)
post = TelegramPost(
message_id=sent_message.message_id,
text=sent_message.caption or "",
text=raw_caption,
author_id=message.from_user.id,
created_at=int(datetime.now().timestamp())
created_at=int(datetime.now().timestamp()),
is_anonymous=is_anonymous
)
await self.db.add_post(post)
success = await add_in_db_media(sent_message, self.db)
@@ -285,17 +318,24 @@ class PostService:
@track_media_processing("media_group")
async def handle_media_group_post(self, message: types.Message, album: list, first_name: str) -> None:
"""Handle media group post submission"""
#TODO: Мне кажется тут какая-то дичь с одинаковыми переменными, в которых post_caption никуда не ведет
post_caption = " "
raw_caption = ""
if album and album[0].caption:
raw_caption = album[0].caption or ""
post_caption = get_text_message(album[0].caption.lower(), first_name, message.from_user.username)
# Определяем анонимность на основе сырого caption
is_anonymous = determine_anonymity(raw_caption)
# Создаем основной пост для медиагруппы
main_post = TelegramPost(
message_id=message.message_id, # ID основного сообщения медиагруппы
text=post_caption,
text=raw_caption,
author_id=message.from_user.id,
created_at=int(datetime.now().timestamp())
created_at=int(datetime.now().timestamp()),
is_anonymous=is_anonymous
)
await self.db.add_post(main_post)