Admin: Word Search theme authoring + tidy word-pool chips
* New "Word Search themes" panel in the Games tab: enter a theme name + words, with live validation (4–8 letters, alpha, deduped) and a count vs the 28 needed to fill all three sizes. An "✨ Suggest a word" button asks the LLM for one fresh word that fits the theme. Save/edit/remove; authored themes join the daily fallback rotation alongside the curated ones (wordsearch_themes table). The system still handles word distribution across sizes + placement. * Daily Word pool's added-word chips now scroll within a bounded area so the console stays tidy as the list grows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -402,3 +402,24 @@ def test_client_error_telemetry(tmp_path, monkeypatch):
|
||||
assert len(rows) == 1 and rows[0]["reason"] == "boot-timeout" and rows[0]["path"] == "/play"
|
||||
assert rows[0]["user_agent"] # captured from the request header
|
||||
assert tc.get("/api/admin/stats").json()["client_errors"]["today"] == 1
|
||||
|
||||
|
||||
def test_wordsearch_theme_admin(tmp_path, monkeypatch):
|
||||
app, api = _make(tmp_path, monkeypatch, admin_email="boss@x.com")
|
||||
assert TestClient(app).get("/api/admin/wordsearch/themes").status_code == 401 # gated
|
||||
tc = _signin(app, api, "boss@x.com")
|
||||
w28 = ["table", "chair", "clock", "shelf", "couch", "pillow", "window", "carpet", "mirror", "candle",
|
||||
"kettle", "drawer", "closet", "curtain", "cushion", "basket", "bottle", "towel", "broom", "ladder",
|
||||
"stairs", "pantry", "blanket", "vase", "hallway", "doorway", "mantel", "hamper"]
|
||||
# too few valid words → 400
|
||||
assert tc.post("/api/admin/wordsearch/themes", json={"theme": "X", "words": ["cat", "dog"]}).status_code == 400
|
||||
# save ok (>= 28); listed with the right count
|
||||
res = tc.post("/api/admin/wordsearch/themes", json={"theme": "My House", "words": w28}).json()
|
||||
assert res["saved"] and any(t["theme"] == "My House" and t["count"] == 28 for t in res["themes"])
|
||||
tid = next(t["id"] for t in res["themes"] if t["theme"] == "My House")
|
||||
# edit/update keeps the same id
|
||||
upd = tc.post("/api/admin/wordsearch/themes", json={"theme": "House Stuff", "words": w28, "id": tid}).json()
|
||||
assert any(t["id"] == tid and t["theme"] == "House Stuff" for t in upd["themes"])
|
||||
# remove
|
||||
left = tc.delete(f"/api/admin/wordsearch/themes/{tid}").json()
|
||||
assert not any(t["id"] == tid for t in left)
|
||||
|
||||
Reference in New Issue
Block a user