Files
stork/scripts/seed_names.py
T
ilia 480e5b6ce6
CI / secret-scan (pull_request) Successful in 33s
CI / python-ci (pull_request) Successful in 1m8s
Harden Stork for public demo and family durability
Read-only demo boards, per-IP rate limits, opaque voter sessions,
session leave, upload sniffing, path containment, and retire /v1.
2026-08-07 20:55:21 -04:00

79 lines
2.7 KiB
Python

"""Seed or refresh starter names (add missing, patch locales on existing).
Usage:
STORK_URL=https://stork.levkin.ca STORK_BOARD_ID=b_xxx \\
.venv/bin/python scripts/seed_names.py
# or resolve legacy invite:
STORK_URL=... STORK_INVITE=... .venv/bin/python scripts/seed_names.py
"""
from __future__ import annotations
import json
import os
import sys
from pathlib import Path
import httpx
ROOT = Path(__file__).resolve().parents[1]
DEFAULT_SEED = ROOT / "data" / "seed-names.example.json"
def main() -> int:
base = os.environ.get("STORK_URL", "http://127.0.0.1:8094").rstrip("/")
board_id = os.environ.get("STORK_BOARD_ID", "").strip()
invite = os.environ.get("STORK_INVITE", "").strip()
display = os.environ.get("STORK_DISPLAY_NAME", "Ilia").strip() or "Ilia"
seed_path = Path(os.environ.get("STORK_SEED_FILE", str(DEFAULT_SEED))).expanduser()
if not board_id and not invite:
print("Set STORK_BOARD_ID or STORK_INVITE", file=sys.stderr)
return 1
if not seed_path.is_file():
print(f"Seed file not found: {seed_path}", file=sys.stderr)
return 1
names = json.loads(seed_path.read_text())["names"]
with httpx.Client(base_url=base, timeout=30.0) as client:
if not board_id:
resolved = client.get("/api/resolve", params={"invite": invite})
resolved.raise_for_status()
board_id = resolved.json()["id"]
session = client.post(
"/api/session",
json={"board_id": board_id, "display_name": display},
)
session.raise_for_status()
existing: dict[tuple[str, str], int] = {}
for kind in {n.get("kind", "c1") for n in names} | {"c1"}:
listed = client.get("/api/names", params={"kind": kind})
if listed.status_code != 200:
continue
for row in listed.json().get("items") or []:
existing[(row["kind"], row["spelling"].casefold())] = row["id"]
for item in names:
kind = item["kind"]
spelling = item["spelling"]
key = (kind, spelling.casefold())
locales = item.get("locales") or {}
if key in existing:
name_id = existing[key]
res = client.patch(
f"/api/names/{name_id}",
json={"locales": locales},
)
res.raise_for_status()
print(f"updated locales {kind}: {spelling}")
continue
res = client.post("/api/names", json=item)
res.raise_for_status()
print(f"added {kind}: {spelling}")
print(f"board: {base}/b/{board_id}")
return 0
if __name__ == "__main__":
raise SystemExit(main())