mirror of
https://github.com/RichieCahill/dotfiles.git
synced 2026-04-17 04:58:19 -04:00
99 lines
2.2 KiB
Python
99 lines
2.2 KiB
Python
"""Models for the Signal command and control bot."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime # noqa: TC003 - pydantic needs this at runtime
|
|
from enum import StrEnum
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, ConfigDict
|
|
from sqlalchemy.engine import Engine # noqa: TC002 - pydantic needs this at runtime
|
|
|
|
|
|
class TrustLevel(StrEnum):
|
|
"""Device trust level."""
|
|
|
|
VERIFIED = "verified"
|
|
UNVERIFIED = "unverified"
|
|
BLOCKED = "blocked"
|
|
|
|
|
|
class Role(StrEnum):
|
|
"""RBAC roles — one per command, plus admin which grants all."""
|
|
|
|
ADMIN = "admin"
|
|
STATUS = "status"
|
|
INVENTORY = "inventory"
|
|
LOCATION = "location"
|
|
|
|
|
|
class MessageStatus(StrEnum):
|
|
"""Dead letter queue message status."""
|
|
|
|
UNPROCESSED = "unprocessed"
|
|
PROCESSED = "processed"
|
|
|
|
|
|
class Device(BaseModel):
|
|
"""A registered device tracked by safety number."""
|
|
|
|
phone_number: str
|
|
safety_number: str
|
|
trust_level: TrustLevel = TrustLevel.UNVERIFIED
|
|
first_seen: datetime
|
|
last_seen: datetime
|
|
|
|
|
|
class SignalMessage(BaseModel):
|
|
"""An incoming Signal message."""
|
|
|
|
source: str
|
|
timestamp: int
|
|
message: str = ""
|
|
attachments: list[str] = []
|
|
group_id: str | None = None
|
|
is_receipt: bool = False
|
|
|
|
|
|
class SignalEnvelope(BaseModel):
|
|
"""Raw envelope from signal-cli-rest-api."""
|
|
|
|
envelope: dict[str, Any]
|
|
account: str | None = None
|
|
|
|
|
|
class InventoryItem(BaseModel):
|
|
"""An item in the van inventory."""
|
|
|
|
name: str
|
|
quantity: float = 1
|
|
unit: str = "each"
|
|
category: str = ""
|
|
notes: str = ""
|
|
|
|
|
|
class InventoryUpdate(BaseModel):
|
|
"""Result of processing an inventory update."""
|
|
|
|
items: list[InventoryItem] = []
|
|
raw_response: str = ""
|
|
source_type: str = "" # "receipt_photo" or "text_list"
|
|
|
|
|
|
class BotConfig(BaseModel):
|
|
"""Top-level bot configuration."""
|
|
|
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
|
|
signal_api_url: str
|
|
phone_number: str
|
|
inventory_api_url: str
|
|
ha_url: str | None = None
|
|
ha_token: str | None = None
|
|
ha_location_entity: str = "sensor.gps_location"
|
|
engine: Engine
|
|
reconnect_delay: int = 5
|
|
max_reconnect_delay: int = 300
|
|
max_retries: int = 10
|
|
max_message_attempts: int = 3
|