Remove legacy cookie auth and Person-based recipe helper; spec updated
This commit is contained in:
parent
42715c9fa6
commit
93b9869735
4 changed files with 3 additions and 44 deletions
31
api/deps.py
31
api/deps.py
|
|
@ -3,11 +3,10 @@ from __future__ import annotations
|
||||||
from typing import AsyncGenerator, Optional
|
from typing import AsyncGenerator, Optional
|
||||||
|
|
||||||
import aiosqlite
|
import aiosqlite
|
||||||
from fastapi import Cookie, Depends, HTTPException, Request
|
from fastapi import Depends, HTTPException, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
import db
|
import db
|
||||||
import persons
|
|
||||||
from common import ProblemDetails
|
from common import ProblemDetails
|
||||||
from settings import settings
|
from settings import settings
|
||||||
from users.models import User
|
from users.models import User
|
||||||
|
|
@ -45,34 +44,6 @@ async def get_db() -> AsyncGenerator[aiosqlite.Connection, None]:
|
||||||
await sql_db.close()
|
await sql_db.close()
|
||||||
|
|
||||||
|
|
||||||
async def cookie_person(
|
|
||||||
user_id: int = Cookie(..., alias="user_id"),
|
|
||||||
conn: aiosqlite.Connection = Depends(get_db),
|
|
||||||
) -> persons.Person:
|
|
||||||
"""Return the authenticated user from the user_id cookie or raise 401.
|
|
||||||
|
|
||||||
When the cookie is missing, FastAPI will raise 422 (validation error).
|
|
||||||
"""
|
|
||||||
person = await persons.get_by_id(conn, user_id)
|
|
||||||
if not person:
|
|
||||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
||||||
return person
|
|
||||||
|
|
||||||
|
|
||||||
async def cookie_person_optional(
|
|
||||||
user_id: Optional[int] = Cookie(default=None, alias="user_id"),
|
|
||||||
conn: aiosqlite.Connection = Depends(get_db),
|
|
||||||
) -> Optional[persons.Person]:
|
|
||||||
"""Return the authenticated user if cookie present; otherwise None.
|
|
||||||
|
|
||||||
Use for endpoints that want to return 401 for missing auth themselves.
|
|
||||||
"""
|
|
||||||
if user_id is None:
|
|
||||||
return None
|
|
||||||
person = await persons.get_by_id(conn, user_id)
|
|
||||||
return person
|
|
||||||
|
|
||||||
|
|
||||||
def error_response(request: Optional[Request], status_code: int, message: str) -> JSONResponse:
|
def error_response(request: Optional[Request], status_code: int, message: str) -> JSONResponse:
|
||||||
body = ProblemDetails(
|
body = ProblemDetails(
|
||||||
title=message,
|
title=message,
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ Refactor the backend from a single-tenant architecture to a robust, multi-tenant
|
||||||
- `POST /api/v1/auth/logout`: clears refresh cookie. After logout, subsequent `POST /api/v1/auth/refresh` returns 401.
|
- `POST /api/v1/auth/logout`: clears refresh cookie. After logout, subsequent `POST /api/v1/auth/refresh` returns 401.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
- `get_current_user` (JWT) is used by protected endpoints (households, shopping purchase, etc.). Legacy `cookie_person` remains only for historical v1 module references and will be removed with full v2 completion.
|
- `get_current_user` (JWT) is used by protected endpoints (households, shopping purchase, etc.). Legacy cookie-based helpers have been removed from the app surface.
|
||||||
- RFC7807 error semantics and the existing OpenAPI augmentation are preserved. The special-case 401 mapping for POST shopping is obsolete under JWT.
|
- RFC7807 error semantics and the existing OpenAPI augmentation are preserved. The special-case 401 mapping for POST shopping is obsolete under JWT.
|
||||||
|
|
||||||
### 3.2. Household & Tenancy API (current)
|
### 3.2. Household & Tenancy API (current)
|
||||||
|
|
@ -296,7 +296,7 @@ Remaining work (prioritized cleanup to final state):
|
||||||
1. Remove the `persons/` package and all code references across domains (recipes, meals, shopping). Replace `Person` with `users`/HouseholdMember everywhere:
|
1. Remove the `persons/` package and all code references across domains (recipes, meals, shopping). Replace `Person` with `users`/HouseholdMember everywhere:
|
||||||
- Code hotspots today: `recipes/models.py` (imports Person), `recipes/repository.py` (FKs, hide_recipe signature), `meals/models.py` (participants as List[Person]), `api/shopping_models.py` and `shopping/models.py` (ShoppingList.purchased_by typed as Person), and `shopping/repository.py` (FKs to Person).
|
- Code hotspots today: `recipes/models.py` (imports Person), `recipes/repository.py` (FKs, hide_recipe signature), `meals/models.py` (participants as List[Person]), `api/shopping_models.py` and `shopping/models.py` (ShoppingList.purchased_by typed as Person), and `shopping/repository.py` (FKs to Person).
|
||||||
- Replace internal usages with `user_id`/`MemberRef` where outward, and update repository DDL to stop referencing `Person`.
|
- Replace internal usages with `user_id`/`MemberRef` where outward, and update repository DDL to stop referencing `Person`.
|
||||||
- Remove `api.deps.cookie_person` once no tests or code depend on it.
|
- Removed `api.deps.cookie_person` and `cookie_person_optional`; v1 tests referencing them remain skipped and will be deleted or ported.
|
||||||
- Ensure no API module performs direct SQL; all persistence must flow through repositories (enforced during cleanup).
|
- Ensure no API module performs direct SQL; all persistence must flow through repositories (enforced during cleanup).
|
||||||
2. Recipes outward schema: DONE for `createdById`/`createdBy` and `hiddenById`/`hiddenBy` (MemberRef on delete). If/when we expose hide actor on other flows, keep MemberRef.
|
2. Recipes outward schema: DONE for `createdById`/`createdBy` and `hiddenById`/`hiddenBy` (MemberRef on delete). If/when we expose hide actor on other flows, keep MemberRef.
|
||||||
3. Shopping outward DTOs: DONE — `ShoppingListOut.purchasedBy` is a MemberRef; mapping added. Ensure clients shift to `displayName`.
|
3. Shopping outward DTOs: DONE — `ShoppingListOut.purchasedBy` is a MemberRef; mapping added. Ensure clients shift to `displayName`.
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ from recipes.repository import (
|
||||||
get_all as get_all,
|
get_all as get_all,
|
||||||
get_all_paged as get_all_paged,
|
get_all_paged as get_all_paged,
|
||||||
get_all_paged_scoped as get_all_paged_scoped,
|
get_all_paged_scoped as get_all_paged_scoped,
|
||||||
hide_recipe as hide_recipe,
|
|
||||||
insert_recipe as insert_recipe,
|
insert_recipe as insert_recipe,
|
||||||
insert_recipe_scoped as insert_recipe_scoped,
|
insert_recipe_scoped as insert_recipe_scoped,
|
||||||
load_recipe_ingredients as load_recipe_ingredients,
|
load_recipe_ingredients as load_recipe_ingredients,
|
||||||
|
|
|
||||||
|
|
@ -74,17 +74,6 @@ async def insert_recipe_scoped(conn, recipe: Recipe, household_id: int):
|
||||||
recipe.id = cursor.lastrowid
|
recipe.id = cursor.lastrowid
|
||||||
|
|
||||||
|
|
||||||
async def hide_recipe(conn, recipe_id: int, person):
|
|
||||||
await conn.execute(
|
|
||||||
"""
|
|
||||||
UPDATE Recipe
|
|
||||||
SET date_hidden = ?, hidden_by_id = ?
|
|
||||||
WHERE id = ?
|
|
||||||
""",
|
|
||||||
(datetime.datetime.now().astimezone().isoformat(), person.id, recipe_id),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def hide_recipe_scoped(conn, recipe_id: int, household_id: int) -> bool:
|
async def hide_recipe_scoped(conn, recipe_id: int, household_id: int) -> bool:
|
||||||
"""Soft-delete a recipe by household for v2.
|
"""Soft-delete a recipe by household for v2.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue