indie-status-page/app/models/models.py

160 lines
No EOL
7 KiB
Python

import uuid
from datetime import datetime
from sqlalchemy import Boolean, DateTime, Integer, String, Text, ForeignKey, Float
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
def _uuid_str() -> str:
return str(uuid.uuid4())
class Service(Base):
__tablename__ = "services"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
organization_id: Mapped[str | None] = mapped_column(
String(36), ForeignKey("organizations.id"), nullable=True, index=True
)
name: Mapped[str] = mapped_column(String(100), nullable=False)
slug: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True)
description: Mapped[str | None] = mapped_column(Text, nullable=True)
group_name: Mapped[str | None] = mapped_column(String(50), nullable=True)
position: Mapped[int] = mapped_column(Integer, default=0)
is_visible: Mapped[bool] = mapped_column(Boolean, default=True)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
updated_at: Mapped[datetime] = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
)
incidents: Mapped[list["Incident"]] = relationship(back_populates="service")
monitors: Mapped[list["Monitor"]] = relationship(back_populates="service")
class Incident(Base):
__tablename__ = "incidents"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
service_id: Mapped[str] = mapped_column(
String(36), ForeignKey("services.id"), nullable=False, index=True
)
title: Mapped[str] = mapped_column(String(200), nullable=False)
status: Mapped[str] = mapped_column(String(20), nullable=False, index=True)
# investigating | identified | monitoring | resolved
severity: Mapped[str] = mapped_column(String(20), nullable=False)
# minor | major | outage
started_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.utcnow)
resolved_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
updated_at: Mapped[datetime] = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
)
service: Mapped["Service"] = relationship(back_populates="incidents")
updates: Mapped[list["IncidentUpdate"]] = relationship(
back_populates="incident", cascade="all, delete-orphan"
)
notifications: Mapped[list["NotificationLog"]] = relationship(back_populates="incident")
class IncidentUpdate(Base):
__tablename__ = "incident_updates"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
incident_id: Mapped[str] = mapped_column(
String(36), ForeignKey("incidents.id"), nullable=False, index=True
)
status: Mapped[str] = mapped_column(String(20), nullable=False)
body: Mapped[str] = mapped_column(Text, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
incident: Mapped["Incident"] = relationship(back_populates="updates")
class Monitor(Base):
__tablename__ = "monitors"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
organization_id: Mapped[str | None] = mapped_column(
String(36), ForeignKey("organizations.id"), nullable=True, index=True
)
service_id: Mapped[str] = mapped_column(
String(36), ForeignKey("services.id"), nullable=False, index=True
)
url: Mapped[str] = mapped_column(String(500), nullable=False)
method: Mapped[str] = mapped_column(String(10), default="GET")
expected_status: Mapped[int] = mapped_column(Integer, default=200)
timeout_seconds: Mapped[int] = mapped_column(Integer, default=10)
interval_seconds: Mapped[int] = mapped_column(Integer, default=60)
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
updated_at: Mapped[datetime] = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
)
service: Mapped["Service"] = relationship(back_populates="monitors")
results: Mapped[list["MonitorResult"]] = relationship(
back_populates="monitor", cascade="all, delete-orphan"
)
class MonitorResult(Base):
__tablename__ = "monitor_results"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
monitor_id: Mapped[str] = mapped_column(
String(36), ForeignKey("monitors.id"), nullable=False, index=True
)
status: Mapped[str] = mapped_column(String(20), nullable=False) # up | down | degraded
response_time_ms: Mapped[int | None] = mapped_column(Integer, nullable=True)
status_code: Mapped[int | None] = mapped_column(Integer, nullable=True)
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
checked_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.utcnow)
monitor: Mapped["Monitor"] = relationship(back_populates="results")
class Subscriber(Base):
__tablename__ = "subscribers"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
organization_id: Mapped[str | None] = mapped_column(
String(36), ForeignKey("organizations.id"), nullable=True, index=True
)
email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, index=True)
is_confirmed: Mapped[bool] = mapped_column(Boolean, default=False)
confirm_token: Mapped[str | None] = mapped_column(String(100), nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
notifications: Mapped[list["NotificationLog"]] = relationship(back_populates="subscriber")
class NotificationLog(Base):
__tablename__ = "notification_logs"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
incident_id: Mapped[str] = mapped_column(
String(36), ForeignKey("incidents.id"), nullable=False, index=True
)
subscriber_id: Mapped[str] = mapped_column(
String(36), ForeignKey("subscribers.id"), nullable=False
)
channel: Mapped[str] = mapped_column(String(20), nullable=False) # email | webhook
status: Mapped[str] = mapped_column(String(20), nullable=False) # sent | failed
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
incident: Mapped["Incident"] = relationship(back_populates="notifications")
subscriber: Mapped["Subscriber"] = relationship(back_populates="notifications")
class SiteSetting(Base):
__tablename__ = "site_settings"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
key: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True)
value: Mapped[str | None] = mapped_column(Text, nullable=True)
updated_at: Mapped[datetime] = mapped_column(
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
)