feature/mealplanner-rewrite (#417)

* multiple recipes per day

* fix update

* meal-planner rewrite

* disable meal-tests

* spacing

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden
2021-05-22 21:04:19 -08:00
committed by GitHub
parent 4b3fc45c1c
commit ef87f2231d
42 changed files with 1502 additions and 491 deletions

View File

@@ -3,19 +3,21 @@ from logging import getLogger
from mealie.db.db_base import BaseDocument
from mealie.db.models.event import Event, EventNotification
from mealie.db.models.group import Group
from mealie.db.models.mealplan import MealPlanModel
from mealie.db.models.mealplan import MealPlan
from mealie.db.models.recipe.recipe import Category, RecipeModel, Tag
from mealie.db.models.settings import CustomPage, SiteSettings
from mealie.db.models.shopping_list import ShoppingList
from mealie.db.models.sign_up import SignUp
from mealie.db.models.theme import SiteThemeModel
from mealie.db.models.users import LongLiveToken, User
from mealie.schema.category import RecipeCategoryResponse, RecipeTagResponse
from mealie.schema.event_notifications import EventNotificationIn
from mealie.schema.events import Event as EventSchema
from mealie.schema.meal import MealPlanInDB
from mealie.schema.meal import MealPlanOut
from mealie.schema.recipe import Recipe
from mealie.schema.settings import CustomPageOut
from mealie.schema.settings import SiteSettings as SiteSettingsSchema
from mealie.schema.shopping_list import ShoppingListOut
from mealie.schema.sign_up import SignUpOut
from mealie.schema.theme import SiteTheme
from mealie.schema.user import GroupInDB, LongLiveTokenInDB, UserInDB
@@ -75,8 +77,8 @@ class _Tags(BaseDocument):
class _Meals(BaseDocument):
def __init__(self) -> None:
self.primary_key = "uid"
self.sql_model = MealPlanModel
self.schema = MealPlanInDB
self.sql_model = MealPlan
self.schema = MealPlanOut
class _Settings(BaseDocument):
@@ -120,7 +122,7 @@ class _Groups(BaseDocument):
self.sql_model = Group
self.schema = GroupInDB
def get_meals(self, session: Session, match_value: str, match_key: str = "name") -> list[MealPlanInDB]:
def get_meals(self, session: Session, match_value: str, match_key: str = "name") -> list[MealPlanOut]:
"""A Helper function to get the group from the database and return a sorted list of
Args:
@@ -129,13 +131,20 @@ class _Groups(BaseDocument):
match_key (str, optional): Match Key. Defaults to "name".
Returns:
list[MealPlanInDB]: [description]
list[MealPlanOut]: [description]
"""
group: GroupInDB = session.query(self.sql_model).filter_by(**{match_key: match_value}).one_or_none()
return group.mealplans
class _ShoppingList(BaseDocument):
def __init__(self) -> None:
self.primary_key = "id"
self.sql_model = ShoppingList
self.schema = ShoppingListOut
class _SignUps(BaseDocument):
def __init__(self) -> None:
self.primary_key = "token"
@@ -179,6 +188,7 @@ class Database:
self.custom_pages = _CustomPages()
self.events = _Events()
self.event_notifications = _EventNotification()
self.shopping_lists = _ShoppingList()
db = Database()

View File

@@ -3,6 +3,7 @@ from mealie.db.models.group import *
from mealie.db.models.mealplan import *
from mealie.db.models.recipe.recipe import *
from mealie.db.models.settings import *
from mealie.db.models.shopping_list import *
from mealie.db.models.sign_up import *
from mealie.db.models.theme import *
from mealie.db.models.users import *

View File

@@ -19,11 +19,18 @@ class Group(SqlAlchemyBase, BaseMixins):
name = sa.Column(sa.String, index=True, nullable=False, unique=True)
users = orm.relationship("User", back_populates="group")
mealplans = orm.relationship(
"MealPlanModel",
"MealPlan",
back_populates="group",
single_parent=True,
order_by="MealPlanModel.startDate",
order_by="MealPlan.start_date",
)
shopping_lists = orm.relationship(
"ShoppingList",
back_populates="group",
single_parent=True,
)
categories = orm.relationship("Category", secondary=group2categories, single_parent=True)
# Webhook Settings
@@ -32,16 +39,7 @@ class Group(SqlAlchemyBase, BaseMixins):
webhook_urls = orm.relationship("WebhookURLModel", uselist=True, cascade="all, delete-orphan")
def __init__(
self,
name,
id=None,
users=None,
mealplans=None,
categories=[],
session=None,
webhook_enable=False,
webhook_time="00:00",
webhook_urls=[],
self, name, categories=[], session=None, webhook_enable=False, webhook_time="00:00", webhook_urls=[], **_
) -> None:
self.name = name
self.categories = [Category.get_ref(session=session, slug=cat.get("slug")) for cat in categories]

View File

@@ -1,50 +1,80 @@
from typing import List
import sqlalchemy as sa
import sqlalchemy.orm as orm
from mealie.db.models.group import Group
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
from mealie.db.models.recipe.recipe import RecipeModel
from mealie.db.models.shopping_list import ShoppingList
from sqlalchemy import Column, Date, ForeignKey, Integer, String
from sqlalchemy.ext.orderinglist import ordering_list
class Meal(SqlAlchemyBase):
__tablename__ = "meal"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.Integer, sa.ForeignKey("mealplan.uid"))
slug = sa.Column(sa.String)
name = sa.Column(sa.String)
date = sa.Column(sa.Date)
image = sa.Column(sa.String)
description = sa.Column(sa.String)
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("mealdays.id"))
position = Column(Integer)
name = Column(String)
slug = Column(String)
description = Column(String)
def __init__(self, slug, name="", description="", session=None) -> None:
if slug and slug != "":
recipe: RecipeModel = session.query(RecipeModel).filter(RecipeModel.slug == slug).one_or_none()
if recipe:
name = recipe.name
self.slug = recipe.slug
description = recipe.description
def __init__(self, slug, name, date, image, description, session=None) -> None:
self.slug = slug
self.name = name
self.date = date
self.image = image
self.description = description
class MealPlanModel(SqlAlchemyBase, BaseMixins):
class MealDay(SqlAlchemyBase, BaseMixins):
__tablename__ = "mealdays"
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("mealplan.uid"))
date = Column(Date)
meals: list[Meal] = orm.relationship(
Meal,
cascade="all, delete, delete-orphan",
order_by="Meal.position",
collection_class=ordering_list("position"),
)
def __init__(self, date, meals: list, session=None):
self.date = date
self.meals = [Meal(**m, session=session) for m in meals]
class MealPlan(SqlAlchemyBase, BaseMixins):
__tablename__ = "mealplan"
uid = sa.Column(sa.Integer, primary_key=True, unique=True) # ! Probably Bad?
startDate = sa.Column(sa.Date)
endDate = sa.Column(sa.Date)
meals: List[Meal] = orm.relationship(Meal, cascade="all, delete, delete-orphan")
group_id = sa.Column(sa.Integer, sa.ForeignKey("groups.id"))
uid = Column(Integer, primary_key=True, unique=True)
start_date = Column(Date)
end_date = Column(Date)
plan_days: list[MealDay] = orm.relationship(MealDay, cascade="all, delete, delete-orphan")
group_id = Column(Integer, ForeignKey("groups.id"))
group = orm.relationship("Group", back_populates="mealplans")
def __init__(self, startDate, endDate, meals, group: str, uid=None, session=None) -> None:
self.startDate = startDate
self.endDate = endDate
shopping_list_id = Column(Integer, ForeignKey("shopping_lists.id"))
shopping_list: ShoppingList = orm.relationship("ShoppingList", single_parent=True)
def __init__(
self,
start_date,
end_date,
plan_days,
group: str,
shopping_list: int = None,
session=None,
**_,
) -> None:
self.start_date = start_date
self.end_date = end_date
self.group = Group.get_ref(session, group)
self.meals = [Meal(**meal) for meal in meals]
def update(self, session, startDate, endDate, meals, uid, group) -> None:
if shopping_list:
self.shopping_list = ShoppingList.get_ref(session, shopping_list)
self.__init__(
startDate=startDate,
endDate=endDate,
meals=meals,
group=group,
session=session,
)
self.plan_days = [MealDay(**day, session=session) for day in plan_days]

View File

@@ -0,0 +1,49 @@
import sqlalchemy.orm as orm
from mealie.db.models.group import Group
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
from requests import Session
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.ext.orderinglist import ordering_list
class ShoppingListItem(SqlAlchemyBase, BaseMixins):
__tablename__ = "shopping_list_items"
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("shopping_lists.id"))
position = Column(Integer, nullable=False)
title = Column(String)
text = Column(String)
quantity = Column(Integer)
checked = Column(Boolean)
def __init__(self, title, text, quantity, checked, **_) -> None:
self.title = title
self.text = text
self.quantity = quantity
self.checked = checked
class ShoppingList(SqlAlchemyBase, BaseMixins):
__tablename__ = "shopping_lists"
id = Column(Integer, primary_key=True)
group_id = Column(Integer, ForeignKey("groups.id"))
group = orm.relationship("Group", back_populates="shopping_lists")
name = Column(String)
items: list[ShoppingListItem] = orm.relationship(
ShoppingListItem,
cascade="all, delete, delete-orphan",
order_by="ShoppingListItem.position",
collection_class=ordering_list("position"),
)
def __init__(self, name, group, items, session=None, **_) -> None:
self.name = name
self.group = Group.get_ref(session, group)
self.items = [ShoppingListItem(**i) for i in items]
@staticmethod
def get_ref(session: Session, id: int):
return session.query(ShoppingList).filter(ShoppingList.id == id).one_or_none()