from datetime import datetime from sqlalchemy import ( Boolean, DateTime, ForeignKey, Integer, String, Text, UniqueConstraint, func ) from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database import Base class User(Base): __tablename__ = "users" id: Mapped[int] = mapped_column(Integer, primary_key=True) username: Mapped[str] = mapped_column(String(64), unique=True, nullable=False) email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False) hashed_password: Mapped[str | None] = mapped_column(String(255), nullable=True) keycloak_sub: Mapped[str | None] = mapped_column(String(255), unique=True, nullable=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) configs: Mapped[list["Config"]] = relationship("Config", back_populates="owner") class Config(Base): __tablename__ = "configs" id: Mapped[int] = mapped_column(Integer, primary_key=True) name: Mapped[str] = mapped_column(String(128), nullable=False) description: Mapped[str] = mapped_column(Text, default="") is_active: Mapped[bool] = mapped_column(Boolean, default=True) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now()) owner_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False) owner: Mapped["User"] = relationship("User", back_populates="configs") zones: Mapped[list["Zone"]] = relationship("Zone", back_populates="config", cascade="all, delete-orphan") interfaces: Mapped[list["Interface"]] = relationship("Interface", back_populates="config", cascade="all, delete-orphan") policies: Mapped[list["Policy"]] = relationship("Policy", back_populates="config", cascade="all, delete-orphan", order_by="Policy.position") rules: Mapped[list["Rule"]] = relationship("Rule", back_populates="config", cascade="all, delete-orphan", order_by="Rule.position") snat_entries: Mapped[list["Snat"]] = relationship("Snat", back_populates="config", cascade="all, delete-orphan") host_entries: Mapped[list["Host"]] = relationship("Host", back_populates="config", cascade="all, delete-orphan") params: Mapped[list["Param"]] = relationship("Param", back_populates="config", cascade="all, delete-orphan") class Zone(Base): __tablename__ = "zones" __table_args__ = (UniqueConstraint("config_id", "name", name="uq_zone_name_per_config"),) id: Mapped[int] = mapped_column(Integer, primary_key=True) config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False) name: Mapped[str] = mapped_column(String(32), nullable=False) type: Mapped[str] = mapped_column(String(16), nullable=False) options: Mapped[str] = mapped_column(Text, default="") config: Mapped["Config"] = relationship("Config", back_populates="zones") interfaces: Mapped[list["Interface"]] = relationship("Interface", back_populates="zone") class Interface(Base): __tablename__ = "interfaces" id: Mapped[int] = mapped_column(Integer, primary_key=True) config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False) name: Mapped[str] = mapped_column(String(32), nullable=False) zone_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("zones.id"), nullable=True) broadcast: Mapped[str] = mapped_column(String(64), default="detect") options: Mapped[str] = mapped_column(Text, default="") config: Mapped["Config"] = relationship("Config", back_populates="interfaces") zone: Mapped["Zone | None"] = relationship("Zone", back_populates="interfaces") class Policy(Base): __tablename__ = "policies" id: Mapped[int] = mapped_column(Integer, primary_key=True) config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False) src_zone_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("zones.id"), nullable=True) dst_zone_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("zones.id"), nullable=True) policy: Mapped[str] = mapped_column(String(16), nullable=False) log_level: Mapped[str] = mapped_column(String(16), default="") limit_burst: Mapped[str] = mapped_column(String(64), default="") connlimit_mask: Mapped[str] = mapped_column(String(32), default="") comment: Mapped[str] = mapped_column(Text, default="") position: Mapped[int] = mapped_column(Integer, default=0) config: Mapped["Config"] = relationship("Config", back_populates="policies") src_zone: Mapped["Zone | None"] = relationship("Zone", foreign_keys=[src_zone_id]) dst_zone: Mapped["Zone | None"] = relationship("Zone", foreign_keys=[dst_zone_id]) class Rule(Base): __tablename__ = "rules" id: Mapped[int] = mapped_column(Integer, primary_key=True) config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False) action: Mapped[str] = mapped_column(String(32), nullable=False) src_zone_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("zones.id"), nullable=True) dst_zone_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("zones.id"), nullable=True) src_ip: Mapped[str] = mapped_column(String(64), default="") dst_ip: Mapped[str] = mapped_column(String(64), default="") proto: Mapped[str] = mapped_column(String(16), default="") dport: Mapped[str] = mapped_column(String(64), default="") sport: Mapped[str] = mapped_column(String(64), default="") origdest: Mapped[str] = mapped_column(String(128), default="") rate_limit: Mapped[str] = mapped_column(String(64), default="") user_group: Mapped[str] = mapped_column(String(64), default="") mark: Mapped[str] = mapped_column(String(32), default="") connlimit: Mapped[str] = mapped_column(String(32), default="") time: Mapped[str] = mapped_column(String(128), default="") headers: Mapped[str] = mapped_column(String(128), default="") switch_name: Mapped[str] = mapped_column(String(32), default="") helper: Mapped[str] = mapped_column(String(32), default="") comment: Mapped[str] = mapped_column(Text, default="") position: Mapped[int] = mapped_column(Integer, default=0) config: Mapped["Config"] = relationship("Config", back_populates="rules") src_zone: Mapped["Zone | None"] = relationship("Zone", foreign_keys=[src_zone_id]) dst_zone: Mapped["Zone | None"] = relationship("Zone", foreign_keys=[dst_zone_id]) class Snat(Base): __tablename__ = "snat" id: Mapped[int] = mapped_column(Integer, primary_key=True) config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False) source_network: Mapped[str] = mapped_column(String(64), nullable=False) out_interface: Mapped[str] = mapped_column(String(32), nullable=False) to_address: Mapped[str] = mapped_column(String(64), default="") proto: Mapped[str] = mapped_column(String(16), default="") port: Mapped[str] = mapped_column(String(64), default="") ipsec: Mapped[str] = mapped_column(String(128), default="") mark: Mapped[str] = mapped_column(String(32), default="") user_group: Mapped[str] = mapped_column(String(64), default="") switch_name: Mapped[str] = mapped_column(String(32), default="") origdest: Mapped[str] = mapped_column(String(128), default="") probability: Mapped[str] = mapped_column(String(16), default="") comment: Mapped[str] = mapped_column(Text, default="") config: Mapped["Config"] = relationship("Config", back_populates="snat_entries") class Host(Base): __tablename__ = "hosts" id: Mapped[int] = mapped_column(Integer, primary_key=True) config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False) zone_id: Mapped[int] = mapped_column(Integer, ForeignKey("zones.id"), nullable=False) interface: Mapped[str] = mapped_column(String(32), nullable=False) subnet: Mapped[str] = mapped_column(String(64), nullable=False) options: Mapped[str] = mapped_column(Text, default="") config: Mapped["Config"] = relationship("Config", back_populates="host_entries") zone: Mapped["Zone"] = relationship("Zone") class Param(Base): __tablename__ = "params" id: Mapped[int] = mapped_column(Integer, primary_key=True) config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False) name: Mapped[str] = mapped_column(String(64), nullable=False) value: Mapped[str] = mapped_column(String(255), nullable=False) config: Mapped["Config"] = relationship("Config", back_populates="params")