added bot class and rbac style auth with dynamic help msg base on roles

This commit is contained in:
2026-03-16 19:24:57 -04:00
parent a19b1c7e60
commit 7d2fbaea43
7 changed files with 414 additions and 217 deletions

View File

@@ -2,7 +2,7 @@
from __future__ import annotations
from python.orm.richie.base import RichieBase, TableBase
from python.orm.richie.base import RichieBase, TableBase, TableBaseBig, TableBaseSmall
from python.orm.richie.congress import Bill, Legislator, Vote, VoteRecord
from python.orm.richie.contact import (
Contact,
@@ -12,7 +12,7 @@ from python.orm.richie.contact import (
RelationshipType,
)
from python.orm.richie.dead_letter_message import DeadLetterMessage
from python.orm.richie.signal_device import SignalDevice
from python.orm.richie.signal_device import DeviceRole, RoleRecord, SignalDevice
__all__ = [
"Bill",
@@ -20,12 +20,16 @@ __all__ = [
"ContactNeed",
"ContactRelationship",
"DeadLetterMessage",
"DeviceRole",
"RoleRecord",
"Legislator",
"Need",
"RelationshipType",
"RichieBase",
"SignalDevice",
"TableBase",
"TableBaseBig",
"TableBaseSmall",
"Vote",
"VoteRecord",
]

View File

@@ -4,7 +4,7 @@ from __future__ import annotations
from datetime import datetime
from sqlalchemy import DateTime, MetaData, func
from sqlalchemy import BigInteger, DateTime, MetaData, SmallInteger, func
from sqlalchemy.ext.declarative import AbstractConcreteBase
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
@@ -22,12 +22,9 @@ class RichieBase(DeclarativeBase):
)
class TableBase(AbstractConcreteBase, RichieBase):
"""Abstract concrete base for richie tables with IDs and timestamps."""
class _TableMixin:
"""Shared timestamp columns for all table bases."""
__abstract__ = True
id: Mapped[int] = mapped_column(primary_key=True)
created: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
server_default=func.now(),
@@ -37,3 +34,27 @@ class TableBase(AbstractConcreteBase, RichieBase):
server_default=func.now(),
onupdate=func.now(),
)
class TableBaseSmall(_TableMixin, AbstractConcreteBase, RichieBase):
"""Table with SmallInteger primary key."""
__abstract__ = True
id: Mapped[int] = mapped_column(SmallInteger, primary_key=True)
class TableBase(_TableMixin, AbstractConcreteBase, RichieBase):
"""Table with Integer primary key."""
__abstract__ = True
id: Mapped[int] = mapped_column(primary_key=True)
class TableBaseBig(_TableMixin, AbstractConcreteBase, RichieBase):
"""Table with BigInteger primary key."""
__abstract__ = True
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)

View File

@@ -1,17 +1,38 @@
"""Signal bot device registry models."""
"""Signal bot device and role ORM models."""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import DateTime, String
from sqlalchemy import DateTime, ForeignKey, SmallInteger, String, UniqueConstraint
from sqlalchemy.dialects.postgresql import ENUM
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.orm import Mapped, mapped_column, relationship
from python.orm.richie.base import TableBase
from python.orm.richie.base import TableBase, TableBaseSmall
from python.signal_bot.models import TrustLevel
class RoleRecord(TableBaseSmall):
"""Lookup table for RBAC roles, keyed by smallint."""
__tablename__ = "role"
name: Mapped[str] = mapped_column(String(50), unique=True)
class DeviceRole(TableBase):
"""Association between a device and a role."""
__tablename__ = "device_role"
__table_args__ = (
UniqueConstraint("device_id", "role_id", name="uq_device_role_device_role"),
{"schema": "main"},
)
device_id: Mapped[int] = mapped_column(ForeignKey("main.signal_device.id"))
role_id: Mapped[int] = mapped_column(SmallInteger, ForeignKey("main.role.id"))
class SignalDevice(TableBase):
"""A Signal device tracked by phone number and safety number."""
@@ -24,3 +45,5 @@ class SignalDevice(TableBase):
default=TrustLevel.UNVERIFIED,
)
last_seen: Mapped[datetime] = mapped_column(DateTime(timezone=True))
roles: Mapped[list[RoleRecord]] = relationship(secondary=DeviceRole.__table__)