feat: (WIP) base-shoppinglist infra (#911)

* feat:  base-shoppinglist infra (WIP)

* add type checker

* implement controllers

* apply router fixes

* add checked section hide/animation

* add label support

* formatting

* fix overflow images

* add experimental banner

* fix #912 word break issue

* remove any type errors

* bump dependencies

* remove templates

* fix build errors

* bump node version

* fix template literal
This commit is contained in:
Hayden
2022-01-08 22:24:34 -09:00
committed by GitHub
parent 86c99b10a2
commit 6db1357064
66 changed files with 3455 additions and 1311 deletions

View File

@@ -8,7 +8,7 @@ from mealie.services.group_services import CookbookService, WebhookService
from mealie.services.group_services.meal_service import MealService
from mealie.services.group_services.reports_service import GroupReportService
from . import categories, invitations, migrations, preferences, self_service
from . import categories, invitations, labels, migrations, preferences, self_service, shopping_lists
router = APIRouter()
@@ -20,18 +20,18 @@ cookbook_router = RouterFactory(service=CookbookService, prefix="/groups/cookboo
@router.get("/groups/mealplans/today", tags=["Groups: Mealplans"])
def get_todays_meals(m_service: MealService = Depends(MealService.private)):
return m_service.get_today()
def get_todays_meals(ms: MealService = Depends(MealService.private)):
return ms.get_today()
meal_plan_router = RouterFactory(service=MealService, prefix="/groups/mealplans", tags=["Groups: Mealplans"])
@meal_plan_router.get("")
def get_all(start: date = None, limit: date = None, m_service: MealService = Depends(MealService.private)):
def get_all(start: date = None, limit: date = None, ms: MealService = Depends(MealService.private)):
start = start or date.today() - timedelta(days=999)
limit = limit or date.today() + timedelta(days=999)
return m_service.get_slice(start, limit)
return ms.get_slice(start, limit)
router.include_router(cookbook_router)
@@ -47,9 +47,12 @@ report_router = RouterFactory(service=GroupReportService, prefix="/groups/report
@report_router.get("")
def get_all_reports(
report_type: ReportCategory = None, gm_service: GroupReportService = Depends(GroupReportService.private)
report_type: ReportCategory = None,
gs: GroupReportService = Depends(GroupReportService.private),
):
return gm_service._get_all(report_type)
return gs._get_all(report_type)
router.include_router(report_router)
router.include_router(shopping_lists.router)
router.include_router(labels.router)

View File

@@ -0,0 +1,71 @@
from functools import cached_property
from sqlite3 import IntegrityError
from typing import Type
from fastapi import APIRouter, Depends
from pydantic import UUID4
from mealie.routes._base.controller import controller
from mealie.routes._base.dependencies import SharedDependencies
from mealie.routes._base.mixins import CrudMixins
from mealie.schema.labels import (
MultiPurposeLabelCreate,
MultiPurposeLabelOut,
MultiPurposeLabelSave,
MultiPurposeLabelSummary,
MultiPurposeLabelUpdate,
)
from mealie.schema.mapper import cast
from mealie.schema.query import GetAll
from mealie.services.group_services.shopping_lists import ShoppingListService
router = APIRouter(prefix="/groups/labels", tags=["Group: Multi Purpose Labels"])
@controller(router)
class ShoppingListRoutes:
deps: SharedDependencies = Depends(SharedDependencies.user)
service: ShoppingListService = Depends(ShoppingListService.private)
@cached_property
def repo(self):
if not self.deps.acting_user:
raise Exception("No user is logged in.")
return self.deps.repos.group_multi_purpose_labels.by_group(self.deps.acting_user.group_id)
def registered_exceptions(self, ex: Type[Exception]) -> str:
registered = {
Exception: "An unexpected error occurred.",
IntegrityError: "An unexpected error occurred.",
}
return registered.get(ex, "An unexpected error occurred.")
# =======================================================================
# CRUD Operations
@property
def mixins(self) -> CrudMixins:
return CrudMixins(self.repo, self.deps.logger, self.registered_exceptions, "An unexpected error occurred.")
@router.get("", response_model=list[MultiPurposeLabelSummary])
def get_all(self, q: GetAll = Depends(GetAll)):
return self.repo.get_all(start=q.start, limit=q.limit, override_schema=MultiPurposeLabelSummary)
@router.post("", response_model=MultiPurposeLabelOut)
def create_one(self, data: MultiPurposeLabelCreate):
save_data = cast(data, MultiPurposeLabelSave, group_id=self.deps.acting_user.group_id)
return self.mixins.create_one(save_data)
@router.get("/{item_id}", response_model=MultiPurposeLabelOut)
def get_one(self, item_id: UUID4):
return self.repo.get_one(item_id)
@router.put("/{item_id}", response_model=MultiPurposeLabelOut)
def update_one(self, item_id: UUID4, data: MultiPurposeLabelUpdate):
return self.mixins.update_one(data, item_id)
@router.delete("/{item_id}", response_model=MultiPurposeLabelOut)
def delete_one(self, item_id: UUID4):
return self.mixins.delete_one(item_id) # type: ignore

View File

@@ -0,0 +1,82 @@
from functools import cached_property
from sqlite3 import IntegrityError
from typing import Type
from fastapi import APIRouter, Depends
from pydantic import UUID4
from mealie.routes._base.controller import controller
from mealie.routes._base.dependencies import SharedDependencies
from mealie.routes._base.mixins import CrudMixins
from mealie.schema.group.group_shopping_list import (
ShoppingListCreate,
ShoppingListOut,
ShoppingListSave,
ShoppingListSummary,
ShoppingListUpdate,
)
from mealie.schema.mapper import cast
from mealie.schema.query import GetAll
from mealie.services.group_services.shopping_lists import ShoppingListService
router = APIRouter(prefix="/groups/shopping/lists", tags=["Group: Shopping Lists"])
@controller(router)
class ShoppingListRoutes:
deps: SharedDependencies = Depends(SharedDependencies.user)
service: ShoppingListService = Depends(ShoppingListService.private)
@cached_property
def repo(self):
if not self.deps.acting_user:
raise Exception("No user is logged in.")
return self.deps.repos.group_shopping_lists.by_group(self.deps.acting_user.group_id)
def registered_exceptions(self, ex: Type[Exception]) -> str:
registered = {
Exception: "An unexpected error occurred.",
IntegrityError: "An unexpected error occurred.",
}
return registered.get(ex, "An unexpected error occurred.")
# =======================================================================
# CRUD Operations
@property
def mixins(self) -> CrudMixins:
return CrudMixins(self.repo, self.deps.logger, self.registered_exceptions, "An unexpected error occurred.")
@router.get("", response_model=list[ShoppingListSummary])
def get_all(self, q: GetAll = Depends(GetAll)):
return self.repo.get_all(start=q.start, limit=q.limit, override_schema=ShoppingListSummary)
@router.post("", response_model=ShoppingListOut)
def create_one(self, data: ShoppingListCreate):
save_data = cast(data, ShoppingListSave, group_id=self.deps.acting_user.group_id)
return self.mixins.create_one(save_data)
@router.get("/{item_id}", response_model=ShoppingListOut)
def get_one(self, item_id: UUID4):
return self.repo.get_one(item_id)
@router.put("/{item_id}", response_model=ShoppingListOut)
def update_one(self, item_id: UUID4, data: ShoppingListUpdate):
return self.mixins.update_one(data, item_id)
@router.delete("/{item_id}", response_model=ShoppingListOut)
def delete_one(self, item_id: UUID4):
return self.mixins.delete_one(item_id) # type: ignore
# =======================================================================
# Other Operations
@router.post("/{item_id}/recipe/{recipe_id}", response_model=ShoppingListOut)
def add_recipe_ingredients_to_list(self, item_id: UUID4, recipe_id: int):
return self.service.add_recipe_ingredients_to_list(item_id, recipe_id)
@router.delete("/{item_id}/recipe/{recipe_id}", response_model=ShoppingListOut)
def remove_recipe_ingredients_from_list(self, item_id: UUID4, recipe_id: int):
return self.service.remove_recipe_ingredients_from_list(item_id, recipe_id)