SDNmeeting / database /models.py
Che237
Deploy SD-MMMS FastAPI backend as Docker Space
900edd0
Raw
History Blame Contribute Delete
5.26 kB
import enum
from datetime import datetime, timezone
from sqlalchemy import (
Boolean,
Column,
DateTime,
Enum,
Float,
ForeignKey,
Integer,
String,
UniqueConstraint,
)
from sqlalchemy.orm import relationship
from .connection import Base
def _utcnow() -> datetime:
"""Naive UTC timestamp for TIMESTAMP WITHOUT TIME ZONE columns.
asyncpg rejects timezone-aware datetimes for naive TIMESTAMP columns, so we
normalise to naive UTC at the application layer.
"""
return datetime.now(timezone.utc).replace(tzinfo=None)
class UserRole(str, enum.Enum):
admin = "admin"
moderator = "moderator"
participant = "participant"
class MeetingStatus(str, enum.Enum):
active = "active"
ended = "ended"
class MeetingRole(str, enum.Enum):
"""Role a user holds *within a specific meeting* (distinct from the global
account role). The meeting creator is the host."""
host = "host"
moderator = "moderator"
participant = "participant"
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String(50), unique=True, index=True, nullable=False)
email = Column(String(255), unique=True, index=True, nullable=False)
hashed_password = Column(String(255), nullable=False)
role = Column(Enum(UserRole), default=UserRole.participant, nullable=False)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=_utcnow)
meetings = relationship(
"Meeting",
back_populates="host",
foreign_keys="Meeting.host_id",
)
microphone_configs = relationship("MicrophoneConfig", back_populates="user")
memberships = relationship(
"MeetingMember",
back_populates="user",
cascade="all, delete-orphan",
)
class Meeting(Base):
__tablename__ = "meetings"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(200), nullable=False)
description = Column(String(500), nullable=True)
host_id = Column(Integer, ForeignKey("users.id"), nullable=False)
invite_token = Column(String(64), unique=True, index=True, nullable=True)
created_at = Column(DateTime, default=_utcnow)
ended_at = Column(DateTime, nullable=True)
status = Column(Enum(MeetingStatus), default=MeetingStatus.active)
host = relationship("User", back_populates="meetings", foreign_keys=[host_id])
microphone_configs = relationship("MicrophoneConfig", back_populates="meeting")
speech_logs = relationship("SpeechLog", back_populates="meeting")
members = relationship(
"MeetingMember",
back_populates="meeting",
cascade="all, delete-orphan",
)
class MeetingMember(Base):
"""Per-meeting membership with a meeting-scoped role."""
__tablename__ = "meeting_members"
__table_args__ = (
UniqueConstraint("meeting_id", "user_id", name="uq_meeting_member"),
)
id = Column(Integer, primary_key=True, index=True)
meeting_id = Column(Integer, ForeignKey("meetings.id"), nullable=False, index=True)
user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
role = Column(
Enum(MeetingRole), default=MeetingRole.participant, nullable=False
)
joined_at = Column(DateTime, default=_utcnow)
meeting = relationship("Meeting", back_populates="members")
user = relationship("User", back_populates="memberships")
class MicrophoneConfig(Base):
__tablename__ = "microphone_configs"
id = Column(Integer, primary_key=True, index=True)
meeting_id = Column(Integer, ForeignKey("meetings.id"), nullable=False)
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
name = Column(String(100), nullable=False)
priority = Column(Integer, default=5)
is_chairman = Column(Boolean, default=False)
is_muted = Column(Boolean, default=False)
created_at = Column(DateTime, default=_utcnow)
meeting = relationship("Meeting", back_populates="microphone_configs")
user = relationship("User", back_populates="microphone_configs")
speech_logs = relationship("SpeechLog", back_populates="microphone")
class SpeechLog(Base):
__tablename__ = "speech_logs"
id = Column(Integer, primary_key=True, index=True)
meeting_id = Column(Integer, ForeignKey("meetings.id"), nullable=False)
microphone_id = Column(
Integer, ForeignKey("microphone_configs.id"), nullable=False
)
start_time = Column(DateTime, default=_utcnow)
end_time = Column(DateTime, nullable=True)
peak_db = Column(Float, default=-100.0)
avg_db = Column(Float, default=-100.0)
meeting = relationship("Meeting", back_populates="speech_logs")
microphone = relationship("MicrophoneConfig", back_populates="speech_logs")
class SystemDiagnostic(Base):
__tablename__ = "system_diagnostics"
id = Column(Integer, primary_key=True, index=True)
timestamp = Column(DateTime, default=_utcnow, index=True)
cpu_usage = Column(Float, default=0.0)
memory_usage = Column(Float, default=0.0)
audio_latency_ms = Column(Float, default=0.0)
buffer_health = Column(Float, default=100.0)
packet_loss = Column(Float, default=0.0)