Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
- Add delete user functionality with cascade deletion of all user data - Fix OAuth URLs to include /api/v1 path - Fix token storage key consistency in OAuth callback - Update user model to cascade delete price alerts - Improve email templates with minimalist design - Add confirmation dialog for user deletion - Prevent deletion of admin users
57 lines
2.1 KiB
Python
57 lines
2.1 KiB
Python
"""Price Alert model for TLD price notifications."""
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
from sqlalchemy import String, Float, Boolean, DateTime, Integer, ForeignKey, UniqueConstraint
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database import Base
|
|
|
|
|
|
class PriceAlert(Base):
|
|
"""
|
|
Price Alert model for tracking user's TLD price subscriptions.
|
|
|
|
Users can subscribe to price alerts for specific TLDs and get notified
|
|
when prices change by a certain threshold.
|
|
"""
|
|
|
|
__tablename__ = "price_alerts"
|
|
__table_args__ = (
|
|
UniqueConstraint('user_id', 'tld', name='unique_user_tld_alert'),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
|
|
|
# User who created the alert
|
|
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False)
|
|
|
|
# TLD to monitor (without dot, e.g., "com", "io")
|
|
tld: Mapped[str] = mapped_column(String(50), index=True, nullable=False)
|
|
|
|
# Alert settings
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
|
|
# Optional: only alert if price drops below this threshold
|
|
target_price: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
|
|
|
|
# Optional: only alert if price changes by this percentage
|
|
threshold_percent: Mapped[float] = mapped_column(Float, default=5.0) # 5% default
|
|
|
|
# Track last notification to avoid spam
|
|
last_notified_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
|
|
last_notified_price: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
|
|
|
|
# Timestamps
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
|
)
|
|
|
|
# Relationship to user
|
|
user: Mapped["User"] = relationship("User", back_populates="price_alerts")
|
|
|
|
def __repr__(self) -> str:
|
|
status = "active" if self.is_active else "paused"
|
|
return f"<PriceAlert user={self.user_id} tld=.{self.tld} ({status})>"
|
|
|