FluxIP/app/accounts/schemas.py

125 lines
4.6 KiB
Python

from __future__ import annotations
from typing import Literal
from pydantic import BaseModel, Field, field_validator, model_validator
AccountProvider = Literal["aws", "cloudflare"]
class AccountCreate(BaseModel):
provider: AccountProvider
name: str = Field(min_length=1, max_length=80)
use_default_aws_credentials: bool = False
aws_access_key_id: str | None = Field(default=None, max_length=128)
aws_secret_access_key: str | None = Field(default=None, max_length=256)
aws_session_token: str | None = Field(default=None, max_length=4096)
cloudflare_api_token: str | None = Field(default=None, max_length=2048)
@field_validator("name")
@classmethod
def normalize_name(cls, value: str) -> str:
normalized = value.strip()
if not normalized:
raise ValueError("账号名称不能为空")
return normalized
@field_validator(
"aws_access_key_id",
"aws_secret_access_key",
"aws_session_token",
"cloudflare_api_token",
mode="before",
)
@classmethod
def normalize_secret(cls, value: object) -> object:
if value is None:
return None
normalized = str(value).strip()
return normalized or None
@model_validator(mode="after")
def validate_provider_credentials(self) -> AccountCreate:
if self.provider == "aws":
if self.cloudflare_api_token:
raise ValueError("AWS 账号不能包含 Cloudflare API Token")
if self.use_default_aws_credentials:
if self.aws_access_key_id or self.aws_secret_access_key or self.aws_session_token:
raise ValueError("使用 AWS 默认凭据链时不能同时填写 API 密钥")
elif not (self.aws_access_key_id and self.aws_secret_access_key):
raise ValueError("AWS Access Key ID 和 Secret Access Key 必须同时填写")
else:
if self.use_default_aws_credentials or any(
(self.aws_access_key_id, self.aws_secret_access_key, self.aws_session_token)
):
raise ValueError("Cloudflare 账号不能包含 AWS 凭据")
if not self.cloudflare_api_token:
raise ValueError("Cloudflare API Token 不能为空")
return self
class AccountUpdate(BaseModel):
config_version: int = Field(ge=1)
name: str | None = Field(default=None, min_length=1, max_length=80)
use_default_aws_credentials: bool | None = None
aws_access_key_id: str | None = Field(default=None, max_length=128)
aws_secret_access_key: str | None = Field(default=None, max_length=256)
aws_session_token: str | None = Field(default=None, max_length=4096)
cloudflare_api_token: str | None = Field(default=None, max_length=2048)
@field_validator("name")
@classmethod
def normalize_name(cls, value: str | None) -> str | None:
if value is None:
return None
normalized = value.strip()
if not normalized:
raise ValueError("账号名称不能为空")
return normalized
@field_validator(
"aws_access_key_id",
"aws_secret_access_key",
"aws_session_token",
"cloudflare_api_token",
mode="before",
)
@classmethod
def normalize_secret(cls, value: object) -> object:
if value is None:
return None
normalized = str(value).strip()
return normalized or None
@model_validator(mode="after")
def validate_update(self) -> AccountUpdate:
fields = self.model_fields_set
access_fields = {"aws_access_key_id", "aws_secret_access_key"}
supplied_access_fields = fields & access_fields
if supplied_access_fields and supplied_access_fields != access_fields:
raise ValueError("AWS Access Key ID 和 Secret Access Key 必须同时填写")
if bool(self.aws_access_key_id) != bool(self.aws_secret_access_key):
raise ValueError("AWS Access Key ID 和 Secret Access Key 必须同时填写")
if not fields - {"config_version"}:
raise ValueError("请至少修改一项账号配置")
return self
class AccountSecretFlags(BaseModel):
aws_access_key_id: bool = False
aws_secret_access_key: bool = False
aws_session_token: bool = False
cloudflare_api_token: bool = False
class AccountView(BaseModel):
id: str
provider: AccountProvider
name: str
use_default_aws_credentials: bool | None
config_version: int
secrets_configured: AccountSecretFlags
created_at: str
updated_at: str
archived_at: str | None