Files
2026-07-18 20:32:51 +08:00

84 lines
2.6 KiB
Python

from functools import lru_cache
from pathlib import Path
from typing import Literal
from pydantic import model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore",
)
app_name: str = "OpenCloud API"
environment: Literal["development", "test", "production"] = "development"
api_v1_prefix: str = "/api/v1"
debug: bool = False
database_url: str
database_pool_size: int = 10
database_max_overflow: int = 20
secret_key: str
jwt_algorithm: str = "HS256"
access_token_expire_minutes: int = 15
refresh_token_expire_days: int = 30
refresh_cookie_name: str = "opencloud_refresh"
cookie_secure: bool = False
cookie_samesite: Literal["lax", "strict", "none"] = "lax"
cookie_domain: str | None = None
frontend_url: str = "http://localhost:5173"
public_base_url: str = "http://localhost:8000"
cors_origins: str = "http://localhost:5173"
upload_dir: Path = Path("data/uploads")
max_upload_bytes: int = 20 * 1024 * 1024
max_image_pixels: int = 50_000_000
thumbnail_max_edge: int = 640
email_delivery_mode: Literal["console", "smtp"] = "console"
smtp_host: str | None = None
smtp_port: int = 587
smtp_username: str | None = None
smtp_password: str | None = None
smtp_starttls: bool = True
email_from: str = "OpenCloud <no-reply@opencloud.local>"
email_confirmation_expire_hours: int = 24
password_reset_expire_minutes: int = 30
admin_email: str | None = None
admin_password: str | None = None
admin_username: str = "管理员"
@property
def cors_origin_list(self) -> list[str]:
return [item.strip() for item in self.cors_origins.split(",") if item.strip()]
@property
def media_base_url(self) -> str:
return f"{self.public_base_url.rstrip('/')}/media"
@model_validator(mode="after")
def validate_production_settings(self) -> "Settings":
if self.environment == "production":
if self.secret_key.startswith("change-me") or len(self.secret_key) < 32:
raise ValueError("生产环境必须配置至少 32 个字符的 SECRET_KEY")
if not self.cookie_secure:
raise ValueError("生产环境必须启用 COOKIE_SECURE")
if self.email_delivery_mode == "smtp" and not self.smtp_host:
raise ValueError("SMTP 模式必须配置 SMTP_HOST")
return self
@lru_cache
def get_settings() -> Settings:
return Settings()
settings = get_settings()