Harden redemption flow and improve operational safety
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
@@ -22,6 +23,24 @@ def _env_int(name: str, default: int) -> int:
|
||||
return default
|
||||
|
||||
|
||||
def _normalize_database_url(database_url: str, warnings: list[str]) -> str:
|
||||
normalized = database_url.strip()
|
||||
if not normalized:
|
||||
return "sqlite:///redemption.db"
|
||||
|
||||
container_prefix = "sqlite:////app/"
|
||||
if normalized.startswith(container_prefix) and not Path("/.dockerenv").exists():
|
||||
local_relative = normalized.removeprefix(container_prefix)
|
||||
project_root = Path(__file__).resolve().parent.parent
|
||||
local_path = (project_root / local_relative).resolve()
|
||||
warnings.append(
|
||||
f"DATABASE_URL 使用容器路径时,已自动映射到本地路径 {local_path}。"
|
||||
)
|
||||
return f"sqlite:///{local_path}"
|
||||
|
||||
return normalized
|
||||
|
||||
|
||||
@dataclass
|
||||
class Settings:
|
||||
app_name: str
|
||||
@@ -39,6 +58,7 @@ class Settings:
|
||||
default_domain: str
|
||||
default_usage_location: str
|
||||
default_license_sku: str
|
||||
license_assignment_required: bool
|
||||
force_change_password: bool
|
||||
graph_base_url: str
|
||||
token_endpoint: str
|
||||
@@ -68,6 +88,7 @@ class Settings:
|
||||
"defaultDomain": self.default_domain,
|
||||
"defaultUsageLocation": self.default_usage_location,
|
||||
"defaultLicenseSku": self.default_license_sku,
|
||||
"licenseAssignmentRequired": self.license_assignment_required,
|
||||
"forceChangePassword": self.force_change_password,
|
||||
"pageSize": self.default_page_size,
|
||||
"maxPageSize": self.max_page_size,
|
||||
@@ -84,6 +105,7 @@ def load_settings() -> Settings:
|
||||
|
||||
validation_errors: list[str] = []
|
||||
warnings: list[str] = []
|
||||
database_url = _normalize_database_url(os.getenv("DATABASE_URL", "sqlite:///redemption.db"), warnings)
|
||||
|
||||
required_fields = {
|
||||
"CLIENT_ID": os.getenv("CLIENT_ID", "").strip(),
|
||||
@@ -121,13 +143,14 @@ def load_settings() -> Settings:
|
||||
default_domain=os.getenv("DEFAULT_DOMAIN", "").strip(),
|
||||
default_usage_location=os.getenv("DEFAULT_USAGE_LOCATION", "US").strip() or "US",
|
||||
default_license_sku=os.getenv("DEFAULT_LICENSE_SKU", "").strip(),
|
||||
license_assignment_required=_env_bool("LICENSE_ASSIGNMENT_REQUIRED", False),
|
||||
force_change_password=_env_bool("FORCE_CHANGE_PASSWORD", True),
|
||||
graph_base_url=graph_base_url,
|
||||
token_endpoint=token_endpoint,
|
||||
scope=scope,
|
||||
database_url=os.getenv("DATABASE_URL", "sqlite:///redemption.db").strip(),
|
||||
database_url=database_url,
|
||||
default_page_size=min(max(_env_int("DEFAULT_PAGE_SIZE", 25), 1), 100),
|
||||
max_page_size=min(max(_env_int("MAX_PAGE_SIZE", 100), 10), 500),
|
||||
validation_errors=tuple(validation_errors),
|
||||
warnings=tuple(warnings),
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user