Files
service-finder/backend/app/core/config.py
2026-03-13 10:22:41 +00:00

145 lines
5.1 KiB
Python
Executable File

# /opt/docker/dev/service_finder/backend/app/core/config.py
import os
from pathlib import Path
from typing import Any, Optional, List
from pydantic_settings import BaseSettings, SettingsConfigDict
from pydantic import Field, field_validator
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession
from datetime import datetime, timezone
class Settings(BaseSettings):
# --- Paths ---
BASE_DIR: Path = Path(__file__).resolve().parent.parent.parent
STATIC_DIR: str = os.path.join(str(BASE_DIR), "static")
# --- General ---
PROJECT_NAME: str = "Service Finder Ecosystem"
VERSION: str = "2.1.0"
API_V1_STR: str = "/api/v1"
DEBUG: bool = False
def get_now_utc_iso(self) -> str:
"""Központi időlekérdező az egész Sentinel rendszernek"""
return datetime.now(timezone.utc).isoformat()
# MB 2.0 Kompatibilitási alias a database.py számára
@property
def DEBUG_MODE(self) -> bool:
return self.DEBUG
# --- Security / JWT ---
SECRET_KEY: str = "NOT_SET_DANGER"
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
REFRESH_TOKEN_EXPIRE_DAYS: int = 7
@field_validator('SECRET_KEY')
@classmethod
def validate_secret_key(cls, v: str, info) -> str:
"""Ellenőrzi, hogy a SECRET_KEY ne legyen default érték éles környezetben."""
if v == "NOT_SET_DANGER" and not info.data.get("DEBUG", True):
raise ValueError(
"SECRET_KEY must be set in production environment. "
"Please set SECRET_KEY in .env file."
)
if not v or v.strip() == "":
raise ValueError("SECRET_KEY cannot be empty.")
return v
# --- Initial Admin ---
INITIAL_ADMIN_EMAIL: str = "admin@servicefinder.hu"
INITIAL_ADMIN_PASSWORD: str = "Admin123!"
# --- Database & Cache ---
# Alapértelmezett értéket adunk, hogy ne szálljon el, ha a .env hiányos
DATABASE_URL: str = Field(
default="postgresql+asyncpg://user:password@postgres-db:5432/service_finder",
env="DATABASE_URL"
)
REDIS_URL: str = "redis://service_finder_redis:6379/0"
@property
def SQLALCHEMY_DATABASE_URI(self) -> str:
"""
Ez a property biztosítja, hogy a database.py és az Alembic
megtalálja a kapcsolatot a várt néven.
"""
return self.DATABASE_URL
# --- Email ---
EMAIL_PROVIDER: str = "auto"
EMAILS_FROM_EMAIL: str = "info@profibot.hu"
EMAILS_FROM_NAME: str = "Profibot"
SENDGRID_API_KEY: Optional[str] = None
SMTP_HOST: Optional[str] = None
SMTP_PORT: int = 587
SMTP_USER: Optional[str] = None
SMTP_PASSWORD: Optional[str] = None
# --- External URLs ---
FRONTEND_BASE_URL: str = "https://dev.profibot.hu"
BACKEND_CORS_ORIGINS: List[str] = Field(
default=[
"http://localhost:3001",
"https://dev.profibot.hu"
],
description="Comma-separated list of allowed CORS origins. Set via ALLOWED_ORIGINS environment variable."
)
@field_validator('BACKEND_CORS_ORIGINS', mode='before')
@classmethod
def parse_allowed_origins(cls, v: Any) -> List[str]:
"""Parse ALLOWED_ORIGINS environment variable from comma-separated string to list."""
import os
env_val = os.getenv('ALLOWED_ORIGINS')
if env_val:
# parse environment variable
env_val = env_val.strip()
if env_val.startswith('"') and env_val.endswith('"'):
env_val = env_val[1:-1]
if env_val.startswith("'") and env_val.endswith("'"):
env_val = env_val[1:-1]
parts = [part.strip() for part in env_val.split(',') if part.strip()]
return parts
# if no env variable, fallback to default or provided value
if isinstance(v, str):
v = v.strip()
if v.startswith('"') and v.endswith('"'):
v = v[1:-1]
if v.startswith("'") and v.endswith("'"):
v = v[1:-1]
parts = [part.strip() for part in v.split(',') if part.strip()]
return parts
return v
# --- Google OAuth ---
GOOGLE_CLIENT_ID: str = ""
GOOGLE_CLIENT_SECRET: str = ""
GOOGLE_CALLBACK_URL: str = "https://dev.profibot.hu/api/v1/auth/callback/google"
# --- Brute-Force & Security ---
LOGIN_RATE_LIMIT_ANON: str = "5/minute"
AUTH_MIN_PASSWORD_LENGTH: int = 8
# --- Dinamikus Admin Motor (Sértetlenül hagyva) ---
async def get_db_setting(self, db: AsyncSession, key_name: str, default: Any = None) -> Any:
try:
query = text("SELECT value FROM system.system_parameters WHERE key = :key")
result = await db.execute(query, {"key": key_name})
row = result.fetchone()
if row and row[0] is not None:
return row[0]
return default
except Exception:
return default
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=True,
extra="ignore"
)
settings = Settings()