from dataclasses import dataclass from operator import attrgetter from campaigns.auth.dtos import User from campaigns.connectors.db import Database, session_context from campaigns.connectors.facebook.base import FacebookClient from campaigns.core.handler import Handler from campaigns.core.types import PlainToken from campaigns.meta.dtos import CampaignPost from campaigns.meta.services import CampaignService, FacebookPageTokenService @dataclass(frozen=True) class GetCampaignPostsRequest: user: User campaign_id: str @dataclass class GetCampaignPostsHandler( Handler[GetCampaignPostsRequest, list[CampaignPost]], ): db: Database facebook_client: FacebookClient campaign_service: CampaignService facebook_page_token_service: FacebookPageTokenService @session_context(in_transaction=False) async def handle(self, request: GetCampaignPostsRequest) -> list[CampaignPost]: campaign = await self.campaign_service.get_user_campaign( user=request.user, campaign_id=request.campaign_id ) page = campaign.facebook_page page_token = await self.facebook_page_token_service.decrypt_token(page) facebook_posts = await self._get_facebook_posts( page_external_id=page.external_id, page_token=page_token, ) instagram_posts = await self._get_instagram_posts( page_external_id=page.external_id, page_token=page_token, ) return sorted( facebook_posts + instagram_posts, key=attrgetter("created_at"), reverse=True ) async def _get_facebook_posts( self, page_external_id: str, page_token: PlainToken ) -> list[CampaignPost]: posts = await self.facebook_client.get_published_posts_for_page( page_id=page_external_id, page_access_token=page_token, limit=None, ) return [ CampaignPost.from_api_obj(post) for post in posts if post.is_eligible_for_promotion ] async def _get_instagram_posts( self, page_external_id: str, page_token: PlainToken ) -> list[CampaignPost]: posts = [] instagram_business_account = ( await self.facebook_client.get_instagram_business_account_for_page( page_id=page_external_id, page_access_token=page_token, ) ) if not instagram_business_account: return [] async for post in self.facebook_client.get_instagram_media( instagram_account_id=instagram_business_account.id, page_access_token=page_token, ): posts.append(CampaignPost.from_api_obj(post)) async for story in self.facebook_client.get_instagram_stories( instagram_account_id=instagram_business_account.id, page_access_token=page_token, ): posts.append(CampaignPost.from_api_obj(story)) return posts