Files
kmtnflower/backend/app/models.py
T

208 lines
7.4 KiB
Python

from datetime import datetime
from sqlalchemy import (
Column,
DateTime,
Float,
Integer,
LargeBinary,
String,
Text,
Boolean,
Date,
ForeignKey,
UniqueConstraint,
Index,
)
from sqlalchemy.orm import DeclarativeBase, relationship
class Base(DeclarativeBase):
pass
class Show(Base):
__tablename__ = "shows"
id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(String(200), nullable=False)
description = Column(Text, nullable=False)
host = Column(String(100), nullable=False)
genre = Column(String(80), nullable=False)
show_art_url = Column(String(500), nullable=True)
hero_image_url = Column(String(500), nullable=True)
display_order = Column(Integer, nullable=False, default=0)
active = Column(Boolean, default=True)
schedules = relationship("ShowSchedule", back_populates="show", cascade="all, delete-orphan")
class ShowSchedule(Base):
__tablename__ = "show_schedules"
id = Column(Integer, primary_key=True, autoincrement=True)
show_id = Column(Integer, ForeignKey("shows.id", ondelete="CASCADE"), nullable=False)
day_of_week = Column(Integer, nullable=False)
time = Column(String(10), nullable=False)
show = relationship("Show", back_populates="schedules")
__table_args__ = (
UniqueConstraint("show_id", "day_of_week", "time", name="uq_show_sched"),
)
class Event(Base):
__tablename__ = "events"
id = Column(Integer, primary_key=True, autoincrement=True)
date = Column(Date, nullable=False)
title = Column(String(200), nullable=False)
description = Column(Text, nullable=False)
location = Column(String(200), nullable=False)
icon = Column(String(10), nullable=False)
rsvp_url = Column(String(500), nullable=True)
active = Column(Boolean, default=True)
class StationConfig(Base):
__tablename__ = "station_config"
id = Column(Integer, primary_key=True, autoincrement=True)
key = Column(String(20), unique=True, nullable=False, default="default")
# Identity
callsign = Column(String(10), nullable=False, default="KMTN")
name_primary = Column(String(100), nullable=False, default="KMountain")
name_secondary = Column(String(100), nullable=False, default="Flower Radio")
tagline = Column(String(200), nullable=False, default="Community Radio — Est. 1987")
frequency = Column(String(10), nullable=False, default="98.7 FM")
founded_year = Column(Integer, nullable=False, default=1987)
# Nonprofit
nonprofit_type = Column(String(10), nullable=False, default="501(c)(3)")
ein = Column(String(20), nullable=False, default="84-XXXXXXX")
# Images (URL strings relative to app root)
logo_url = Column(String(500), nullable=False, default="svg/small-flower.svg")
hero_background_url = Column(String(500), nullable=False, default="svg/mountain-landscape.svg")
hero_icon_url = Column(String(500), nullable=False, default="svg/orange-flower.svg")
hero_divider_url = Column(String(500), nullable=False, default="svg/mountain-divider.svg")
# Contact
address = Column(Text, nullable=False, default="42 Pine Street\nMountain View, CO 80424")
phone = Column(String(30), nullable=False, default="(970) 555-0198")
email = Column(String(100), nullable=False, default="hello@kmountainflower.org")
website = Column(String(200), nullable=False, default="kmountainflower.org")
# Donation
donation_url = Column(String(500), nullable=False, default="")
# Stream
stream_url = Column(String(500), nullable=False, default="")
stream_metadata_url = Column(String(500), nullable=False, default="")
# Mobile app download links
play_store_icon_url = Column(String(500), nullable=False, default="")
play_store_url = Column(String(500), nullable=False, default="")
app_store_embed_html = Column(Text, nullable=False, default="")
class HistoryEntry(Base):
__tablename__ = "history_entries"
id = Column(Integer, primary_key=True, autoincrement=True)
year = Column(Integer, nullable=False)
title = Column(String(200), nullable=False)
body = Column(Text, nullable=False)
display_order = Column(Integer, nullable=False)
active = Column(Boolean, default=True)
class TeamMember(Base):
__tablename__ = "team_members"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100), nullable=False)
title = Column(String(150), nullable=False)
bio = Column(Text, nullable=True)
photo_url = Column(String(500), nullable=True)
display_order = Column(Integer, nullable=False)
active = Column(Boolean, default=True)
class CommunityHighlight(Base):
__tablename__ = "community_highlights"
id = Column(Integer, primary_key=True, autoincrement=True)
icon = Column(String(10), nullable=False)
title = Column(String(200), nullable=False)
description = Column(Text, nullable=False)
display_order = Column(Integer, nullable=False)
active = Column(Boolean, default=True)
class Underwriter(Base):
__tablename__ = "underwriters"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100), nullable=False)
logo_url = Column(String(500), nullable=True)
description = Column(Text, nullable=False)
website_url = Column(String(500), nullable=True)
display_order = Column(Integer, nullable=False, default=0)
active = Column(Boolean, default=True)
class StorageBlob(Base):
__tablename__ = "storage_blobs"
id = Column(Integer, primary_key=True, autoincrement=True)
blob_id = Column(String(32), unique=True, nullable=False, index=True)
content_type = Column(String(100), nullable=False)
size = Column(Integer, nullable=False)
data = Column(LargeBinary, nullable=False)
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
# ── Visitor Stats ──────────────────────────────────────────────
class VisitorStatDaily(Base):
"""Daily aggregated visitor statistics."""
__tablename__ = "visitor_stats_daily"
id = Column(Integer, primary_key=True, autoincrement=True)
date = Column(Date, nullable=False, unique=True)
unique_visitors = Column(Integer, nullable=False, default=0)
__table_args__ = (
Index("idx_visitor_stats_date", "date"),
)
class VisitorStatGeo(Base):
"""Geographic breakdown of visitors per day."""
__tablename__ = "visitor_stats_geo"
id = Column(Integer, primary_key=True, autoincrement=True)
date = Column(Date, nullable=False)
country = Column(String(100), nullable=True)
country_code = Column(String(10), nullable=True)
city = Column(String(200), nullable=True)
latitude = Column(Float, nullable=True)
longitude = Column(Float, nullable=True)
visitor_count = Column(Integer, nullable=False, default=0)
__table_args__ = (
Index("idx_visitor_stats_geo_date", "date"),
Index("idx_visitor_stats_geo_country", "country_code"),
)
class LogParseState(Base):
"""Tracks the last successfully parsed log date."""
__tablename__ = "log_parse_state"
id = Column(Integer, primary_key=True, autoincrement=True)
key = Column(String(20), unique=True, nullable=False, default="default")
last_parsed_date = Column(Date, nullable=False)
updated_at = Column(DateTime, nullable=False, default=datetime.utcnow)