Files
svg-backend/backend/app/core/config.py

104 lines
4.2 KiB
Python

from pydantic import Field, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
app_name: str = Field(..., validation_alias="APP_NAME")
app_env: str = Field(..., validation_alias="APP_ENV")
app_port: int = Field(..., validation_alias="BACKEND_PORT")
api_v1_prefix: str = Field(..., validation_alias="API_V1_PREFIX")
auth_header_name: str = Field(..., validation_alias="AUTH_HEADER_NAME")
api_keys_admin: str = Field(..., validation_alias="API_KEYS_ADMIN")
api_keys_operator: str = Field(..., validation_alias="API_KEYS_OPERATOR")
api_keys_viewer: str = Field(..., validation_alias="API_KEYS_VIEWER")
postgres_host: str = Field(..., validation_alias="POSTGRES_HOST")
postgres_port: int = Field(..., validation_alias="POSTGRES_PORT")
postgres_db: str = Field(..., validation_alias="POSTGRES_DB")
postgres_user: str = Field(..., validation_alias="POSTGRES_USER")
postgres_password: str = Field(..., validation_alias="POSTGRES_PASSWORD")
database_url_raw: str | None = Field(default=None, validation_alias="DATABASE_URL")
svg_max_file_size_bytes: int = Field(10 * 1024 * 1024, validation_alias="SVG_MAX_FILE_SIZE_BYTES")
svg_max_elements: int = Field(25000, validation_alias="SVG_MAX_ELEMENTS")
svg_allow_internal_use_references_only: bool = Field(True, validation_alias="SVG_ALLOW_INTERNAL_USE_REFERENCES_ONLY")
svg_forbid_foreign_object_v1: bool = Field(True, validation_alias="SVG_FORBID_FOREIGN_OBJECT_V1")
svg_forbid_style_v1: bool = Field(False, validation_alias="SVG_FORBID_STYLE_V1")
svg_forbid_image_v1: bool = Field(True, validation_alias="SVG_FORBID_IMAGE_V1")
svg_display_enabled: bool = True
svg_display_mode: str = "passthrough"
svg_display_hide_small_text: bool = False
svg_display_min_text_font_size: float = 8.0
svg_display_hide_technical_text: bool = False
svg_display_remove_hidden_elements: bool = True
svg_display_force_viewbox: bool = True
svg_display_technical_text_patterns: str = "debug,tech,helper,tmp,service"
storage_root_dir: str = Field(..., validation_alias="STORAGE_ROOT")
publish_preview_retention_per_variant: int = 2
publish_require_full_pricing_coverage: bool = False
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
@model_validator(mode="after")
def validate_database_config(self) -> "Settings":
assembled_database_url = (
f"postgresql+asyncpg://{self.postgres_user}:{self.postgres_password}"
f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}"
)
if self.database_url_raw and self.database_url_raw != assembled_database_url:
raise ValueError("DATABASE_URL must match POSTGRES_HOST/PORT/DB/USER/PASSWORD")
return self
@property
def admin_keys(self) -> set[str]:
return {item.strip() for item in self.api_keys_admin.split(",") if item.strip()}
@property
def operator_keys(self) -> set[str]:
return {item.strip() for item in self.api_keys_operator.split(",") if item.strip()}
@property
def viewer_keys(self) -> set[str]:
return {item.strip() for item in self.api_keys_viewer.split(",") if item.strip()}
@property
def database_url(self) -> str:
if self.database_url_raw:
return self.database_url_raw
return (
f"postgresql+asyncpg://{self.postgres_user}:{self.postgres_password}"
f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}"
)
@property
def storage_original_dir(self) -> str:
return f"{self.storage_root_dir}/original"
@property
def storage_sanitized_dir(self) -> str:
return f"{self.storage_root_dir}/sanitized"
@property
def storage_normalized_dir(self) -> str:
return f"{self.storage_root_dir}/normalized"
@property
def storage_display_dir(self) -> str:
return f"{self.storage_root_dir}/display"
@property
def storage_preview_dir(self) -> str:
return f"{self.storage_root_dir}/preview"
settings = Settings()