mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-06 22:15:22 +02:00
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:
parent
86c99b10a2
commit
6db1357064
66 changed files with 3455 additions and 1311 deletions
|
@ -1 +1,2 @@
|
|||
from .group_shopping_list import *
|
||||
from .webhook import *
|
||||
|
|
65
mealie/schema/group/group_shopping_list.py
Normal file
65
mealie/schema/group/group_shopping_list.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi_camelcase import CamelModel
|
||||
from pydantic import UUID4
|
||||
|
||||
from mealie.schema.recipe.recipe_ingredient import IngredientFood, IngredientUnit
|
||||
|
||||
|
||||
class ShoppingListItemCreate(CamelModel):
|
||||
shopping_list_id: UUID4
|
||||
checked: bool = False
|
||||
position: int = 0
|
||||
|
||||
is_food: bool = False
|
||||
|
||||
note: Optional[str] = ""
|
||||
quantity: float = 1
|
||||
unit_id: int = None
|
||||
unit: IngredientUnit = None
|
||||
food_id: int = None
|
||||
food: IngredientFood = None
|
||||
recipe_id: Optional[int] = None
|
||||
|
||||
label_id: Optional[UUID4] = None
|
||||
|
||||
|
||||
class ShoppingListItemOut(ShoppingListItemCreate):
|
||||
id: UUID4
|
||||
label: "Optional[MultiPurposeLabelSummary]" = None
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class ShoppingListCreate(CamelModel):
|
||||
"""
|
||||
Create Shopping List
|
||||
"""
|
||||
|
||||
name: str = None
|
||||
|
||||
|
||||
class ShoppingListSave(ShoppingListCreate):
|
||||
group_id: UUID4
|
||||
|
||||
|
||||
class ShoppingListSummary(ShoppingListSave):
|
||||
id: UUID4
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class ShoppingListUpdate(ShoppingListSummary):
|
||||
list_items: list[ShoppingListItemOut] = []
|
||||
|
||||
|
||||
class ShoppingListOut(ShoppingListUpdate):
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
from mealie.schema.labels import MultiPurposeLabelSummary
|
||||
|
||||
ShoppingListItemOut.update_forward_refs()
|
36
mealie/schema/labels/__init__.py
Normal file
36
mealie/schema/labels/__init__.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
from fastapi_camelcase import CamelModel
|
||||
from pydantic import UUID4
|
||||
|
||||
from mealie.schema.recipe import IngredientFood
|
||||
|
||||
|
||||
class MultiPurposeLabelCreate(CamelModel):
|
||||
name: str
|
||||
|
||||
|
||||
class MultiPurposeLabelSave(MultiPurposeLabelCreate):
|
||||
group_id: UUID4
|
||||
|
||||
|
||||
class MultiPurposeLabelUpdate(MultiPurposeLabelSave):
|
||||
id: UUID4
|
||||
|
||||
|
||||
class MultiPurposeLabelSummary(MultiPurposeLabelUpdate):
|
||||
pass
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class MultiPurposeLabelOut(MultiPurposeLabelUpdate):
|
||||
shopping_list_items: "list[ShoppingListItemOut]" = []
|
||||
foods: list[IngredientFood] = []
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
from mealie.schema.group.group_shopping_list import ShoppingListItemOut
|
||||
|
||||
MultiPurposeLabelOut.update_forward_refs()
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Generic, TypeVar
|
||||
from typing import TypeVar
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
@ -6,7 +6,7 @@ T = TypeVar("T", bound=BaseModel)
|
|||
U = TypeVar("U", bound=BaseModel)
|
||||
|
||||
|
||||
def mapper(source: U, dest: T, **kwargs) -> Generic[T]:
|
||||
def mapper(source: U, dest: T, **_) -> T:
|
||||
"""
|
||||
Map a source model to a destination model. Only top-level fields are mapped.
|
||||
"""
|
||||
|
@ -16,3 +16,9 @@ def mapper(source: U, dest: T, **kwargs) -> Generic[T]:
|
|||
setattr(dest, field, getattr(source, field))
|
||||
|
||||
return dest
|
||||
|
||||
|
||||
def cast(source: U, dest: T, **kwargs) -> T:
|
||||
create_data = {field: getattr(source, field) for field in source.__fields__ if field in dest.__fields__}
|
||||
create_data.update(kwargs or {})
|
||||
return dest(**create_data)
|
||||
|
|
6
mealie/schema/query.py
Normal file
6
mealie/schema/query.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from fastapi_camelcase import CamelModel
|
||||
|
||||
|
||||
class GetAll(CamelModel):
|
||||
start: int = 0
|
||||
limit: int = 999
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
@ -92,32 +94,32 @@ class RecipeSummary(CamelModel):
|
|||
orm_mode = True
|
||||
|
||||
@validator("tags", always=True, pre=True)
|
||||
def validate_tags(cats: list[Any]):
|
||||
def validate_tags(cats: list[Any]): # type: ignore
|
||||
if isinstance(cats, list) and cats and isinstance(cats[0], str):
|
||||
return [RecipeTag(name=c, slug=slugify(c)) for c in cats]
|
||||
return cats
|
||||
|
||||
@validator("recipe_category", always=True, pre=True)
|
||||
def validate_categories(cats: list[Any]):
|
||||
def validate_categories(cats: list[Any]): # type: ignore
|
||||
if isinstance(cats, list) and cats and isinstance(cats[0], str):
|
||||
return [RecipeCategory(name=c, slug=slugify(c)) for c in cats]
|
||||
return cats
|
||||
|
||||
@validator("group_id", always=True, pre=True)
|
||||
def validate_group_id(group_id: list[Any]):
|
||||
def validate_group_id(group_id: Any):
|
||||
if isinstance(group_id, int):
|
||||
return uuid4()
|
||||
return group_id
|
||||
|
||||
@validator("user_id", always=True, pre=True)
|
||||
def validate_user_id(user_id: list[Any]):
|
||||
def validate_user_id(user_id: Any):
|
||||
if isinstance(user_id, int):
|
||||
return uuid4()
|
||||
return user_id
|
||||
|
||||
|
||||
class Recipe(RecipeSummary):
|
||||
recipe_ingredient: Optional[list[RecipeIngredient]] = []
|
||||
recipe_ingredient: list[RecipeIngredient] = []
|
||||
recipe_instructions: Optional[list[RecipeStep]] = []
|
||||
nutrition: Optional[Nutrition]
|
||||
|
||||
|
@ -155,7 +157,7 @@ class Recipe(RecipeSummary):
|
|||
orm_mode = True
|
||||
|
||||
@classmethod
|
||||
def getter_dict(_cls, name_orm: RecipeModel):
|
||||
def getter_dict(cls, name_orm: RecipeModel):
|
||||
return {
|
||||
**GetterDict(name_orm),
|
||||
# "recipe_ingredient": [x.note for x in name_orm.recipe_ingredient],
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class ErrorResponse(BaseModel):
|
||||
message: str
|
||||
error: bool = True
|
||||
exception: str = None
|
||||
exception: Optional[str] = None
|
||||
|
||||
@classmethod
|
||||
def respond(cls, message: str, exception: Optional[str] = None) -> dict:
|
||||
"""
|
||||
This method is an helper to create an obect and convert to a dictionary
|
||||
in the same call, for use while providing details to a HTTPException
|
||||
"""
|
||||
return cls(message=message, exception=exception).dict()
|
||||
|
|
|
@ -13,7 +13,6 @@ from mealie.db.models.users import User
|
|||
from mealie.schema.group.group_preferences import ReadGroupPreferences
|
||||
from mealie.schema.recipe import RecipeSummary
|
||||
|
||||
from ..meal_plan import ShoppingListOut
|
||||
from ..recipe import CategoryBase
|
||||
|
||||
settings = get_app_settings()
|
||||
|
@ -148,7 +147,6 @@ class UpdateGroup(GroupBase):
|
|||
|
||||
class GroupInDB(UpdateGroup):
|
||||
users: Optional[list[UserOut]]
|
||||
shopping_lists: Optional[list[ShoppingListOut]]
|
||||
preferences: Optional[ReadGroupPreferences] = None
|
||||
|
||||
class Config:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue