diff --git a/src/adapter/telegram_bot.py b/src/adapter/telegram_bot.py index 6f9ca93..83c9c5b 100644 --- a/src/adapter/telegram_bot.py +++ b/src/adapter/telegram_bot.py @@ -5,6 +5,8 @@ from typing import Any from aiogram.types import ( InlineKeyboardButton, InlineKeyboardMarkup, + InputMediaAudio, + InputMediaDocument, InputMediaPhoto, InputMediaVideo, ) @@ -122,7 +124,7 @@ class TelegramBot(TelegramBase, TelegramBotWriter): if not media_items: raise ValueError('No media items to send') - group: list[InputMediaPhoto | InputMediaVideo] = [] + group: list[InputMediaAudio | InputMediaDocument | InputMediaPhoto | InputMediaVideo] = [] for index, item in enumerate(media_items): item_caption = caption if index == 0 else None if item.media_type == 'photo': @@ -132,10 +134,9 @@ class TelegramBot(TelegramBase, TelegramBotWriter): else: raise ValueError(f'Unsupported media type for group: {item.media_type}') - # Type ignore: aiogram expects Union type but we only use Photo/Video messages = await self.bot.send_media_group( chat_id=chat_id, media=group, reply_to_message_id=reply_to_message_id - ) # type: ignore[arg-type] + ) # Return message_id of first message (with caption) return messages[0].message_id diff --git a/src/config.py b/src/config.py index 36aed43..799f92f 100644 --- a/src/config.py +++ b/src/config.py @@ -1,4 +1,5 @@ import json +import typing from pydantic import BaseModel, field_validator from pydantic_settings import BaseSettings, SettingsConfigDict @@ -24,7 +25,7 @@ class AppConfig(BaseModel): if isinstance(v, list): return v if isinstance(v, str): - return json.loads(v) + return typing.cast(list[str], json.loads(v)) raise ValueError('ORIGINS must be a JSON array string') diff --git a/src/dto/creative.py b/src/dto/creative.py index 697106c..d45590b 100644 --- a/src/dto/creative.py +++ b/src/dto/creative.py @@ -15,6 +15,7 @@ class CreativeMediaItem(pydantic.BaseModel): media_type: str media_file_id: str position: int + s3_url: str | None = None class CreativeMediaInput(pydantic.BaseModel): diff --git a/src/usecase/creative/create_creative.py b/src/usecase/creative/create_creative.py index f175242..fec25e6 100644 --- a/src/usecase/creative/create_creative.py +++ b/src/usecase/creative/create_creative.py @@ -96,6 +96,7 @@ async def _replace_media_items( media_type=media.media_type, media_file_id=media.media_file_id, position=media.position, + s3_url=self.s3.public_url(media.media_s3_key) if media.media_s3_key else None, ) ) return created diff --git a/src/usecase/creative/get_creative.py b/src/usecase/creative/get_creative.py index 5ad21fd..b6926c3 100644 --- a/src/usecase/creative/get_creative.py +++ b/src/usecase/creative/get_creative.py @@ -36,6 +36,7 @@ async def get_creative(self: 'Usecase', input: dto.GetCreativeInput) -> dto.Crea media_type=item.media_type, media_file_id=item.media_file_id, position=item.position, + s3_url=self.s3.public_url(item.media_s3_key) if item.media_s3_key else None, ) for item in media_items ], diff --git a/src/usecase/creative/get_creatives.py b/src/usecase/creative/get_creatives.py index db2fd8e..5e36112 100644 --- a/src/usecase/creative/get_creatives.py +++ b/src/usecase/creative/get_creatives.py @@ -44,6 +44,7 @@ async def get_creatives(self: 'Usecase', input: dto.GetCreativesInput) -> list[d media_type=item.media_type, media_file_id=item.media_file_id, position=item.position, + s3_url=self.s3.public_url(item.media_s3_key) if item.media_s3_key else None, ) for item in media_items ], diff --git a/src/usecase/creative/update_creative.py b/src/usecase/creative/update_creative.py index edd11d7..dafc2c4 100644 --- a/src/usecase/creative/update_creative.py +++ b/src/usecase/creative/update_creative.py @@ -7,6 +7,7 @@ from src import domain, dto if TYPE_CHECKING: from .. import Usecase + from .. import S3Storage log = logging.getLogger(__name__) @@ -50,7 +51,7 @@ async def update_creative( await _replace_media_items(self, creative.id, workspace_id, media_items) placements_count = await self.database.count_placement_posts_by_creative(creative.id) - creative_media = await _get_media_items(creative) + creative_media = await _get_media_items(creative, self.s3) return dto.CreativeOutput( id=creative.id, @@ -119,7 +120,7 @@ async def _replace_media_items( ) -async def _get_media_items(creative: domain.Creative) -> list[dto.CreativeMediaItem]: +async def _get_media_items(creative: domain.Creative, s3_storage: S3Storage) -> list[dto.CreativeMediaItem]: media_rel = creative.media_items if hasattr(media_rel, 'all'): items = await media_rel.all().order_by('position') @@ -130,6 +131,7 @@ async def _get_media_items(creative: domain.Creative) -> list[dto.CreativeMediaI media_type=item.media_type, media_file_id=item.media_file_id, position=item.position, + s3_url=s3_storage.public_url(item.media_s3_key) if item.media_s3_key else None, ) for item in items ] diff --git a/src/usecase/purchase/build_placement_creative.py b/src/usecase/purchase/build_placement_creative.py index 29c128a..2b048ac 100644 --- a/src/usecase/purchase/build_placement_creative.py +++ b/src/usecase/purchase/build_placement_creative.py @@ -185,6 +185,7 @@ async def build_placement_creative( media_type=item.media_type, media_file_id=item.media_file_id, position=item.position, + s3_url=self.s3.public_url(item.media_s3_key) if item.media_s3_key else None, ) for item in media_items ], diff --git a/tg_bot/backend/backend_client.go b/tg_bot/backend/backend_client.go index 73978ce..3371fa4 100644 --- a/tg_bot/backend/backend_client.go +++ b/tg_bot/backend/backend_client.go @@ -388,9 +388,10 @@ type CreativeButton struct { } type CreativeMediaItem struct { - MediaType string `json:"media_type"` - MediaFileID string `json:"media_file_id"` - Position int `json:"position"` + MediaType string `json:"media_type"` + MediaFileID string `json:"media_file_id"` + Position int `json:"position"` + S3URL *string `json:"s3_url,omitempty"` } type CreativeMediaInput struct {