from __future__ import annotations import json import os import secrets from pathlib import Path def _default_data_dir() -> Path: return Path(os.getenv("SALDO_DATA_DIR", Path.cwd() / "instance")).resolve() class Config: APP_NAME = "Saldo" SECRET_KEY = os.getenv("SECRET_KEY") or secrets.token_hex(32) DATA_DIR = _default_data_dir() AVATAR_UPLOAD_DIR = DATA_DIR / "avatars" SQLALCHEMY_DATABASE_URI = os.getenv( "DATABASE_URL", f"sqlite:///{(DATA_DIR / 'saldo.db').as_posix()}", ) SQLALCHEMY_TRACK_MODIFICATIONS = False REMEMBER_COOKIE_DURATION = 60 * 60 * 24 * 30 MAX_CONTENT_LENGTH = int(os.getenv("SALDO_MAX_CONTENT_LENGTH", str(5 * 1024 * 1024))) SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = "Lax" REMEMBER_COOKIE_HTTPONLY = True REMEMBER_COOKIE_SAMESITE = "Lax" SESSION_COOKIE_SECURE = os.getenv("SALDO_SESSION_COOKIE_SECURE", "0") != "0" REMEMBER_COOKIE_SECURE = SESSION_COOKIE_SECURE CSRF_ENABLED = os.getenv("SALDO_CSRF_ENABLED", "1") != "0" VAPID_PUBLIC_KEY = os.getenv("VAPID_PUBLIC_KEY", "") VAPID_PRIVATE_KEY = os.getenv("VAPID_PRIVATE_KEY", "") VAPID_CLAIMS = { "sub": os.getenv("VAPID_SUBJECT", "mailto:admin@example.invalid"), } ADMIN_BOOTSTRAP_USERNAME = os.getenv("SALDO_ADMIN_USERNAME", "admin") ADMIN_BOOTSTRAP_PASSWORD = os.getenv("SALDO_ADMIN_PASSWORD", "") ADMIN_BOOTSTRAP_EMAIL = os.getenv("SALDO_ADMIN_EMAIL", "admin@example.invalid") ALLOCATION_TARGET_RULES = json.loads( os.getenv( "SALDO_ALLOCATION_TARGET_RULES", json.dumps( { "sparen": { "recommended_pct": 0.18, "min_pct": 0.15, "max_pct": 0.20, "label": "Sparen", }, "urlaub": { "recommended_pct": 0.06, "min_pct": 0.05, "max_pct": 0.08, "label": "Urlaub", }, "freizeit": { "recommended_pct": 0.07, "min_pct": 0.05, "max_pct": 0.10, "label": "Freizeit", }, } ), ) ) DEFAULT_PERSONAL_SPLIT_DESI_PCT = float( os.getenv("SALDO_DEFAULT_PERSONAL_SPLIT_DESI_PCT", "50") ) STRONG_INCOME_CHANGE_THRESHOLD = float( os.getenv("SALDO_STRONG_INCOME_CHANGE_THRESHOLD", "150") )