steam-backlog-enforcer/steam_backlog_enforcer/_config_setup.py
2026-10-10 16:07:42 +02:00

52 lines
1.9 KiB
Python

"""First-run interactive configuration.
Split out of ``config.py``: prompting a human for credentials is a different
concern from the data model those credentials live in, and only the ``setup``
command ever reaches it. The existing ``test_config_interactive_setup.py``
already treated it as its own unit.
"""
from __future__ import annotations
from dataclasses import replace
import json
import sys
from steam_backlog_enforcer import config as config_mod
from steam_backlog_enforcer._prompter import current_prompter
from steam_backlog_enforcer.config import Config
def interactive_setup() -> Config:
"""Run first-time interactive setup."""
prompter = current_prompter()
api_key = prompter.text("Enter your Steam Web API key")
if not api_key:
sys.exit(1)
steam_id = prompter.text("Enter your Steam64 ID")
if not steam_id:
sys.exit(1)
return save_credentials(api_key, steam_id)
def save_credentials(api_key: str, steam_id: str) -> Config:
"""Store *api_key* and *steam_id* in the config, owner-only.
The non-interactive half of setup, so the web setup screen stores the
credentials exactly the way the CLI does. Every other setting already in
the config is kept: re-entering a key must not reset the user's choices,
including keys this version does not model (hand-added or legacy ones).
"""
config = replace(Config.load(), steam_api_key=api_key, steam_id=steam_id)
# Read through the module, not an import-time binding: the path is
# redirected in tests, and the API key lives here — it must not become
# world-readable, nor be written to the real config during a test run.
path = config_mod.CONFIG_FILE
on_disk = json.loads(path.read_text(encoding="utf-8")) if path.exists() else {}
merged = on_disk | config.__dict__
config_mod.atomic_write(path, json.dumps(merged, indent=2) + "\n")
path.chmod(0o600)
return config