86 lines
2.5 KiB
Python
86 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from typing import List
|
|
|
|
import aiosqlite
|
|
from fastapi import APIRouter, Depends, Request
|
|
|
|
from api.deps import get_current_user, get_db, error_response, get_household_from_slug
|
|
from common import ApiModel
|
|
from users.models import User
|
|
|
|
router = APIRouter(tags=["households"])
|
|
|
|
|
|
class CreateHouseholdBody(ApiModel):
|
|
name: str
|
|
|
|
|
|
class HouseholdResponse(ApiModel):
|
|
id: int
|
|
name: str
|
|
slug: str
|
|
|
|
|
|
def slugify(name: str) -> str:
|
|
s = re.sub(r"[^a-z0-9]+", "-", name.lower()).strip("-")
|
|
return s or "household"
|
|
|
|
|
|
@router.get("/users/me/households", response_model=List[HouseholdResponse])
|
|
async def list_my_households(
|
|
request: Request, user: User = Depends(get_current_user), conn: aiosqlite.Connection = Depends(get_db)
|
|
):
|
|
results: list[HouseholdResponse] = []
|
|
async with conn.execute(
|
|
"""
|
|
SELECT h.id, h.name, h.slug FROM Household h
|
|
JOIN HouseholdMember m ON m.household_id = h.id
|
|
WHERE m.user_id = ?
|
|
ORDER BY h.id
|
|
""",
|
|
(user.id,),
|
|
) as c:
|
|
async for row in c:
|
|
results.append(HouseholdResponse(id=int(row[0]), name=row[1], slug=row[2]))
|
|
return results
|
|
|
|
|
|
@router.post("/households", response_model=HouseholdResponse)
|
|
async def create_household(
|
|
request: Request,
|
|
body: CreateHouseholdBody,
|
|
user: User = Depends(get_current_user),
|
|
conn: aiosqlite.Connection = Depends(get_db),
|
|
):
|
|
slug = slugify(body.name)
|
|
try:
|
|
async with conn.execute(
|
|
"INSERT INTO Household (name, slug) VALUES (?, ?)", (body.name, slug)
|
|
) as cur:
|
|
lrid = cur.lastrowid
|
|
if lrid is None:
|
|
return error_response(request, 400, "Unable to create household")
|
|
hid = int(lrid)
|
|
await conn.execute(
|
|
"INSERT INTO HouseholdMember (user_id, household_id, role) VALUES (?, ?, ?)",
|
|
(user.id, hid, "admin"),
|
|
)
|
|
return HouseholdResponse(id=hid, name=body.name, slug=slug)
|
|
except Exception:
|
|
return error_response(request, 400, "Unable to create household")
|
|
|
|
|
|
# Household-scoped router and endpoint to validate scoping mechanics
|
|
scoped = APIRouter(prefix="/households/{householdSlug}")
|
|
|
|
|
|
class WhoAmI(ApiModel):
|
|
household_id: int
|
|
household_slug: str
|
|
|
|
|
|
@scoped.get("/whoami", response_model=WhoAmI)
|
|
async def whoami(household=Depends(get_household_from_slug)):
|
|
return WhoAmI(household_id=household["id"], household_slug=household["slug"])
|