feat: subs and views
This commit is contained in:
@@ -19,6 +19,8 @@ class MockDatabase:
|
||||
self.external_channels: dict[uuid.UUID, domain.ExternalChannel] = {}
|
||||
self.creatives: dict[uuid.UUID, domain.Creative] = {}
|
||||
self.purchases: dict[uuid.UUID, domain.Purchase] = {}
|
||||
self.subscriptions: dict[uuid.UUID, domain.Subscription] = {}
|
||||
self.views_snapshots: dict[uuid.UUID, domain.ViewsSnapshot] = {}
|
||||
self.m2m_target_external: dict[uuid.UUID, list[uuid.UUID]] = {}
|
||||
|
||||
def transaction(self) -> AbstractAsyncContextManager[None]:
|
||||
@@ -205,6 +207,8 @@ class MockDatabase:
|
||||
purchase.subscriptions_count = 0
|
||||
if not hasattr(purchase, 'status') or purchase.status is None:
|
||||
purchase.status = domain.PurchaseStatus.ACTIVE
|
||||
if not hasattr(purchase, 'views_availability') or purchase.views_availability is None:
|
||||
purchase.views_availability = domain.PostViewsAvailability.UNKNOWN
|
||||
# Загружаем связанные объекты
|
||||
target_ch = self.target_channels.get(purchase.target_channel_id)
|
||||
if target_ch:
|
||||
@@ -257,6 +261,61 @@ class MockDatabase:
|
||||
return True
|
||||
return False
|
||||
|
||||
async def get_purchase_by_invite_link(self, invite_link: str) -> domain.Purchase | None:
|
||||
for purchase in self.purchases.values():
|
||||
if purchase.invite_link == invite_link:
|
||||
return purchase
|
||||
return None
|
||||
|
||||
async def create_subscription(self, subscription: domain.Subscription) -> domain.Subscription:
|
||||
if not subscription.id:
|
||||
subscription.id = uuid.uuid4()
|
||||
if not hasattr(subscription, 'created_at') or subscription.created_at is None:
|
||||
subscription.created_at = datetime.datetime.now(datetime.UTC)
|
||||
if not hasattr(subscription, 'updated_at') or subscription.updated_at is None:
|
||||
subscription.updated_at = datetime.datetime.now(datetime.UTC)
|
||||
# Загружаем связанный объект
|
||||
purchase = self.purchases.get(subscription.purchase_id)
|
||||
if purchase:
|
||||
subscription.purchase = purchase
|
||||
self.subscriptions[subscription.id] = subscription
|
||||
return subscription
|
||||
|
||||
async def get_subscription_by_user_and_purchase(
|
||||
self, user_telegram_id: int, purchase_id: uuid.UUID
|
||||
) -> domain.Subscription | None:
|
||||
for subscription in self.subscriptions.values():
|
||||
if subscription.user_telegram_id == user_telegram_id and subscription.purchase_id == purchase_id:
|
||||
return subscription
|
||||
return None
|
||||
|
||||
async def create_views_snapshot(self, snapshot: domain.ViewsSnapshot) -> domain.ViewsSnapshot:
|
||||
if not snapshot.id:
|
||||
snapshot.id = uuid.uuid4()
|
||||
if not hasattr(snapshot, 'created_at') or snapshot.created_at is None:
|
||||
snapshot.created_at = datetime.datetime.now(datetime.UTC)
|
||||
if not hasattr(snapshot, 'updated_at') or snapshot.updated_at is None:
|
||||
snapshot.updated_at = datetime.datetime.now(datetime.UTC)
|
||||
purchase = self.purchases.get(snapshot.purchase_id)
|
||||
if purchase:
|
||||
snapshot.purchase = purchase
|
||||
self.views_snapshots[snapshot.id] = snapshot
|
||||
return snapshot
|
||||
|
||||
async def get_views_history(
|
||||
self,
|
||||
purchase_id: uuid.UUID,
|
||||
*,
|
||||
from_date: datetime.datetime | None = None,
|
||||
to_date: datetime.datetime | None = None,
|
||||
) -> list[domain.ViewsSnapshot]:
|
||||
result = [s for s in self.views_snapshots.values() if s.purchase_id == purchase_id]
|
||||
if from_date:
|
||||
result = [s for s in result if s.fetched_at >= from_date]
|
||||
if to_date:
|
||||
result = [s for s in result if s.fetched_at <= to_date]
|
||||
return sorted(result, key=lambda s: s.fetched_at)
|
||||
|
||||
|
||||
class MockTelegramWriter:
|
||||
def __init__(self) -> None:
|
||||
@@ -279,6 +338,10 @@ class MockTelegramWriter:
|
||||
link_type = 'approval' if requires_approval else 'public'
|
||||
return f'https://t.me/+{link_type}_link_{self.invite_link_counter}_{chat_id}'
|
||||
|
||||
async def get_post_views(self, post_url: str) -> int | None:
|
||||
"""Mock implementation returns None (TDLib not integrated)."""
|
||||
return None
|
||||
|
||||
|
||||
class MockJWTEncoder:
|
||||
def encode_access_token(self, user_id: uuid.UUID, telegram_id: int, username: str | None = None) -> str:
|
||||
|
||||
Reference in New Issue
Block a user