diff --git a/fooder/controller/preset.py b/fooder/controller/preset.py index 0dbf0b7..d2f684a 100644 --- a/fooder/controller/preset.py +++ b/fooder/controller/preset.py @@ -1,6 +1,7 @@ from typing import AsyncIterator, Optional +from fastapi import HTTPException -from ..model.preset import Preset +from ..model.preset import Preset, PresetDetails from ..domain.preset import Preset as DBPreset from .base import AuthorizedController @@ -14,3 +15,28 @@ class ListPresets(AuthorizedController): session, limit=limit, offset=offset, q=q ): yield Preset.from_orm(preset) + + +class GetPreset(AuthorizedController): + async def call(self, id: int) -> PresetDetails: + async with self.async_session() as session: + preset = await DBPreset.get(session, self.user.id, id) + + if preset is not None: + return PresetDetails.from_orm(preset) + + raise HTTPException(status_code=404, detail="preset not found") + + +class DeletePreset(AuthorizedController): + async def call( + self, + id: int, + ) -> AsyncIterator[Preset]: + async with self.async_session.begin() as session: + preset = await DBPreset.get(session, self.user.id, id) + + if preset is None: + raise HTTPException(status_code=404, detail="preset not found") + + await preset.delete(session) diff --git a/fooder/domain/preset.py b/fooder/domain/preset.py index 27627ef..12c9cc7 100644 --- a/fooder/domain/preset.py +++ b/fooder/domain/preset.py @@ -104,3 +104,9 @@ class Preset(Base, CommonMixin): .options(joinedload(cls.entries).joinedload(PresetEntry.product)) ) return await session.scalar(query) + + async def delete(self, session: AsyncSession) -> None: + for entry in self.entries: + await session.delete(entry) + await session.delete(self) + await session.flush() diff --git a/fooder/test/test_preset.py b/fooder/test/test_preset.py index a619910..2c492ea 100644 --- a/fooder/test/test_preset.py +++ b/fooder/test/test_preset.py @@ -86,3 +86,18 @@ def test_create_meal_from_preset(client, meal_from_preset): continue assert meal[k] == v, f"{k} != {v}" + + +@pytest.mark.dependency(depends=["test_list_presets"]) +def test_delete_preset(client): + presets = client.get("preset").json()["presets"] + preset_id = presets[0]["id"] + + response = client.get(f"preset/{preset_id}") + assert response.status_code == 200, response.json() + + response = client.delete(f"preset/{preset_id}") + assert response.status_code == 200, response.json() + + response = client.get(f"preset/{preset_id}") + assert response.status_code == 404, response.json() diff --git a/fooder/view/preset.py b/fooder/view/preset.py index d645279..a78a3ed 100644 --- a/fooder/view/preset.py +++ b/fooder/view/preset.py @@ -1,6 +1,6 @@ from fastapi import APIRouter, Depends, Request -from ..model.preset import ListPresetsPayload -from ..controller.preset import ListPresets +from ..model.preset import ListPresetsPayload, PresetDetails +from ..controller.preset import ListPresets, DeletePreset, GetPreset router = APIRouter(tags=["preset"]) @@ -17,3 +17,21 @@ async def list_presets( return ListPresetsPayload( presets=[p async for p in controller.call(limit=limit, offset=offset, q=q)] ) + + +@router.get("/{preset_id}", response_model=PresetDetails) +async def get_preset( + request: Request, + preset_id: int, + controller: GetPreset = Depends(GetPreset), +): + return await controller.call(preset_id) + + +@router.delete("/{preset_id}") +async def delete_preset( + request: Request, + preset_id: int, + controller: DeletePreset = Depends(DeletePreset), +): + await controller.call(preset_id)