This commit is contained in:
Artem Tsyrulnikov
2026-01-19 16:47:52 +03:00
parent 6b410f89cc
commit a90c8b7df6
20 changed files with 205 additions and 343 deletions

View File

@@ -2,16 +2,52 @@ import logging
from typing import TYPE_CHECKING
from src import domain, dto
from .create_placements import _build_placement_output
if TYPE_CHECKING:
from .. import Usecase
from src.usecase.purchase.create_placements import _build_placement_output
log = logging.getLogger(__name__)
async def get_placement_user(self: 'Usecase', input: dto.GetPlacementInput) -> dto.PlacementOutput:
def _build_placement_post_output(
placement_post: domain.PlacementPost, subscriptions_count: int
) -> dto.PlacementPostOutput | None:
placement = placement_post.placement
if not placement:
log.warning('PlacementPost %s missing placement data', placement_post.id)
return None
if not placement.channel or not placement.project or not placement.creative:
log.warning('PlacementPost %s placement missing related data', placement_post.id)
return None
ad_post_url = placement_post.post.url if placement_post.post else None
return dto.PlacementPostOutput(
id=placement_post.id,
project_id=placement.project_id,
project_channel_title=placement.project.channel.title if placement.project.channel else None,
placement_channel_id=placement.channel_id,
placement_channel_title=placement.channel.title,
creative_id=placement.creative_id,
creative_name=placement.creative.name,
placement_date=placement.placement_at or placement_post.created_at,
cost=placement.cost_value,
comment=placement.comment,
ad_post_url=ad_post_url,
invite_link_type=placement.invite_link_type,
invite_link=placement.invite_link,
status=placement_post.status,
subscriptions_count=subscriptions_count,
placement_id=placement.id,
placement=_build_placement_output(placement),
created_at=placement_post.created_at,
)
if TYPE_CHECKING:
from .. import Usecase
async def get_placement_user(self: 'Usecase', input: dto.GetPlacementInput) -> dto.PlacementWithPostsOutput:
"""Get single placement by ID (user-managed)"""
context = await self.ensure_workspace_permission(
input.workspace_id, input.user_id, domain.PermissionKey.PLACEMENTS_READ
@@ -32,4 +68,24 @@ async def get_placement_user(self: 'Usecase', input: dto.GetPlacementInput) -> d
channel = await self.database.get_channel(channel_id=placement.channel_id)
placement.channel = channel
return _build_placement_output(placement)
placement_posts = await self.database.get_workspace_placement_posts(
input.workspace_id,
placement_id=placement.id,
include_archived=True,
)
placement_post_ids = [post.id for post in placement_posts]
subscriptions_counts = await self.database.count_subscriptions_by_placement_post_batch(placement_post_ids)
placement_post_outputs = []
for placement_post in placement_posts:
placement_post_output = _build_placement_post_output(
placement_post, subscriptions_counts.get(placement_post.id, 0)
)
if placement_post_output is not None:
placement_post_outputs.append(placement_post_output)
placement_output = _build_placement_output(placement)
return dto.PlacementWithPostsOutput(
**placement_output.model_dump(),
placement_posts=placement_post_outputs,
)