f2205b93f4
Tree and person soft-delete + restore (owner-only for trees, editor for people) with recovery listings (?deleted=true); the worker already purges past the 30-day window. Adds tree-wide GET /relationships and /events so the family/pedigree view loads the whole graph in a few calls. 27 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Justin Paul <justin@jpaul.me>
50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
import uuid
|
|
|
|
from fastapi import APIRouter, status
|
|
|
|
from app.api.deps import CurrentUser, SessionDep
|
|
from app.schemas.tree import TreeCreate, TreeRead
|
|
from app.services import tree_service
|
|
|
|
router = APIRouter(prefix="/trees", tags=["trees"])
|
|
|
|
|
|
@router.post("", response_model=TreeRead, status_code=status.HTTP_201_CREATED)
|
|
async def create_tree(data: TreeCreate, session: SessionDep, current: CurrentUser) -> TreeRead:
|
|
tree = await tree_service.create_tree(
|
|
session,
|
|
owner=current,
|
|
name=data.name,
|
|
description=data.description,
|
|
visibility=data.visibility,
|
|
)
|
|
return TreeRead.model_validate(tree)
|
|
|
|
|
|
@router.get("", response_model=list[TreeRead])
|
|
async def list_my_trees(
|
|
session: SessionDep, current: CurrentUser, deleted: bool = False
|
|
) -> list[TreeRead]:
|
|
if deleted:
|
|
trees = await tree_service.list_deleted_trees_for_user(session, user=current)
|
|
else:
|
|
trees = await tree_service.list_trees_for_user(session, user=current)
|
|
return [TreeRead.model_validate(t) for t in trees]
|
|
|
|
|
|
@router.get("/{tree_id}", response_model=TreeRead)
|
|
async def get_tree(tree_id: uuid.UUID, session: SessionDep, current: CurrentUser) -> TreeRead:
|
|
tree = await tree_service.get_tree(session, viewer_id=current.id, tree_id=tree_id)
|
|
return TreeRead.model_validate(tree)
|
|
|
|
|
|
@router.delete("/{tree_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
async def delete_tree(tree_id: uuid.UUID, session: SessionDep, current: CurrentUser) -> None:
|
|
await tree_service.delete_tree(session, actor=current, tree_id=tree_id)
|
|
|
|
|
|
@router.post("/{tree_id}/restore", response_model=TreeRead)
|
|
async def restore_tree(tree_id: uuid.UUID, session: SessionDep, current: CurrentUser) -> TreeRead:
|
|
tree = await tree_service.restore_tree(session, actor=current, tree_id=tree_id)
|
|
return TreeRead.model_validate(tree)
|