4788ae7723
Fuzzy search: pg_trgm extension + trigram GIN indexes on name parts and a GET /trees/{id}/persons?q= search ranked by trigram similarity (finds Mueller for 'muller'), privacy-filtered. Living-person protection: the privacy engine now derives possibly-living status (explicit flag, else no death fact + birth within ~100y or unknown) and returns 'redacted' for non-members of public/unlisted trees; the service minimises those records ('Living person', no vitals). Members are unaffected. 31 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>
37 lines
1.5 KiB
Python
37 lines
1.5 KiB
Python
"""Living-person protection: living people are redacted from non-members."""
|
|
|
|
from tests.conftest import auth, register
|
|
|
|
|
|
async def test_living_person_redacted_for_non_members(client):
|
|
owner = auth(await register(client, "pub-owner@example.com"))
|
|
tid = (
|
|
await client.post(
|
|
"/api/v1/trees", json={"name": "Public", "visibility": "public"}, headers=owner
|
|
)
|
|
).json()["id"]
|
|
await client.post(
|
|
f"/api/v1/trees/{tid}/persons",
|
|
json={"given": "Old", "surname": "Ancestor", "is_living": False},
|
|
headers=owner,
|
|
)
|
|
await client.post(
|
|
f"/api/v1/trees/{tid}/persons",
|
|
json={"given": "Young", "surname": "Living", "is_living": True},
|
|
headers=owner,
|
|
)
|
|
|
|
other = auth(await register(client, "pub-viewer@example.com"))
|
|
people = (await client.get(f"/api/v1/trees/{tid}/persons", headers=other)).json()
|
|
names = {p["primary_name"] for p in people}
|
|
assert "Old Ancestor" in names # deceased is visible
|
|
assert "Living person" in names # living is redacted
|
|
assert "Young Living" not in names # the real living name is hidden
|
|
# The redacted person leaks no gender.
|
|
living = next(p for p in people if p["primary_name"] == "Living person")
|
|
assert living["gender"] is None
|
|
|
|
# The owner (a member) sees real names.
|
|
owner_people = (await client.get(f"/api/v1/trees/{tid}/persons", headers=owner)).json()
|
|
assert "Young Living" in {p["primary_name"] for p in owner_people}
|