eight-hourr/backend/services/settings_store.py

98 lines
2.6 KiB
Python
Raw Normal View History

2026-07-17 06:55:36 +00:00
from __future__ import annotations
import json
from datetime import datetime, timezone
from typing import Any
from paths import DATA_DIR
SETTINGS_FILE = DATA_DIR / "settings.json"
SETTINGS_FILE.parent.mkdir(parents=True, exist_ok=True)
SECRET_FIELDS = {
"gitlab_token",
"xai_api_key",
"pts_password",
"teams_password",
"compbase_password",
}
PASSWORD_FIELDS = {"pts_password", "teams_password", "compbase_password"}
MASK_PLACEHOLDER = "********"
def _now_iso() -> str:
return datetime.now(timezone.utc).isoformat()
def load_overrides() -> dict[str, Any]:
if not SETTINGS_FILE.exists():
return {}
try:
payload = json.loads(SETTINGS_FILE.read_text(encoding="utf-8"))
return payload.get("values", payload) if isinstance(payload, dict) else {}
except (json.JSONDecodeError, OSError):
return {}
def save_overrides(values: dict[str, Any]) -> None:
SETTINGS_FILE.write_text(
json.dumps(
{"updated_at": _now_iso(), "values": values},
ensure_ascii=False,
indent=2,
),
encoding="utf-8",
)
def mask_secret(value: str) -> str:
if not value:
return ""
if len(value) <= 10:
return MASK_PLACEHOLDER
return f"{value[:6]}...{value[-4:]}"
def is_masked_or_empty(value: Any) -> bool:
if value is None:
return True
text = str(value).strip()
if not text:
return True
if text == MASK_PLACEHOLDER:
return True
if "..." in text and len(text) < 30:
return True
return False
def merge_secret_updates(
current: dict[str, Any],
updates: dict[str, Any],
existing_secrets: dict[str, str],
) -> dict[str, Any]:
merged = {**current, **updates}
for field in SECRET_FIELDS:
if field in updates and is_masked_or_empty(updates[field]):
if existing_secrets.get(field):
merged[field] = existing_secrets[field]
else:
merged.pop(field, None)
return merged
def public_view(settings: dict[str, Any]) -> dict[str, Any]:
public = dict(settings)
for field in SECRET_FIELDS:
raw = public.get(field, "")
public[f"{field}_set"] = bool(raw)
public[field] = mask_secret(raw) if raw else ""
public["gitlab_board_label_list"] = [
part.strip()
for part in str(public.get("gitlab_board_labels", "")).split(",")
if part.strip()
]
public["auto_fill_time"] = (
f"{int(public.get('auto_fill_hour', 18)):02d}:"
f"{int(public.get('auto_fill_minute', 0)):02d}"
)
return public