Files

233 lines
12 KiB
Python

from datetime import datetime
from sqlalchemy import BigInteger, Boolean, DateTime, Integer, String, func
from sqlalchemy.orm import Mapped, mapped_column
from .database import Base
class Admin(Base):
"""An admin-portal login. `is_admin` grants user/API-key/log management."""
__tablename__ = "radadmin_admins"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
username: Mapped[str] = mapped_column(String(64), nullable=False, unique=True)
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
is_admin: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
must_change_password: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
created_at: Mapped[datetime | None] = mapped_column(
DateTime, nullable=True, server_default=func.current_timestamp()
)
class Session(Base):
"""An opaque login token handed to the browser (Authorization: Bearer)."""
__tablename__ = "radadmin_sessions"
token: Mapped[str] = mapped_column(String(64), primary_key=True)
admin_id: Mapped[int] = mapped_column(Integer, nullable=False)
created_at: Mapped[datetime | None] = mapped_column(
DateTime, nullable=True, server_default=func.current_timestamp()
)
expires_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)
class ApiKey(Base):
"""A programmatic key (X-API-Key). Only the hash is stored."""
__tablename__ = "radadmin_api_keys"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
name: Mapped[str] = mapped_column(String(64), nullable=False)
key_prefix: Mapped[str] = mapped_column(String(16), nullable=False)
key_hash: Mapped[str] = mapped_column(String(255), nullable=False)
created_by: Mapped[str | None] = mapped_column(String(64), nullable=True)
created_at: Mapped[datetime | None] = mapped_column(
DateTime, nullable=True, server_default=func.current_timestamp()
)
last_used_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
revoked: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
class LogEntry(Base):
"""One activity-log row per state-changing action or auth event."""
__tablename__ = "radadmin_logs"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
username: Mapped[str | None] = mapped_column(String(64), nullable=True)
action: Mapped[str] = mapped_column(String(64), nullable=False)
detail: Mapped[str | None] = mapped_column(String(512), nullable=True)
ip_address: Mapped[str | None] = mapped_column(String(45), nullable=True)
created_at: Mapped[datetime | None] = mapped_column(
DateTime, nullable=True, server_default=func.current_timestamp()
)
class Customer(Base):
__tablename__ = "customers"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
username: Mapped[str] = mapped_column(String(64), nullable=False)
mac_address: Mapped[str] = mapped_column(String(17), nullable=False)
status: Mapped[str] = mapped_column(String(10), nullable=False, default="new")
created_at: Mapped[datetime | None] = mapped_column(
DateTime, nullable=True, server_default=func.current_timestamp()
)
class RadadminClient(Base):
"""Human-only client metadata (name/phone/alias), keyed by MAC. RADIUS ignores this."""
__tablename__ = "radadmin_clients"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
# Not DB-unique on its own — uniqueness is enforced only among live rows by the
# generated `active_mac` column (see radadmin_schema.sql). Soft-deleted rows
# (deleted_at set) may share a mac_address with the live row and each other.
mac_address: Mapped[str] = mapped_column(String(17), nullable=False)
name: Mapped[str | None] = mapped_column(String(128), nullable=True)
phone: Mapped[str | None] = mapped_column(String(32), nullable=True)
alias: Mapped[str | None] = mapped_column(String(64), nullable=True)
# Mirror of the client's group (radusergroup) and billing status (customers):
# set on add, synced on edit, and kept frozen on the row after soft-delete so
# the deleted client's group/status survive their hard-deleted source rows.
groupname: Mapped[str | None] = mapped_column(String(64), nullable=True, default=None)
status: Mapped[str | None] = mapped_column(String(10), nullable=True, default=None)
created_at: Mapped[datetime | None] = mapped_column(
DateTime, nullable=True, server_default=func.current_timestamp()
)
# Soft delete: NULL = live, a timestamp = deleted. Deleted rows are never
# returned by the API and are kept only for restore/reference.
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, default=None)
class RadadminDevice(Base):
"""Human alias for a NAS/AP box, keyed by its AP MAC. RADIUS never reads this."""
__tablename__ = "radadmin_devices"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
mac_address: Mapped[str] = mapped_column(String(17), nullable=False, unique=True)
alias: Mapped[str | None] = mapped_column(String(64), nullable=True)
created_at: Mapped[datetime | None] = mapped_column(
DateTime, nullable=True, server_default=func.current_timestamp()
)
class Nas(Base):
__tablename__ = "nas"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
nasname: Mapped[str] = mapped_column(String(128), nullable=False)
shortname: Mapped[str | None] = mapped_column(String(32), nullable=True)
type: Mapped[str | None] = mapped_column(String(30), nullable=True, default="other")
ports: Mapped[int | None] = mapped_column(Integer, nullable=True)
secret: Mapped[str] = mapped_column(String(60), nullable=False, default="secret")
server: Mapped[str | None] = mapped_column(String(64), nullable=True)
community: Mapped[str | None] = mapped_column(String(50), nullable=True)
description: Mapped[str | None] = mapped_column(String(200), nullable=True, default="RADIUS Client")
class NasReload(Base):
__tablename__ = "nasreload"
nasipaddress: Mapped[str] = mapped_column(String(15), primary_key=True)
reloadtime: Mapped[datetime] = mapped_column(DateTime, nullable=False)
class RadCheck(Base):
__tablename__ = "radcheck"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
attribute: Mapped[str] = mapped_column(String(64), nullable=False, default="")
op: Mapped[str] = mapped_column(String(2), nullable=False, default="==")
value: Mapped[str] = mapped_column(String(253), nullable=False, default="")
class RadReply(Base):
__tablename__ = "radreply"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
attribute: Mapped[str] = mapped_column(String(64), nullable=False, default="")
op: Mapped[str] = mapped_column(String(2), nullable=False, default="=")
value: Mapped[str] = mapped_column(String(253), nullable=False, default="")
class RadGroupCheck(Base):
__tablename__ = "radgroupcheck"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
groupname: Mapped[str] = mapped_column(String(64), nullable=False, default="")
attribute: Mapped[str] = mapped_column(String(64), nullable=False, default="")
op: Mapped[str] = mapped_column(String(2), nullable=False, default="==")
value: Mapped[str] = mapped_column(String(253), nullable=False, default="")
class RadGroupReply(Base):
__tablename__ = "radgroupreply"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
groupname: Mapped[str] = mapped_column(String(64), nullable=False, default="")
attribute: Mapped[str] = mapped_column(String(64), nullable=False, default="")
op: Mapped[str] = mapped_column(String(2), nullable=False, default="=")
value: Mapped[str] = mapped_column(String(253), nullable=False, default="")
class RadUserGroup(Base):
__tablename__ = "radusergroup"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
groupname: Mapped[str] = mapped_column(String(64), nullable=False, default="")
priority: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
class RadAcct(Base):
__tablename__ = "radacct"
radacctid: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
acctsessionid: Mapped[str] = mapped_column(String(64), nullable=False, default="")
acctuniqueid: Mapped[str] = mapped_column(String(32), nullable=False, default="")
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
realm: Mapped[str | None] = mapped_column(String(64), nullable=True, default="")
nasipaddress: Mapped[str] = mapped_column(String(15), nullable=False, default="")
nasportid: Mapped[str | None] = mapped_column(String(32), nullable=True)
nasporttype: Mapped[str | None] = mapped_column(String(32), nullable=True)
acctstarttime: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
acctupdatetime: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
acctstoptime: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
acctinterval: Mapped[int | None] = mapped_column(Integer, nullable=True)
acctsessiontime: Mapped[int | None] = mapped_column(Integer, nullable=True)
acctauthentic: Mapped[str | None] = mapped_column(String(32), nullable=True)
connectinfo_start: Mapped[str | None] = mapped_column(String(128), nullable=True)
connectinfo_stop: Mapped[str | None] = mapped_column(String(128), nullable=True)
acctinputoctets: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
acctoutputoctets: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
calledstationid: Mapped[str] = mapped_column(String(50), nullable=False, default="")
callingstationid: Mapped[str] = mapped_column(String(50), nullable=False, default="")
acctterminatecause: Mapped[str] = mapped_column(String(32), nullable=False, default="")
servicetype: Mapped[str | None] = mapped_column(String(32), nullable=True)
framedprotocol: Mapped[str | None] = mapped_column(String(32), nullable=True)
framedipaddress: Mapped[str] = mapped_column(String(15), nullable=False, default="")
framedipv6address: Mapped[str] = mapped_column(String(45), nullable=False, default="")
framedipv6prefix: Mapped[str] = mapped_column(String(45), nullable=False, default="")
framedinterfaceid: Mapped[str] = mapped_column(String(44), nullable=False, default="")
delegatedipv6prefix: Mapped[str] = mapped_column(String(45), nullable=False, default="")
class_: Mapped[str | None] = mapped_column("class", String(64), nullable=True)
class RadPostAuth(Base):
__tablename__ = "radpostauth"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
pass_: Mapped[str] = mapped_column("pass", String(64), nullable=False, default="")
reply: Mapped[str] = mapped_column(String(32), nullable=False, default="")
authdate: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
class_: Mapped[str | None] = mapped_column("class", String(64), nullable=True)