197 lines
4.8 KiB
Python
197 lines
4.8 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
def utcnow_iso() -> str:
|
|
return datetime.now(timezone.utc).isoformat()
|
|
|
|
|
|
class BackendRecord(BaseModel):
|
|
backend_id: str
|
|
name: str
|
|
base_url: str
|
|
frontend_base_url: str | None = None
|
|
status: str = "active"
|
|
created_at: str = Field(default_factory=utcnow_iso)
|
|
updated_at: str = Field(default_factory=utcnow_iso)
|
|
|
|
|
|
class BackendCredential(BaseModel):
|
|
backend_id: str
|
|
client_id: str
|
|
client_secret_hash: str
|
|
created_at: str = Field(default_factory=utcnow_iso)
|
|
rotated_at: str | None = None
|
|
|
|
|
|
class UserRecord(BaseModel):
|
|
username: str
|
|
email: str | None = None
|
|
default_backend_id: str | None = None
|
|
created_at: str = Field(default_factory=utcnow_iso)
|
|
updated_at: str = Field(default_factory=utcnow_iso)
|
|
|
|
|
|
class PermissionsModel(BaseModel):
|
|
permissions: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ChannelSettings(BaseModel):
|
|
configured: bool = True
|
|
config: dict[str, Any] = Field(default_factory=dict)
|
|
secrets: dict[str, Any] = Field(default_factory=dict)
|
|
updated_at: str = Field(default_factory=utcnow_iso)
|
|
|
|
def masked_dict(self) -> dict[str, Any]:
|
|
data = self.model_dump(mode="json")
|
|
secrets = data.pop("secrets", {})
|
|
data["secrets_masked"] = bool(secrets)
|
|
data["secret_keys"] = sorted(
|
|
str(key).strip()
|
|
for key in (secrets.keys() if isinstance(secrets, dict) else [])
|
|
if str(key).strip()
|
|
)
|
|
return data
|
|
|
|
|
|
class OutlookSettings(BaseModel):
|
|
configured: bool = True
|
|
email: str
|
|
username: str
|
|
domain: str | None = None
|
|
service_endpoint: str | None = None
|
|
server: str | None = None
|
|
autodiscover: bool = False
|
|
default_timezone: str = "Asia/Shanghai"
|
|
password: str
|
|
updated_at: str = Field(default_factory=utcnow_iso)
|
|
|
|
def masked_dict(self) -> dict[str, Any]:
|
|
data = self.model_dump()
|
|
data.pop("password", None)
|
|
data["password_masked"] = True
|
|
return data
|
|
|
|
|
|
class MinIOSettings(BaseModel):
|
|
configured: bool = True
|
|
endpoint: str
|
|
access_key: str
|
|
secret_key: str
|
|
bucket: str | None = None
|
|
namespace: str | None = None
|
|
secure: bool = False
|
|
region: str | None = None
|
|
updated_at: str = Field(default_factory=utcnow_iso)
|
|
|
|
def masked_dict(self) -> dict[str, Any]:
|
|
data = self.model_dump()
|
|
data.pop("secret_key", None)
|
|
data["secret_key_masked"] = True
|
|
return data
|
|
|
|
|
|
class BackendRoutingPayload(BaseModel):
|
|
name: str | None = None
|
|
backend_id: str | None = None
|
|
base_url: str | None = None
|
|
frontend_base_url: str | None = None
|
|
|
|
|
|
class RegisterBackendRequest(BaseModel):
|
|
name: str
|
|
base_url: str
|
|
backend_id: str | None = None
|
|
frontend_base_url: str | None = None
|
|
|
|
|
|
class UpdateBackendRequest(BaseModel):
|
|
name: str | None = None
|
|
base_url: str | None = None
|
|
frontend_base_url: str | None = None
|
|
|
|
|
|
class RegisterBackendResponse(BaseModel):
|
|
backend_id: str
|
|
client_id: str
|
|
client_secret: str
|
|
created_at: str
|
|
frontend_base_url: str | None = None
|
|
|
|
|
|
class RegisterUserRequest(BaseModel):
|
|
username: str
|
|
password: str
|
|
email: str | None = None
|
|
name: str | None = None
|
|
backend_name: str | None = None
|
|
backend_id: str | None = None
|
|
base_url: str | None = None
|
|
public_base_url: str | None = None
|
|
frontend_base_url: str | None = None
|
|
backend: BackendRoutingPayload | None = None
|
|
|
|
|
|
class RegisterUserBackendResult(BaseModel):
|
|
backend_id: str
|
|
client_id: str
|
|
client_secret: str | None = None
|
|
name: str
|
|
base_url: str
|
|
frontend_base_url: str | None = None
|
|
status: str = "active"
|
|
created_at: str
|
|
|
|
|
|
class RegisterUserResponse(BaseModel):
|
|
user: UserRecord
|
|
backend: RegisterUserBackendResult
|
|
|
|
|
|
class PortalRegisterRequest(BaseModel):
|
|
username: str
|
|
password: str
|
|
email: str | None = None
|
|
instance_id: str | None = None
|
|
backend_name: str | None = None
|
|
image_name: str | None = None
|
|
replace: bool = False
|
|
|
|
|
|
class RotateSecretResponse(BaseModel):
|
|
backend_id: str
|
|
client_id: str
|
|
client_secret: str
|
|
rotated_at: str
|
|
|
|
|
|
class OAuthTokenRequest(BaseModel):
|
|
grant_type: str = "client_credentials"
|
|
client_id: str
|
|
client_secret: str
|
|
aud: str
|
|
scopes: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class OAuthTokenResponse(BaseModel):
|
|
access_token: str
|
|
token_type: str = "bearer"
|
|
expires_in: int
|
|
|
|
|
|
class IntrospectRequest(BaseModel):
|
|
token: str
|
|
|
|
|
|
class IntrospectResponse(BaseModel):
|
|
active: bool
|
|
client_id: str | None = None
|
|
backend_id: str | None = None
|
|
aud: str | None = None
|
|
scp: list[str] = Field(default_factory=list)
|
|
exp: int | None = None
|