family link: which accounts belong to a household, and GET /api/admin/family

household_people joins a roster family to the accounts of its parents; a
household can have two, a person can rarely be on two. PUT
/roster/households/{id}/people sets it (admin and above). GET /family
(account:self) returns the signed-in person's own households with scouts
and this year's checklist, and nothing else - the parent view of the
roster, read only. Inactive households drop off it.

tests/smoke_admin.py 141 -> 147.
This commit is contained in:
2026-09-04 19:19:34 -04:00
parent 504538567f
commit 7f04d57665
3 changed files with 89 additions and 0 deletions
+13
View File
@@ -365,6 +365,19 @@ for t, k in (("roster_checks", "scout_id IN (SELECT id FROM scouts WHERE househo
con.execute("DELETE FROM %s WHERE %s" % (t, k), (hid, h2))
con.execute("DELETE FROM join_leads WHERE id='lead-import-test'"); con.commit(); con.close()
print("\nfamily link")
hid = S.create_household({"parent_name": "Link Parent"}, created_by="me")
S.add_scout(hid, {"first_name": "Lin", "unit_id": pk["id"], "den": "Wolf"})
check("no link, no families", S.households_for_person("p-x", "2026-2027") == [])
check("link set", S.set_household_people(hid, ["p-x", "p-y", "p-x"]) == ["p-x", "p-y"] and set(S.household_people(hid)) == {"p-x", "p-y"})
fam = S.households_for_person("p-x", "2026-2027")
check("a linked person sees the household with scouts and checks", len(fam) == 1 and fam[0]["scouts"][0]["first_name"] == "Lin" and "checks" in fam[0]["scouts"][0])
check("unlinked person sees nothing", S.households_for_person("p-z", "2026-2027") == [])
S.update_household(hid, {"active": False})
check("an inactive household drops off the family view", S.households_for_person("p-x", "2026-2027") == [])
check("unknown household is None", S.set_household_people("nope", ["p-x"]) is None)
con = S.connect(); con.execute("DELETE FROM household_people WHERE household_id=?", (hid,)); con.execute("DELETE FROM scouts WHERE household_id=?", (hid,)); con.execute("DELETE FROM households WHERE id=?", (hid,)); con.commit(); con.close()
print("\napi docs registry")
import admin_api as A
reg = A.describe_routes()