0262ed3d97
- Sidebar bottom-left now shows the signed-in user; clicking opens a menu with Settings and Sign out. New /settings page: account info + change password (POST /auth/change-password, re-verifies current password). Export/restore/ delete are stubbed there for the next pass. - Per-tree default/home person: tree.home_person_id (migration) + TreeUpdate/ Read; the tree and family views open focused on it; the person page gets a "Set as default" control and "Default person" badge. Cleared if that person is deleted. Complements the account-level "this is me" link. - Tree visualization now fills the content area (AppShell drops the max-width column on the /tree route); other pages stay centered. - Audit records are coerced JSON-safe (UUIDs/enums), so PATCHing UUID fields like home_person_id audits cleanly. 50 backend tests pass; migration up/down verified; frontend builds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
54 lines
1.8 KiB
Python
54 lines
1.8 KiB
Python
"""Change password and per-tree home person."""
|
|
|
|
from tests.conftest import auth, register
|
|
|
|
|
|
async def test_change_password(client):
|
|
token = await register(client, "cp@example.com", password="password123")
|
|
h = auth(token)
|
|
|
|
# Wrong current password is rejected.
|
|
bad = await client.post(
|
|
"/api/v1/auth/change-password",
|
|
json={"current_password": "nope", "new_password": "newpass123"},
|
|
headers=h,
|
|
)
|
|
assert bad.status_code == 403
|
|
|
|
ok = await client.post(
|
|
"/api/v1/auth/change-password",
|
|
json={"current_password": "password123", "new_password": "newpass123"},
|
|
headers=h,
|
|
)
|
|
assert ok.status_code == 204
|
|
|
|
# The new password logs in; the old one does not.
|
|
assert (
|
|
await client.post(
|
|
"/api/v1/auth/login", json={"email": "cp@example.com", "password": "newpass123"}
|
|
)
|
|
).status_code == 200
|
|
assert (
|
|
await client.post(
|
|
"/api/v1/auth/login", json={"email": "cp@example.com", "password": "password123"}
|
|
)
|
|
).status_code == 401
|
|
|
|
|
|
async def test_tree_home_person(client):
|
|
h = auth(await register(client, "home@example.com"))
|
|
tid = (await client.post("/api/v1/trees", json={"name": "T"}, headers=h)).json()["id"]
|
|
pid = (
|
|
await client.post(f"/api/v1/trees/{tid}/persons", json={"given": "Root"}, headers=h)
|
|
).json()["id"]
|
|
|
|
r = await client.patch(
|
|
f"/api/v1/trees/{tid}", json={"home_person_id": pid}, headers=h
|
|
)
|
|
assert r.status_code == 200 and r.json()["home_person_id"] == pid
|
|
|
|
# Deleting the home person clears the link.
|
|
await client.delete(f"/api/v1/trees/{tid}/persons/{pid}", headers=h)
|
|
tree = (await client.get(f"/api/v1/trees/{tid}", headers=h)).json()
|
|
assert tree["home_person_id"] is None
|