from dataclasses import dataclass from anydi import singleton from fansifter_common.adapters.ows_account import OwsAccountClient from fansifter_common.auth.requests import AuthAccountRequest from fansifter_common.auth.services import AuthService from fansifter_common.auth.types import Permission from slugify import slugify from dmp.adapters.db import ReportingDB, transactional from dmp.adapters.fivetran import FivetranClient from dmp.adapters.fivetran.models import ConnectCard from dmp.config import Settings from dmp.shopify.models import ShopifyStoreAssociation from dmp.shopify.repositories import StoreAssociationRepository @dataclass(kw_only=True) class ConnectStoreRequest(AuthAccountRequest): global_participant_id: str | None shop_domain: str redirect_uri: str @singleton class ConnectStoreHandler: permission = Permission("fan_data_channel", "connect") def __init__( self, db: ReportingDB, auth_service: AuthService, ows_account_client: OwsAccountClient, store_association_repository: StoreAssociationRepository, fivetran_client: FivetranClient, settings: Settings, ) -> None: self.db = db self.auth_service = auth_service self.ows_account_client = ows_account_client self.store_association_repository = store_association_repository self.fivetran_client = fivetran_client self.settings = settings @transactional def handle( self, request: ConnectStoreRequest ) -> tuple[ShopifyStoreAssociation, ConnectCard]: self.auth_service.check_account_resource( request.identity_id, account=request.account, permission=self.permission, ) fivetran_schema = self._generate_fivetran_schema(request) connection = self.fivetran_client.create_shopify_connection( group_id=self.settings.fivetran_shopify_group_id, schema=fivetran_schema, shop_domain=request.shop_domain, ) connect_card = self.fivetran_client.get_connect_card( connection_id=connection.id, redirect_uri=request.redirect_uri, ) association = ShopifyStoreAssociation( fivetran_connector_id=connection.id, fivetran_schema=fivetran_schema, shop_domain=request.shop_domain, vendor_id=request.vendor_id, subaccount_id=request.subaccount_id, global_participant_id=request.global_participant_id, created_by=request.identity_id, ) self.store_association_repository.add(association) return association, connect_card def _generate_fivetran_schema(self, request: ConnectStoreRequest) -> str: if request.account.is_subaccount: subaccount = self.ows_account_client.get_subaccount(request.subaccount_id) account_name = subaccount.name else: vendor = self.ows_account_client.get_vendor(request.vendor_id) account_name = vendor.name account_slug = slugify(account_name, separator="_", max_length=32).lower() existing_connectors_count = ( self.store_association_repository.get_count_by_account_id( vendor_id=request.vendor_id, subaccount_id=request.subaccount_id ) ) fivetran_schema = ( f"store_{request.subaccount_id or request.vendor_id}_{account_slug}_" f"{existing_connectors_count + 1:03}" ) if self.settings.fivetran_schema_prefix: fivetran_schema = ( f"{self.settings.fivetran_schema_prefix.lower()}_{fivetran_schema}" ) return fivetran_schema