diff --git a/backend-spec.md b/backend-spec.md index e6f1de6..f785382 100644 --- a/backend-spec.md +++ b/backend-spec.md @@ -353,3 +353,4 @@ Implementation policy updates (2025-11-01): Outstanding cleanup: - Remove remaining `Person` fallbacks in domain repositories and delete the `persons/` package once tests are migrated. Ensure no code paths depend on `cookie_person`. - Consider adding versioning endpoints for recipes explicitly rather than overloading POST. + - Add a temporary test helper to seed `User`/`HouseholdMember` rows from legacy `Person` when needed (now available as `tests/user_fixtures.py`). Use this to migrate tests off `persons` before deleting the package. diff --git a/tests/user_fixtures.py b/tests/user_fixtures.py new file mode 100644 index 0000000..777dd1c --- /dev/null +++ b/tests/user_fixtures.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +import aiosqlite + + +async def seed_users_from_legacy_persons(conn: aiosqlite.Connection): + """Seed User and HouseholdMember from legacy test persons if present. + + This is a no-op if the Person table is empty or missing. + """ + # Ensure required tables exist + try: + await conn.execute("SELECT 1 FROM User LIMIT 1") + await conn.execute("SELECT 1 FROM Household LIMIT 1") + await conn.execute("SELECT 1 FROM HouseholdMember LIMIT 1") + except Exception: + return + + # If any users exist already, do nothing + async with conn.execute("SELECT COUNT(1) FROM User") as c: + row = await c.fetchone() + if row and int(row[0]) > 0: + return + + # Default household id (created by migration/bootstrap) + async with conn.execute("SELECT id FROM Household WHERE slug = 'default' LIMIT 1") as c: + row = await c.fetchone() + if not row: + return + hid = int(row[0]) + + # Copy over Person rows into User and create membership + try: + async with conn.execute("SELECT id, name FROM Person") as cur: + async for pid, name in cur: + email = f"{str(name).lower()}@example.com" + await conn.execute( + "INSERT OR IGNORE INTO User (id, email, display_name) VALUES (?, ?, ?)", + (int(pid), email, str(name)), + ) + await conn.execute( + "INSERT OR IGNORE INTO HouseholdMember (user_id, household_id, role) VALUES (?, ?, 'admin')", + (int(pid), hid), + ) + except Exception: + # Person table may not exist in some contexts; ignore + return diff --git a/users/repository.py b/users/repository.py index 2b1f9ce..908004f 100644 --- a/users/repository.py +++ b/users/repository.py @@ -91,6 +91,16 @@ async def insert_user(conn, email: str, display_name: str, profile_photo_url: st return user_id +async def insert_user_with_id( + conn, user_id: int, email: str, display_name: str, profile_photo_url: str | None = None +): + """Insert a user with an explicit id (primarily for tests/fixtures).""" + await conn.execute( + "INSERT OR REPLACE INTO User (id, email, display_name, profile_photo_url) VALUES (?, ?, ?, ?)", + (user_id, email, display_name, profile_photo_url), + ) + + async def set_local_credentials(conn, user_id: int, hashed_password: str): await conn.execute( "INSERT OR REPLACE INTO LocalCredentials (user_id, hashed_password) VALUES (?, ?)",