import abc from datetime import datetime from src.services.publications import ( OrderProfile as PublicationOrderProfile, Sequence as PublicationSequence, Publication, ) from src.services.users.data import UserProfile from dataclasses import dataclass SubscriptionId = int @dataclass class SubscriptionCreateParams: user_id: int order_id: int @dataclass class Subscription: id: SubscriptionId user: UserProfile publication_order: PublicationOrderProfile sequence_seen: int start: datetime @dataclass class UpdateSubscription: id: int user_id: int publication_order_id: int | None = None sequence_seen: int | None = None start: datetime | None = None @dataclass class AvailableSubscriptionEntry: publication: Publication available_since: datetime order: PublicationOrderProfile sequence: PublicationSequence class SubscriptionRepo(abc.ABC): @abc.abstractmethod def get_subscriptions_for_user(self, user_id: int) -> list[Subscription]: pass @abc.abstractmethod def get_subscription_by_id(self, sub_id: SubscriptionId) -> Subscription | None: pass @abc.abstractmethod def create_subscription_for_user(self, user_id: int, order_id: int) -> Subscription: pass @abc.abstractmethod def delete_subscription(self, subscription_id: SubscriptionId): pass @abc.abstractmethod def update_subscription(self, subscription: UpdateSubscription) -> Subscription: pass @abc.abstractmethod def get_available_entries(self, user_id: int) -> dict[SubscriptionId, list[AvailableSubscriptionEntry]]: pass @abc.abstractmethod def get_unseen_available_subscription_entries(self, user_id: int) -> list[AvailableSubscriptionEntry]: """ Get all publication entries that _should_ be available to the user given the timeline but are newer than the `sequence_seen` value from the subscription """ pass class SubscriptionService: def __init__(self, repo: SubscriptionRepo): self._repo = repo def get_subscriptions(self, user_id: int) -> list[Subscription]: return self._repo.get_subscriptions_for_user(user_id) def get_updates(self, user_id: int) -> list[AvailableSubscriptionEntry]: return self._repo.get_unseen_available_subscription_entries(user_id) def get_all_available_entries(self, user_id: int) -> dict[SubscriptionId, list[AvailableSubscriptionEntry]]: return self._repo.get_available_entries(user_id) def create_suscription(self, params: SubscriptionCreateParams) -> Subscription: return self._repo.create_subscription_for_user(params.user_id, params.order_id) def delete_subcription(self, user_id: int, subscription_id: SubscriptionId): subscription = self._repo.get_subscription_by_id(subscription_id) if subscription is None: # TODO Domain error types raise RuntimeError('not found') if subscription.user.id != user_id: # TODO: Domain error types raise RuntimeError('Cannot delete a subscription for another user') self._repo.delete_subscription(subscription_id)