169 lines
6.4 KiB
Python
169 lines
6.4 KiB
Python
from datetime import datetime
|
|
from enum import Enum
|
|
|
|
from sqlalchemy import Boolean, DateTime, Enum as SqlEnum, ForeignKey, Integer, JSON
|
|
from sqlalchemy import String, Text, UniqueConstraint
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database import Base
|
|
|
|
|
|
class WatchType(str, Enum):
|
|
artist = "artist"
|
|
event = "event"
|
|
|
|
|
|
class RegionScope(str, Enum):
|
|
hamburg = "hamburg"
|
|
germany = "germany"
|
|
|
|
|
|
class NotificationType(str, Enum):
|
|
discovery = "discovery"
|
|
reminder = "reminder"
|
|
|
|
|
|
class NotificationStatus(str, Enum):
|
|
sent = "sent"
|
|
skipped = "skipped"
|
|
failed = "failed"
|
|
|
|
|
|
class ProviderStatusType(str, Enum):
|
|
ok = "ok"
|
|
blocked = "blocked"
|
|
error = "error"
|
|
|
|
|
|
class SourceStatusType(str, Enum):
|
|
pending = "pending"
|
|
ok = "ok"
|
|
no_match = "no_match"
|
|
error = "error"
|
|
|
|
|
|
class WatchItem(Base):
|
|
__tablename__ = "watch_items"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
|
name: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
|
|
watch_type: Mapped[WatchType] = mapped_column(SqlEnum(WatchType), nullable=False)
|
|
region_scope: Mapped[RegionScope] = mapped_column(SqlEnum(RegionScope), nullable=False)
|
|
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, nullable=False
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime,
|
|
default=datetime.utcnow,
|
|
onupdate=datetime.utcnow,
|
|
nullable=False,
|
|
)
|
|
|
|
tracked_events: Mapped[list["TrackedEvent"]] = relationship(
|
|
back_populates="watch_item", cascade="all, delete-orphan"
|
|
)
|
|
sources: Mapped[list["WatchSource"]] = relationship(
|
|
back_populates="watch_item", cascade="all, delete-orphan"
|
|
)
|
|
|
|
|
|
class WatchSource(Base):
|
|
__tablename__ = "watch_sources"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
|
watch_item_id: Mapped[int] = mapped_column(ForeignKey("watch_items.id"), nullable=False)
|
|
label: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
url: Mapped[str] = mapped_column(String(1024), nullable=False)
|
|
parser_type: Mapped[str] = mapped_column(String(50), default="auto", nullable=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
last_status: Mapped[SourceStatusType] = mapped_column(
|
|
SqlEnum(SourceStatusType), default=SourceStatusType.pending, nullable=False
|
|
)
|
|
last_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
last_checked_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, nullable=False
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime,
|
|
default=datetime.utcnow,
|
|
onupdate=datetime.utcnow,
|
|
nullable=False,
|
|
)
|
|
|
|
watch_item: Mapped[WatchItem] = relationship(back_populates="sources")
|
|
|
|
|
|
class TrackedEvent(Base):
|
|
__tablename__ = "tracked_events"
|
|
__table_args__ = (
|
|
UniqueConstraint("watch_item_id", "source", "external_id", name="uq_watch_event"),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
|
watch_item_id: Mapped[int] = mapped_column(ForeignKey("watch_items.id"), nullable=False)
|
|
source: Mapped[str] = mapped_column(String(50), nullable=False, default="ticketmaster")
|
|
external_id: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
title: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
matched_term: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
venue_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
city: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
country_code: Mapped[str | None] = mapped_column(String(10), nullable=True)
|
|
event_date: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
ticket_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
|
|
image_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
|
|
is_ticket_purchased: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
purchased_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
discovery_notified_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
reminder_notified_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
first_seen_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, nullable=False
|
|
)
|
|
last_seen_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, nullable=False
|
|
)
|
|
raw_payload: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
|
|
watch_item: Mapped[WatchItem] = relationship(back_populates="tracked_events")
|
|
notifications: Mapped[list["NotificationLog"]] = relationship(
|
|
back_populates="tracked_event", cascade="all, delete-orphan"
|
|
)
|
|
|
|
|
|
class NotificationLog(Base):
|
|
__tablename__ = "notification_logs"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
|
tracked_event_id: Mapped[int] = mapped_column(
|
|
ForeignKey("tracked_events.id"), nullable=False
|
|
)
|
|
notification_type: Mapped[NotificationType] = mapped_column(
|
|
SqlEnum(NotificationType), nullable=False
|
|
)
|
|
status: Mapped[NotificationStatus] = mapped_column(
|
|
SqlEnum(NotificationStatus), nullable=False
|
|
)
|
|
message: Mapped[str] = mapped_column(Text, nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, nullable=False
|
|
)
|
|
|
|
tracked_event: Mapped[TrackedEvent] = relationship(back_populates="notifications")
|
|
|
|
|
|
class ProviderStatus(Base):
|
|
__tablename__ = "provider_statuses"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
|
|
provider_name: Mapped[str] = mapped_column(String(50), unique=True, nullable=False)
|
|
status: Mapped[ProviderStatusType] = mapped_column(
|
|
SqlEnum(ProviderStatusType), nullable=False
|
|
)
|
|
message: Mapped[str] = mapped_column(Text, nullable=False)
|
|
last_checked_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, nullable=False
|
|
)
|
|
last_success_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|