mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 14:33:33 -07:00
fix mealplan
This commit is contained in:
parent
57b2dfda1e
commit
746d39815a
16 changed files with 121 additions and 85 deletions
|
@ -79,6 +79,7 @@ export default {
|
|||
this.$store.dispatch("requestHomePageSettings");
|
||||
this.$store.dispatch("requestSiteSettings");
|
||||
this.$store.dispatch("refreshToken");
|
||||
this.$store.dispatch("requestCurrentGroup");
|
||||
this.darkModeSystemCheck();
|
||||
this.darkModeAddEventListener();
|
||||
},
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
const CREATE_EVENT = "created";
|
||||
import api from "@/api";
|
||||
import utils from "@/utils";
|
||||
import MealPlanCard from "./MealPlanCard";
|
||||
|
@ -116,9 +117,8 @@ export default {
|
|||
},
|
||||
},
|
||||
async mounted() {
|
||||
let settings = await api.settings.requestAll();
|
||||
this.items = await api.recipes.getAllByCategory(settings.planCategories);
|
||||
console.log(this.items);
|
||||
let categories = Array.from(this.groupSettings, x => x.name);
|
||||
this.items = await api.recipes.getAllByCategory(categories);
|
||||
|
||||
if (this.items.length === 0) {
|
||||
const keys = [
|
||||
|
@ -134,6 +134,9 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
groupSettings() {
|
||||
return this.$store.getters.getCurrentGroup;
|
||||
},
|
||||
actualStartDate() {
|
||||
return Date.parse(this.startDate);
|
||||
},
|
||||
|
@ -146,7 +149,6 @@ export default {
|
|||
|
||||
let dateDif = (endDate - startDate) / (1000 * 3600 * 24) + 1;
|
||||
|
||||
|
||||
if (dateDif < 1) {
|
||||
return null;
|
||||
}
|
||||
|
@ -190,12 +192,13 @@ export default {
|
|||
|
||||
async save() {
|
||||
const mealBody = {
|
||||
group: this.groupSettings.name,
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
meals: this.meals,
|
||||
};
|
||||
await api.mealPlans.create(mealBody);
|
||||
this.$emit("created");
|
||||
this.$emit(CREATE_EVENT);
|
||||
this.meals = [];
|
||||
this.startDate = null;
|
||||
this.endDate = null;
|
||||
|
|
|
@ -28,7 +28,7 @@ const actions = {
|
|||
const getters = {
|
||||
getGroups: state => state.groups,
|
||||
getGroupNames: state => Array.from(state.groups, x => x.name),
|
||||
getCurrentGroup: state => state.currentGroup
|
||||
getCurrentGroup: state => state.currentGroup,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
@ -9,12 +9,12 @@ from db.init_db import init_db
|
|||
from routes import (
|
||||
backup_routes,
|
||||
debug_routes,
|
||||
meal_routes,
|
||||
migration_routes,
|
||||
setting_routes,
|
||||
theme_routes,
|
||||
)
|
||||
from routes.groups import groups
|
||||
from routes.mealplans import mealplans
|
||||
from routes.recipe import (
|
||||
all_recipe_routes,
|
||||
category_routes,
|
||||
|
@ -51,7 +51,7 @@ def api_routers():
|
|||
app.include_router(recipe_crud_routes.router)
|
||||
|
||||
# Meal Routes
|
||||
app.include_router(meal_routes.router)
|
||||
app.include_router(mealplans.router)
|
||||
# Settings Routes
|
||||
app.include_router(setting_routes.router)
|
||||
app.include_router(theme_routes.router)
|
||||
|
|
|
@ -3,6 +3,9 @@ from pathlib import Path
|
|||
|
||||
import dotenv
|
||||
|
||||
APP_VERSION = "v0.3.0"
|
||||
DB_VERSION = "v0.3.0"
|
||||
|
||||
CWD = Path(__file__).parent
|
||||
|
||||
|
||||
|
@ -19,8 +22,6 @@ dotenv.load_dotenv(ENV)
|
|||
SECRET = "super-secret-key"
|
||||
|
||||
# General
|
||||
APP_VERSION = "v0.3.0"
|
||||
DB_VERSION = "v0.3.0"
|
||||
PRODUCTION = os.environ.get("ENV")
|
||||
PORT = int(os.getenv("mealie_port", 9000))
|
||||
API = os.getenv("api_docs", True)
|
||||
|
@ -83,7 +84,7 @@ else:
|
|||
|
||||
# Mongo Database
|
||||
MEALIE_DB_NAME = os.getenv("mealie_db_name", "mealie")
|
||||
DEFAULT_GROUP = os.getenv("default_group", "home")
|
||||
DEFAULT_GROUP = os.getenv("default_group", "Home")
|
||||
DB_USERNAME = os.getenv("db_username", "root")
|
||||
DB_PASSWORD = os.getenv("db_password", "example")
|
||||
DB_HOST = os.getenv("db_host", "mongo")
|
||||
|
|
|
@ -60,6 +60,10 @@ class Group(SqlAlchemyBase, BaseMixins):
|
|||
|
||||
self.__init__(session=session, *args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def get_ref(session: Session, name: str):
|
||||
return session.query(Group).filter(Group.name == name).one()
|
||||
|
||||
@staticmethod
|
||||
def create_if_not_exist(session, name: str = DEFAULT_GROUP):
|
||||
try:
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import uuid
|
||||
from typing import List
|
||||
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy.orm as orm
|
||||
from db.models.group import Group
|
||||
from db.models.model_base import BaseMixins, SqlAlchemyBase
|
||||
|
||||
|
||||
|
@ -29,16 +29,25 @@ class MealPlanModel(SqlAlchemyBase, BaseMixins):
|
|||
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.relation(Meal)
|
||||
meals: List[Meal] = orm.relationship(Meal, cascade="all, delete")
|
||||
group_id = sa.Column(sa.String, sa.ForeignKey("groups.id"))
|
||||
group = orm.relationship("Group", back_populates="mealplans")
|
||||
|
||||
def __init__(self, startDate, endDate, meals, uid=None, session=None) -> None:
|
||||
def __init__(
|
||||
self, startDate, endDate, meals, group: str, uid=None, session=None
|
||||
) -> None:
|
||||
self.startDate = startDate
|
||||
self.endDate = endDate
|
||||
self.group = Group.get_ref(session, group)
|
||||
self.meals = [Meal(**meal) for meal in meals]
|
||||
|
||||
def update(self, session, startDate, endDate, meals, uid) -> None:
|
||||
def update(self, session, startDate, endDate, meals, uid, group) -> None:
|
||||
MealPlanModel._sql_remove_list(session, [Meal], uid)
|
||||
|
||||
self.__init__(startDate, endDate, meals)
|
||||
self.__init__(
|
||||
startDate=startDate,
|
||||
endDate=endDate,
|
||||
meals=meals,
|
||||
group=group,
|
||||
session=session,
|
||||
)
|
||||
|
|
|
@ -1,44 +1,33 @@
|
|||
from datetime import date
|
||||
from typing import List
|
||||
|
||||
from db.database import db
|
||||
from db.db_setup import generate_session
|
||||
from fastapi import APIRouter, Depends
|
||||
from schema.meal import MealPlanBase, MealPlanInDB
|
||||
from schema.recipe import Recipe
|
||||
from routes.deps import manager
|
||||
from schema.meal import MealPlanIn, MealPlanInDB
|
||||
from schema.snackbar import SnackResponse
|
||||
from schema.user import GroupInDB, UserInDB
|
||||
from services.meal_services import get_todays_meal, process_meals
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
router = APIRouter(prefix="/api/meal-plans", tags=["Meal Plan"])
|
||||
|
||||
|
||||
@router.get("/all", response_model=List[MealPlanInDB])
|
||||
def get_all_meals(session: Session = Depends(generate_session)):
|
||||
@router.get("/all", response_model=list[MealPlanInDB])
|
||||
def get_all_meals(
|
||||
current_user: UserInDB = Depends(manager),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Returns a list of all available Meal Plan """
|
||||
|
||||
return db.meals.get_all(session)
|
||||
|
||||
|
||||
@router.get("/{id}/shopping-list")
|
||||
def get_shopping_list(id: str, session: Session = Depends(generate_session)):
|
||||
|
||||
#! Refactor into Single Database Call
|
||||
mealplan = db.meals.get(session, id)
|
||||
mealplan: MealPlanInDB
|
||||
slugs = [x.slug for x in mealplan.meals]
|
||||
recipes: list[Recipe] = [db.recipes.get(session, x) for x in slugs]
|
||||
ingredients = [
|
||||
{"name": x.name, "recipeIngredient": x.recipeIngredient}
|
||||
for x in recipes
|
||||
if x
|
||||
]
|
||||
|
||||
return ingredients
|
||||
print(current_user.group)
|
||||
group_entry: GroupInDB = db.groups.get(session, current_user.group, "name")
|
||||
return group_entry.mealplans
|
||||
|
||||
|
||||
@router.post("/create")
|
||||
def create_meal_plan(data: MealPlanBase, session: Session = Depends(generate_session)):
|
||||
def create_meal_plan(
|
||||
data: MealPlanIn,
|
||||
session: Session = Depends(generate_session),
|
||||
current_user=Depends(manager),
|
||||
):
|
||||
""" Creates a meal plan database entry """
|
||||
processed_plan = process_meals(session, data)
|
||||
db.meals.create(session, processed_plan.dict())
|
||||
|
@ -46,16 +35,9 @@ def create_meal_plan(data: MealPlanBase, session: Session = Depends(generate_ses
|
|||
return SnackResponse.success("Mealplan Created")
|
||||
|
||||
|
||||
@router.get("/this-week", response_model=MealPlanInDB)
|
||||
def get_this_week(session: Session = Depends(generate_session)):
|
||||
""" Returns the meal plan data for this week """
|
||||
|
||||
return db.meals.get_all(session, limit=1, order_by="startDate")
|
||||
|
||||
|
||||
@router.put("/{plan_id}")
|
||||
def update_meal_plan(
|
||||
plan_id: str, meal_plan: MealPlanBase, session: Session = Depends(generate_session)
|
||||
plan_id: str, meal_plan: MealPlanIn, session: Session = Depends(generate_session)
|
||||
):
|
||||
""" Updates a meal plan based off ID """
|
||||
processed_plan = process_meals(session, meal_plan)
|
||||
|
@ -74,6 +56,13 @@ def delete_meal_plan(plan_id, session: Session = Depends(generate_session)):
|
|||
return SnackResponse.error("Mealplan Deleted")
|
||||
|
||||
|
||||
@router.get("/this-week", response_model=MealPlanInDB)
|
||||
def get_this_week(session: Session = Depends(generate_session)):
|
||||
""" Returns the meal plan data for this week """
|
||||
|
||||
return db.meals.get_all(session, limit=1, order_by="startDate")
|
||||
|
||||
|
||||
@router.get("/today", tags=["Meal Plan"])
|
||||
def get_today(session: Session = Depends(generate_session)):
|
||||
"""
|
23
mealie/routes/mealplans/helpers.py
Normal file
23
mealie/routes/mealplans/helpers.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from db.database import db
|
||||
from db.db_setup import generate_session
|
||||
from fastapi import APIRouter, Depends
|
||||
from schema.meal import MealPlanInDB
|
||||
from schema.recipe import Recipe
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
router = APIRouter(prefix="/api/meal-plans", tags=["Meal Plan"])
|
||||
|
||||
|
||||
@router.get("/{id}/shopping-list")
|
||||
def get_shopping_list(id: str, session: Session = Depends(generate_session)):
|
||||
|
||||
#! Refactor into Single Database Call
|
||||
mealplan = db.meals.get(session, id)
|
||||
mealplan: MealPlanInDB
|
||||
slugs = [x.slug for x in mealplan.meals]
|
||||
recipes: list[Recipe] = [db.recipes.get(session, x) for x in slugs]
|
||||
ingredients = [
|
||||
{"name": x.name, "recipeIngredient": x.recipeIngredient} for x in recipes if x
|
||||
]
|
||||
|
||||
return ingredients
|
7
mealie/routes/mealplans/mealplans.py
Normal file
7
mealie/routes/mealplans/mealplans.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from fastapi import APIRouter
|
||||
from routes.mealplans import crud, helpers
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
router.include_router(crud.router)
|
||||
router.include_router(helpers.router)
|
|
@ -1,6 +1,5 @@
|
|||
import shutil
|
||||
from datetime import timedelta
|
||||
from os import access
|
||||
|
||||
from core.config import USER_DIR
|
||||
from core.security import get_password_hash, verify_password
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
from datetime import date
|
||||
from typing import List, Optional
|
||||
|
||||
from db.models.mealplan import MealPlanModel
|
||||
from pydantic import BaseModel, validator
|
||||
from pydantic.utils import GetterDict
|
||||
|
||||
|
||||
class MealIn(BaseModel):
|
||||
|
@ -18,7 +20,8 @@ class MealOut(MealIn):
|
|||
orm_mode = True
|
||||
|
||||
|
||||
class MealPlanBase(BaseModel):
|
||||
class MealPlanIn(BaseModel):
|
||||
group: str
|
||||
startDate: date
|
||||
endDate: date
|
||||
meals: List[MealIn]
|
||||
|
@ -30,7 +33,7 @@ class MealPlanBase(BaseModel):
|
|||
return v
|
||||
|
||||
|
||||
class MealPlanProcessed(MealPlanBase):
|
||||
class MealPlanProcessed(MealPlanIn):
|
||||
meals: list[MealOut]
|
||||
|
||||
|
||||
|
@ -40,18 +43,9 @@ class MealPlanInDB(MealPlanProcessed):
|
|||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class MealPlan(BaseModel):
|
||||
uid: Optional[str]
|
||||
|
||||
class Config:
|
||||
schema_extra = {
|
||||
"example": {
|
||||
"startDate": date.today(),
|
||||
"endDate": date.today(),
|
||||
"meals": [
|
||||
{"slug": "Packed Mac and Cheese", "date": date.today()},
|
||||
{"slug": "Eggs and Toast", "date": date.today()},
|
||||
],
|
||||
@classmethod
|
||||
def getter_dict(_cls, name_orm: MealPlanModel):
|
||||
return {
|
||||
**GetterDict(name_orm),
|
||||
"group": name_orm.group.name,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
from datetime import date, timedelta
|
||||
|
||||
from db.database import db
|
||||
from schema.meal import MealIn, MealOut, MealPlanBase, MealPlanProcessed
|
||||
from schema.meal import MealIn, MealOut, MealPlanIn, MealPlanProcessed
|
||||
from schema.recipe import Recipe
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
|
||||
def process_meals(session: Session, meal_plan_base: MealPlanBase) -> MealPlanProcessed:
|
||||
def process_meals(session: Session, meal_plan_base: MealPlanIn) -> MealPlanProcessed:
|
||||
meals = []
|
||||
for x, meal in enumerate(meal_plan_base.meals):
|
||||
meal: MealIn
|
||||
|
@ -30,7 +30,10 @@ def process_meals(session: Session, meal_plan_base: MealPlanBase) -> MealPlanPro
|
|||
meals.append(meal_data)
|
||||
|
||||
return MealPlanProcessed(
|
||||
meals=meals, startDate=meal_plan_base.startDate, endDate=meal_plan_base.endDate
|
||||
group=meal_plan_base.group,
|
||||
meals=meals,
|
||||
startDate=meal_plan_base.startDate,
|
||||
endDate=meal_plan_base.endDate,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ from tests.utils.routes import (
|
|||
|
||||
def get_meal_plan_template(first=None, second=None):
|
||||
return {
|
||||
"group": "Home",
|
||||
"startDate": "2021-01-18",
|
||||
"endDate": "2021-01-19",
|
||||
"meals": [
|
||||
|
@ -54,17 +55,17 @@ def slug_2(api_client):
|
|||
api_client.delete(RECIPES_PREFIX + "/" + slug_2)
|
||||
|
||||
|
||||
def test_create_mealplan(api_client, slug_1, slug_2):
|
||||
def test_create_mealplan(api_client, slug_1, slug_2, token):
|
||||
meal_plan = get_meal_plan_template()
|
||||
meal_plan["meals"][0]["slug"] = slug_1
|
||||
meal_plan["meals"][1]["slug"] = slug_2
|
||||
|
||||
response = api_client.post(MEALPLAN_CREATE, json=meal_plan)
|
||||
response = api_client.post(MEALPLAN_CREATE, json=meal_plan, headers=token)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_read_mealplan(api_client, slug_1, slug_2):
|
||||
response = api_client.get(MEALPLAN_ALL)
|
||||
def test_read_mealplan(api_client, slug_1, slug_2, token):
|
||||
response = api_client.get(MEALPLAN_ALL, headers=token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
@ -77,9 +78,9 @@ def test_read_mealplan(api_client, slug_1, slug_2):
|
|||
assert meals[1]["slug"] == meal_plan["meals"][1]["slug"]
|
||||
|
||||
|
||||
def test_update_mealplan(api_client, slug_1, slug_2):
|
||||
def test_update_mealplan(api_client, slug_1, slug_2, token):
|
||||
|
||||
response = api_client.get(MEALPLAN_ALL)
|
||||
response = api_client.get(MEALPLAN_ALL, headers=token)
|
||||
|
||||
existing_mealplan = json.loads(response.text)
|
||||
existing_mealplan = existing_mealplan[0]
|
||||
|
@ -89,11 +90,13 @@ def test_update_mealplan(api_client, slug_1, slug_2):
|
|||
existing_mealplan["meals"][0]["slug"] = slug_2
|
||||
existing_mealplan["meals"][1]["slug"] = slug_1
|
||||
|
||||
response = api_client.put(f"{MEALPLAN_PREFIX}/{plan_uid}", json=existing_mealplan)
|
||||
response = api_client.put(
|
||||
f"{MEALPLAN_PREFIX}/{plan_uid}", json=existing_mealplan, headers=token
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
response = api_client.get(MEALPLAN_ALL)
|
||||
response = api_client.get(MEALPLAN_ALL, headers=token)
|
||||
existing_mealplan = json.loads(response.text)
|
||||
existing_mealplan = existing_mealplan[0]
|
||||
|
||||
|
@ -101,8 +104,8 @@ def test_update_mealplan(api_client, slug_1, slug_2):
|
|||
assert existing_mealplan["meals"][1]["slug"] == slug_1
|
||||
|
||||
|
||||
def test_delete_mealplan(api_client):
|
||||
response = api_client.get(MEALPLAN_ALL)
|
||||
def test_delete_mealplan(api_client, token):
|
||||
response = api_client.get(MEALPLAN_ALL, headers=token)
|
||||
|
||||
assert response.status_code == 200
|
||||
existing_mealplan = json.loads(response.text)
|
||||
|
|
|
@ -16,7 +16,7 @@ def default_user():
|
|||
"id": 1,
|
||||
"fullName": "Change Me",
|
||||
"email": "changeme@email.com",
|
||||
"group": "home",
|
||||
"group": "Home",
|
||||
"admin": True
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ def new_user():
|
|||
"id": 2,
|
||||
"fullName": "My New User",
|
||||
"email": "newuser@email.com",
|
||||
"group": "home",
|
||||
"group": "Home",
|
||||
"admin": False
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ def test_create_user(api_client: requests, token, new_user):
|
|||
"fullName": "My New User",
|
||||
"email": "newuser@email.com",
|
||||
"password": "MyStrongPassword",
|
||||
"group": "home",
|
||||
"group": "Home",
|
||||
"admin": False
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ def test_update_user(api_client: requests, token):
|
|||
"id": 1,
|
||||
"fullName": "Updated Name",
|
||||
"email": "updated@email.com",
|
||||
"group": "home",
|
||||
"group": "Home",
|
||||
"admin": True
|
||||
}
|
||||
response = api_client.put(f"{BASE}/1", headers=token, json=update_data)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue