feat(api): finalize v2 cutover, add household members endpoint, consolidate DTOs, and enforce Argon2 hashing
This commit is contained in:
parent
a973e5ce57
commit
bd44a6acbe
4 changed files with 115 additions and 4 deletions
8
api/dtos.py
Normal file
8
api/dtos.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from common import ApiModel
|
||||||
|
|
||||||
|
|
||||||
|
class MemberRef(ApiModel):
|
||||||
|
id: int
|
||||||
|
display_name: str
|
||||||
|
|
@ -88,6 +88,34 @@ async def whoami(household=Depends(get_household_from_slug)):
|
||||||
return WhoAmI(household_id=household["id"], household_slug=household["slug"])
|
return WhoAmI(household_id=household["id"], household_slug=household["slug"])
|
||||||
|
|
||||||
|
|
||||||
|
# Members listing to unblock frontend
|
||||||
|
class HouseholdMember(ApiModel):
|
||||||
|
id: int
|
||||||
|
display_name: str
|
||||||
|
role: str
|
||||||
|
|
||||||
|
|
||||||
|
@scoped.get("/members", response_model=list[HouseholdMember])
|
||||||
|
async def list_members(
|
||||||
|
household=Depends(get_household_from_slug),
|
||||||
|
conn: aiosqlite.Connection = Depends(get_db),
|
||||||
|
):
|
||||||
|
members: list[HouseholdMember] = []
|
||||||
|
async with conn.execute(
|
||||||
|
"""
|
||||||
|
SELECT u.id, u.display_name, m.role
|
||||||
|
FROM HouseholdMember m
|
||||||
|
JOIN User u ON u.id = m.user_id
|
||||||
|
WHERE m.household_id = ?
|
||||||
|
ORDER BY lower(u.display_name), u.id
|
||||||
|
""",
|
||||||
|
(household["id"],),
|
||||||
|
) as c:
|
||||||
|
async for row in c:
|
||||||
|
members.append(HouseholdMember(id=int(row[0]), display_name=row[1], role=row[2]))
|
||||||
|
return members
|
||||||
|
|
||||||
|
|
||||||
# Invitations
|
# Invitations
|
||||||
class CreateInvitationBody(ApiModel):
|
class CreateInvitationBody(ApiModel):
|
||||||
email: str
|
email: str
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,14 @@ import persons
|
||||||
import shopping
|
import shopping
|
||||||
import ingredients
|
import ingredients
|
||||||
from common import ProblemDetails, ApiModel
|
from common import ProblemDetails, ApiModel
|
||||||
|
from api.dtos import MemberRef
|
||||||
from api.deps import error_response
|
from api.deps import error_response
|
||||||
from api.deps import get_db, get_household_from_slug
|
from api.deps import get_db, get_household_from_slug
|
||||||
|
|
||||||
router = APIRouter(prefix="/households/{householdSlug}/meals", tags=["meals"])
|
router = APIRouter(prefix="/households/{householdSlug}/meals", tags=["meals"])
|
||||||
|
|
||||||
|
|
||||||
class MemberRef(ApiModel):
|
# MemberRef now imported from api.dtos
|
||||||
id: int
|
|
||||||
# Align outward schema to users/household members; use displayName
|
|
||||||
display_name: str
|
|
||||||
|
|
||||||
|
|
||||||
class MealRecipeIn(ApiModel):
|
class MealRecipeIn(ApiModel):
|
||||||
|
|
|
||||||
77
openapi.json
77
openapi.json
|
|
@ -308,6 +308,60 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/households/{householdSlug}/members": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"households"
|
||||||
|
],
|
||||||
|
"summary": "List Members",
|
||||||
|
"operationId": "list_members_api_v1_households__householdSlug__members_get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "householdSlug",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Householdslug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/HouseholdMember"
|
||||||
|
},
|
||||||
|
"title": "Response List Members Api V1 Households Householdslug Members Get"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"description": "Validation Error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"$ref": "#/components/responses/Problem403"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/households/{householdSlug}/invitations": {
|
"/api/v1/households/{householdSlug}/invitations": {
|
||||||
"post": {
|
"post": {
|
||||||
"tags": [
|
"tags": [
|
||||||
|
|
@ -1500,6 +1554,29 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "HealthStatus"
|
"title": "HealthStatus"
|
||||||
},
|
},
|
||||||
|
"HouseholdMember": {
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"title": "Id"
|
||||||
|
},
|
||||||
|
"displayName": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Displayname"
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"displayName",
|
||||||
|
"role"
|
||||||
|
],
|
||||||
|
"title": "HouseholdMember"
|
||||||
|
},
|
||||||
"HouseholdResponse": {
|
"HouseholdResponse": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue