This commit is contained in:
2026-04-09 19:28:41 +03:00
commit 9fa723bb4c
43 changed files with 2804 additions and 0 deletions

102
app/config.py Normal file
View File

@@ -0,0 +1,102 @@
# app/config.py (рабочая версия)
from typing import List, Optional
from pydantic_settings import BaseSettings
from pydantic import Field, field_validator
import json
class Settings(BaseSettings):
"""Настройки приложения"""
# App
APP_NAME: str = "FormBuilder"
APP_ENV: str = Field(default="development", pattern="^(development|staging|production)$")
DEBUG: bool = True
SECRET_KEY: str = "your-secret-key-change-in-production-min-32-chars"
# Database
DB_TYPE: str = "postgresql"
DB_HOST: str = "localhost"
DB_PORT: int = 5432
DB_USER: str = "postgres"
DB_PASSWORD: str = "postgres"
DB_NAME: str = "formbuilder"
# Database Pool
DB_POOL_SIZE: int = 20
DB_MAX_OVERFLOW: int = 40
DB_POOL_TIMEOUT: int = 30
DB_POOL_PRE_PING: bool = True
# Redis
REDIS_URL: Optional[str] = None
# CORS
BACKEND_CORS_ORIGINS: List[str] = ["http://localhost:3000", "http://localhost:8000"]
# Security
JWT_SECRET_KEY: Optional[str] = None
JWT_ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
# Email
SMTP_HOST: Optional[str] = None
SMTP_PORT: Optional[int] = None
SMTP_USER: Optional[str] = None
SMTP_PASSWORD: Optional[str] = None
SMTP_USE_TLS: bool = True
# File Upload
MAX_UPLOAD_SIZE_MB: int = 10
ALLOWED_UPLOAD_EXTENSIONS: List[str] = [".jpg", ".jpeg", ".png", ".pdf", ".doc", ".docx"]
UPLOAD_PATH: str = "uploads"
# Logging
LOG_LEVEL: str = "INFO"
@property
def DATABASE_URL(self) -> str:
"""Формирует URL для подключения к БД"""
return f"postgresql://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
@field_validator("BACKEND_CORS_ORIGINS", mode="before")
@classmethod
def parse_cors_origins(cls, v):
"""Парсинг CORS origins"""
if isinstance(v, str):
try:
return json.loads(v)
except:
return [origin.strip() for origin in v.split(",")]
return v
@field_validator("ALLOWED_UPLOAD_EXTENSIONS", mode="before")
@classmethod
def parse_extensions(cls, v):
"""Парсинг расширений файлов"""
if isinstance(v, str):
try:
return json.loads(v)
except:
return [ext.strip() for ext in v.split(",")]
return v
@field_validator("SECRET_KEY")
@classmethod
def validate_secret_key(cls, v, info):
"""Валидация секретного ключа в production"""
# Получаем APP_ENV из данных, которые уже были обработаны
app_env = info.data.get('APP_ENV', 'development')
if app_env == "production" and (not v or len(v) < 32):
raise ValueError("SECRET_KEY must be at least 32 characters in production")
return v
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
case_sensitive = True
extra = "ignore" # Игнорируем лишние переменные окружения
# Создаем глобальный экземпляр настроек
settings = Settings()