dooris/api/src/dooris_api/models.py
lilly 63a9485209
All checks were successful
Build Container / Build Container (push) Successful in 1m26s
api: restructure user authentication modelling to support other user backends
2026-05-28 17:29:57 +02:00

69 lines
1.9 KiB
Python

from typing import Optional, Literal, Self
from datetime import datetime, UTC
from pydantic import BaseModel, HttpUrl, Field
from enum import Enum
from simple_openid_connect.data import IdToken
class HttpProblemType(Enum):
"""
Statically known HTTP problem types using the [type URI scheme](https://datatracker.ietf.org/doc/rfc4151/)
"""
UNAUTHORIZED = "type:noc@hamburg.ccc.de,2026:UNAUTHORIZED"
FORBIDDEN_TO_OPERATE = "type:noc@hamburg.ccc.de,2026,FORBIDDEN_TO_OPERATE"
LOCK_NOT_FOUND = "type:noc@hamburg.ccc.de,2026:LOCK_NOT_FOUND"
class HttpProblemDetail(BaseModel):
"""
API Error modeled after [RFC9475](https://www.rfc-editor.org/rfc/rfc9457.html).
"""
status: int
type: HttpProblemType
title: str
detail: str
instance: Optional[HttpUrl]
class ApiUser(BaseModel):
is_anonymous: bool
is_ccchh_user: bool
is_token_user: bool
may_operate_locks: bool
username: str
guaranteed_session_until: Optional[datetime]
raw_id_token: Optional[str] = Field(exclude=True)
@classmethod
def from_id_token(cls, id_token: IdToken, raw_id_token: str) -> Self:
return cls(
is_anonymous=False,
is_ccchh_user=True,
is_token_user=False,
may_operate_locks="intern@" in getattr(id_token, "ccchh-roles", []),
username=id_token.preferred_username,
guaranteed_session_until=datetime.fromtimestamp(id_token.exp, UTC),
raw_id_token=raw_id_token,
)
class LockStatus(BaseModel):
is_unreachable: bool
is_low_battery: bool
is_error_jammed: bool
lock_target_level: Literal["locked", "unlocked", "open"]
lock_state: Literal["unknown", "locked", "unlocked"]
activity_state: Literal["unknown", "locking", "unlocking", "stable"]
class Lock(BaseModel):
name: str
id: str
status: LockStatus
class LockOperation(BaseModel):
desired_state: Literal["open", "closed"]