"""Subscription model.""" from datetime import datetime from enum import Enum from sqlalchemy import String, DateTime, ForeignKey, Integer, Boolean, Enum as SQLEnum from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database import Base class SubscriptionTier(str, Enum): """Subscription tiers matching frontend pricing.""" STARTER = "starter" # Free PROFESSIONAL = "professional" # $4.99/mo ENTERPRISE = "enterprise" # $9.99/mo class SubscriptionStatus(str, Enum): """Subscription status.""" ACTIVE = "active" CANCELLED = "cancelled" EXPIRED = "expired" PENDING = "pending" # Plan configuration TIER_CONFIG = { SubscriptionTier.STARTER: { "name": "Starter", "price": 0, "domain_limit": 3, "check_frequency": "daily", # daily, hourly "history_days": 0, # No history "features": { "email_alerts": True, "priority_alerts": False, "full_whois": False, "expiration_tracking": False, "api_access": False, "webhooks": False, } }, SubscriptionTier.PROFESSIONAL: { "name": "Professional", "price": 4.99, "domain_limit": 25, "check_frequency": "daily", "history_days": 30, "features": { "email_alerts": True, "priority_alerts": True, "full_whois": True, "expiration_tracking": True, "api_access": False, "webhooks": False, } }, SubscriptionTier.ENTERPRISE: { "name": "Enterprise", "price": 9.99, "domain_limit": 100, "check_frequency": "hourly", "history_days": -1, # Unlimited "features": { "email_alerts": True, "priority_alerts": True, "full_whois": True, "expiration_tracking": True, "api_access": True, "webhooks": True, } }, } class Subscription(Base): """Subscription model for tracking user plans.""" __tablename__ = "subscriptions" id: Mapped[int] = mapped_column(primary_key=True, index=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), unique=True, nullable=False) # Plan details tier: Mapped[SubscriptionTier] = mapped_column( SQLEnum(SubscriptionTier), default=SubscriptionTier.STARTER ) status: Mapped[SubscriptionStatus] = mapped_column( SQLEnum(SubscriptionStatus), default=SubscriptionStatus.ACTIVE ) # Limits domain_limit: Mapped[int] = mapped_column(Integer, default=3) # Payment info (for future integration) payment_reference: Mapped[str | None] = mapped_column(String(255), nullable=True) # Dates started_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) expires_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) cancelled_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) # Relationship user: Mapped["User"] = relationship("User", back_populates="subscription") @property def is_active(self) -> bool: """Check if subscription is currently active.""" if self.status != SubscriptionStatus.ACTIVE: return False if self.expires_at and self.expires_at < datetime.utcnow(): return False return True @property def config(self) -> dict: """Get configuration for this subscription tier.""" return TIER_CONFIG.get(self.tier, TIER_CONFIG[SubscriptionTier.STARTER]) @property def max_domains(self) -> int: """Get maximum allowed domains for this subscription.""" return self.config["domain_limit"] @property def check_frequency(self) -> str: """Get check frequency for this subscription.""" return self.config["check_frequency"] @property def history_days(self) -> int: """Get history retention days. -1 = unlimited.""" return self.config["history_days"] def has_feature(self, feature: str) -> bool: """Check if subscription has a specific feature.""" return self.config.get("features", {}).get(feature, False) def __repr__(self) -> str: return f""