Files
tgex-backend/src/usecase/creative/update_creative.py
Artem Tsyrulnikov 049024ebe8 refactor
2026-01-15 22:02:16 +03:00

99 lines
3.3 KiB
Python

import asyncio
import logging
import uuid
from typing import TYPE_CHECKING
from src import domain, dto
if TYPE_CHECKING:
from .. import Usecase
log = logging.getLogger(__name__)
async def update_creative(
self: 'Usecase',
creative_id: uuid.UUID,
input: dto.UpdateCreativeInput,
user_id: uuid.UUID,
workspace_id: uuid.UUID,
) -> dto.CreativeOutput:
context = await self.ensure_workspace_permission(workspace_id, user_id, domain.PermissionKey.PROJECTS_WRITE)
creative = await self.database.get_creative(workspace_id, creative_id)
if not creative:
log.warning('User %s attempted to update unavailable creative %s', user_id, creative_id)
raise domain.CreativeNotFound(creative_id)
context.ensure_project_permission(domain.PermissionKey.PROJECTS_WRITE, creative.project_id)
if input.name:
creative.name = input.name
if input.text:
creative.text = domain.replace_invite_link_with_tag(input.text)
if input.media_data is not None:
domain.validate_media_size(input.media_data)
# Удаляем старое медиа из S3 в фоне
old_media_key = creative.media_s3_key
if old_media_key:
async def delete_old_media() -> None:
try:
await self.s3.delete(old_media_key)
log.info('Deleted old creative media from S3: %s', old_media_key)
except Exception as e:
log.warning('Failed to delete old creative media from S3: %s', e)
asyncio.create_task(delete_old_media())
# Загружаем новое медиа в S3
new_media_data = input.media_data
if new_media_data:
file_id = uuid.uuid4()
new_media_key = f'creatives/{workspace_id}/{file_id}'
content_type = _get_content_type(input.media_type)
await self.s3.upload(new_media_key, new_media_data, content_type)
log.info('Uploaded new creative media to S3: %s', new_media_key)
creative.media_s3_key = new_media_key
else:
creative.media_s3_key = None
if input.media_type is not None:
creative.media_type = input.media_type
if input.media_file_id is not None:
creative.media_file_id = input.media_file_id
if input.buttons is not None:
creative.buttons = [button.model_dump() for button in input.buttons]
if input.status:
creative.status = input.status
await self.database.update_creative(creative)
placements_count = await self.database.count_publications_by_creative(creative.id)
return dto.CreativeOutput(
id=creative.id,
name=creative.name,
text=creative.text,
media_type=creative.media_type,
media_file_id=creative.media_file_id,
buttons=creative.buttons,
project_id=creative.project_id,
project_channel_title=creative.project.channel.title,
created_at=creative.created_at,
status=creative.status,
placements_count=placements_count,
)
def _get_content_type(media_type: str | None) -> str:
if not media_type:
return 'application/octet-stream'
mapping = {
'photo': 'image/jpeg',
'video': 'video/mp4',
'animation': 'image/gif',
}
return mapping.get(media_type, 'application/octet-stream')