Files
finance/backend/app/config.py
T
k1nq d582f15681 feat: add tests for import polling, login page, money utilities, and query keys
- Implemented tests for import polling functionality, ensuring correct behavior for active and terminal import statuses.
- Created tests for the login page, validating user interactions and error handling.
- Added unit tests for money utility functions, covering parsing, formatting, and summation of monetary values.
- Developed tests for query keys, ensuring proper scoping and invalidation roots.

chore: setup testing environment and configuration

- Added setup file for testing with Vitest and Testing Library.
- Configured TypeScript and Vite for the frontend project.
- Created Docker and Nginx configurations for local development and production environments.
- Established a PostgreSQL initialization script for setting up application roles.

docs: add README and environment configuration for infra

- Included README for the infra directory, detailing local development setup and service descriptions.
- Created an example environment configuration file for local development with placeholders for sensitive information.
2026-09-14 09:26:33 +05:00

69 lines
2.0 KiB
Python

import base64
import binascii
from functools import lru_cache
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(extra="ignore")
environment: str = "development"
database_url: str = "postgresql+psycopg://fin:fin@localhost:5432/fin"
redis_url: str = "redis://localhost:6379/0"
admin_bootstrap_token: str = ""
imports_kek_b64: str = ""
blob_dir: str = "./var/blobs"
s3_endpoint_url: str = ""
s3_region: str = "us-east-1"
s3_access_key_id: str = ""
s3_secret_access_key: str = ""
s3_bucket_statements: str = "finance-statements"
smtp_host: str = ""
smtp_port: int = 1025
smtp_use_tls: bool = False
smtp_from: str = "no-reply@finance.local"
public_base_url: str = "http://localhost:8080"
session_cookie_name: str = "fin_session"
csrf_cookie_name: str = "csrf_token"
cookie_secure: bool = True
session_ttl_days: int = 14
invite_ttl_days: int = 7
reset_ttl_hours: int = 4
max_upload_bytes: int = 20 * 1024 * 1024
max_xlsx_rows: int = 10_000
max_pdf_pages: int = 200
max_archive_uncompressed_bytes: int = 64 * 1024 * 1024
deletion_window_days: int = 30
celery_task_always_eager: bool = False
celery_broker_url: str = ""
default_locale: str = "ru"
default_timezone: str = "Europe/Moscow"
@property
def broker_url(self) -> str:
return self.celery_broker_url or self.redis_url
@property
def kek(self) -> bytes:
if not self.imports_kek_b64:
raise RuntimeError("IMPORTS_KEK_B64 must be configured (base64-encoded 32-byte KEK)")
try:
raw = base64.b64decode(self.imports_kek_b64, validate=True)
except (binascii.Error, ValueError) as exc:
raise RuntimeError("IMPORTS_KEK_B64 is not valid base64") from exc
if len(raw) != 32:
raise RuntimeError("IMPORTS_KEK_B64 must decode to exactly 32 bytes")
return raw
@lru_cache
def get_settings() -> Settings:
return Settings()