All checks were successful
PostgreSQL Compatibility Matrix / PG14 smoke (pull_request) Successful in 12s
PostgreSQL Compatibility Matrix / PG15 smoke (pull_request) Successful in 11s
PostgreSQL Compatibility Matrix / PG16 smoke (pull_request) Successful in 9s
PostgreSQL Compatibility Matrix / PG17 smoke (pull_request) Successful in 10s
PostgreSQL Compatibility Matrix / PG18 smoke (pull_request) Successful in 11s
This commit introduces optional `first_name` and `last_name` fields to the user model, including database migrations, backend, and frontend support. It enhances user profiles, updates user creation and editing flows, and refines the UI to display full names where available.
181 lines
9.8 KiB
Python
181 lines
9.8 KiB
Python
from datetime import datetime
|
|
from sqlalchemy import JSON, Boolean, DateTime, Float, ForeignKey, Integer, String, Text, UniqueConstraint, func
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
from app.core.db import Base
|
|
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
email: Mapped[str] = mapped_column(String(255), unique=True, index=True, nullable=False)
|
|
first_name: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
last_name: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
role: Mapped[str] = mapped_column(String(20), nullable=False, default="viewer")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
|
|
|
audit_logs: Mapped[list["AuditLog"]] = relationship(back_populates="user")
|
|
owned_targets: Mapped[list["TargetOwner"]] = relationship(
|
|
back_populates="user",
|
|
cascade="all, delete-orphan",
|
|
foreign_keys="TargetOwner.user_id",
|
|
)
|
|
|
|
|
|
class Target(Base):
|
|
__tablename__ = "targets"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(120), unique=True, index=True, nullable=False)
|
|
host: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
port: Mapped[int] = mapped_column(Integer, nullable=False, default=5432)
|
|
dbname: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
username: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
encrypted_password: Mapped[str] = mapped_column(Text, nullable=False)
|
|
sslmode: Mapped[str] = mapped_column(String(20), nullable=False, default="prefer")
|
|
use_pg_stat_statements: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
|
tags: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
|
|
|
metrics: Mapped[list["Metric"]] = relationship(back_populates="target", cascade="all, delete-orphan")
|
|
query_stats: Mapped[list["QueryStat"]] = relationship(back_populates="target", cascade="all, delete-orphan")
|
|
alert_definitions: Mapped[list["AlertDefinition"]] = relationship(back_populates="target", cascade="all, delete-orphan")
|
|
owners: Mapped[list["TargetOwner"]] = relationship(back_populates="target", cascade="all, delete-orphan")
|
|
|
|
|
|
class TargetOwner(Base):
|
|
__tablename__ = "target_owners"
|
|
__table_args__ = (UniqueConstraint("target_id", "user_id", name="uq_target_owner_target_user"),)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
target_id: Mapped[int] = mapped_column(ForeignKey("targets.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
assigned_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
|
|
|
|
target: Mapped[Target] = relationship(back_populates="owners")
|
|
user: Mapped[User] = relationship(foreign_keys=[user_id], back_populates="owned_targets")
|
|
|
|
|
|
class Metric(Base):
|
|
__tablename__ = "metrics"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
target_id: Mapped[int] = mapped_column(ForeignKey("targets.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
ts: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now(), index=True)
|
|
metric_name: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
|
|
value: Mapped[float] = mapped_column(Float, nullable=False)
|
|
labels: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
|
|
target: Mapped[Target] = relationship(back_populates="metrics")
|
|
|
|
|
|
class QueryStat(Base):
|
|
__tablename__ = "query_stats"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
target_id: Mapped[int] = mapped_column(ForeignKey("targets.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
ts: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now(), index=True)
|
|
queryid: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
calls: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
total_time: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
|
mean_time: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
|
rows: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
query_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
target: Mapped[Target] = relationship(back_populates="query_stats")
|
|
|
|
|
|
class AuditLog(Base):
|
|
__tablename__ = "audit_logs"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
ts: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now(), index=True)
|
|
user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id"), nullable=True, index=True)
|
|
action: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
payload: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
|
|
user: Mapped[User | None] = relationship(back_populates="audit_logs")
|
|
|
|
|
|
class AlertDefinition(Base):
|
|
__tablename__ = "alert_definitions"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
target_id: Mapped[int | None] = mapped_column(ForeignKey("targets.id", ondelete="CASCADE"), nullable=True, index=True)
|
|
sql_text: Mapped[str] = mapped_column(Text, nullable=False)
|
|
comparison: Mapped[str] = mapped_column(String(10), nullable=False, default="gte")
|
|
warning_threshold: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
alert_threshold: Mapped[float] = mapped_column(Float, nullable=False)
|
|
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
|
created_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id"), nullable=True, index=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now(), index=True)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
nullable=False,
|
|
server_default=func.now(),
|
|
onupdate=func.now(),
|
|
)
|
|
|
|
target: Mapped[Target | None] = relationship(back_populates="alert_definitions")
|
|
|
|
|
|
class EmailNotificationSettings(Base):
|
|
__tablename__ = "email_notification_settings"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
smtp_host: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
smtp_port: Mapped[int] = mapped_column(Integer, nullable=False, default=587)
|
|
smtp_username: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
encrypted_smtp_password: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
from_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
from_email: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
use_starttls: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
|
use_ssl: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
warning_subject_template: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
alert_subject_template: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
warning_body_template: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
alert_body_template: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
nullable=False,
|
|
server_default=func.now(),
|
|
onupdate=func.now(),
|
|
)
|
|
|
|
|
|
class ServiceInfoSettings(Base):
|
|
__tablename__ = "service_info_settings"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
current_version: Mapped[str] = mapped_column(String(64), nullable=False, default="0.1.0")
|
|
release_check_url: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
|
latest_version: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
update_available: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
last_checked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
last_check_error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
nullable=False,
|
|
server_default=func.now(),
|
|
onupdate=func.now(),
|
|
)
|
|
|
|
|
|
class AlertNotificationEvent(Base):
|
|
__tablename__ = "alert_notification_events"
|
|
__table_args__ = (UniqueConstraint("alert_key", "target_id", "severity", name="uq_alert_notif_event_key_target_sev"),)
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
alert_key: Mapped[str] = mapped_column(String(200), nullable=False, index=True)
|
|
target_id: Mapped[int] = mapped_column(ForeignKey("targets.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
severity: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
last_seen_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
|
|
last_sent_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
|