+
{{ title }}
None:
self.primary_key = "slug"
self.sql_model: RecipeModel = RecipeModel
- self.orm_mode = False
+ self.orm_mode = True
+ self.schema: Recipe = Recipe
def update_image(self, session: Session, slug: str, extension: str = None) -> str:
entry: RecipeModel = self._query_one(session, match_value=slug)
@@ -43,7 +47,8 @@ class _Meals(BaseDocument):
def __init__(self) -> None:
self.primary_key = "uid"
self.sql_model = MealPlanModel
- self.orm_mode = False
+ self.orm_mode = True
+ self.schema = MealPlanInDB
class _Settings(BaseDocument):
@@ -70,10 +75,9 @@ class _Users(BaseDocument):
def update_password(self, session, id, password: str):
entry = self._query_one(session=session, match_value=id)
entry.update_password(password)
- return_data = entry.dict()
session.commit()
- return return_data
+ return self.schema.from_orm(entry)
class _Groups(BaseDocument):
@@ -88,7 +92,8 @@ class _SignUps(BaseDocument):
def __init__(self) -> None:
self.primary_key = "token"
self.sql_model = SignUp
- self.orm_mode = False
+ self.orm_mode = True
+ self.schema = SignUpOut
class Database:
diff --git a/mealie/db/db_base.py b/mealie/db/db_base.py
index 62041f3c5..9bc5f38fa 100644
--- a/mealie/db/db_base.py
+++ b/mealie/db/db_base.py
@@ -122,7 +122,7 @@ class BaseDocument:
return self.schema.from_orm(result[0])
except IndexError:
return None
- return [self.schema(x) for x in result]
+ return [self.schema.from_orm(x) for x in result]
db_entries = [x.dict() for x in result]
diff --git a/mealie/db/models/mealplan.py b/mealie/db/models/mealplan.py
index e1e2f11bd..8fe812541 100644
--- a/mealie/db/models/mealplan.py
+++ b/mealie/db/models/mealplan.py
@@ -13,32 +13,16 @@ class Meal(SqlAlchemyBase):
slug = sa.Column(sa.String)
name = sa.Column(sa.String)
date = sa.Column(sa.Date)
- dateText = sa.Column(sa.String)
image = sa.Column(sa.String)
description = sa.Column(sa.String)
- def __init__(
- self, slug, name, date, dateText, image, description, session=None
- ) -> None:
+ def __init__(self, slug, name, date, image, description, session=None) -> None:
self.slug = slug
self.name = name
self.date = date
- self.dateText = dateText
self.image = image
self.description = description
- def dict(self) -> dict:
- data = {
- "slug": self.slug,
- "name": self.name,
- "date": self.date,
- "dateText": self.dateText,
- "image": self.image,
- "description": self.description,
- }
-
- return data
-
class MealPlanModel(SqlAlchemyBase, BaseMixins):
__tablename__ = "mealplan"
@@ -58,13 +42,3 @@ class MealPlanModel(SqlAlchemyBase, BaseMixins):
MealPlanModel._sql_remove_list(session, [Meal], uid)
self.__init__(startDate, endDate, meals)
-
- def dict(self) -> dict:
- data = {
- "uid": self.uid,
- "startDate": self.startDate,
- "endDate": self.endDate,
- "meals": [meal.dict() for meal in self.meals],
- }
-
- return data
diff --git a/mealie/db/models/recipe/recipe.py b/mealie/db/models/recipe/recipe.py
index 30518f817..6a74238a4 100644
--- a/mealie/db/models/recipe/recipe.py
+++ b/mealie/db/models/recipe/recipe.py
@@ -183,29 +183,29 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
extras=extras,
)
- def dict(self):
- data = {
- "name": self.name,
- "description": self.description,
- "image": self.image,
- "recipeYield": self.recipeYield,
- "recipeCuisine": self.recipeCuisine,
- "recipeCategory": [x.to_str() for x in self.recipeCategory],
- "recipeIngredient": [x.to_str() for x in self.recipeIngredient],
- "recipeInstructions": [x.dict() for x in self.recipeInstructions],
- "nutrition": self.nutrition.dict(),
- "totalTime": self.totalTime,
- "prepTime": self.prepTime,
- "performTime": self.performTime,
- "tool": [x.str() for x in self.tool],
- # Mealie Specific
- "slug": self.slug,
- "tags": [x.to_str() for x in self.tags],
- "dateAdded": self.dateAdded,
- "notes": [x.dict() for x in self.notes],
- "rating": self.rating,
- "orgURL": self.orgURL,
- "extras": RecipeModel._flatten_dict(self.extras),
- }
+ # def dict(self):
+ # data = {
+ # "name": self.name,
+ # "description": self.description,
+ # "image": self.image,
+ # "recipeYield": self.recipeYield,
+ # "recipeCuisine": self.recipeCuisine,
+ # "recipeCategory": [x.to_str() for x in self.recipeCategory],
+ # "recipeIngredient": [x.to_str() for x in self.recipeIngredient],
+ # "recipeInstructions": [x.dict() for x in self.recipeInstructions],
+ # "nutrition": self.nutrition.dict(),
+ # "totalTime": self.totalTime,
+ # "prepTime": self.prepTime,
+ # "performTime": self.performTime,
+ # "tool": [x.str() for x in self.tool],
+ # # Mealie Specific
+ # "slug": self.slug,
+ # "tags": [x.to_str() for x in self.tags],
+ # "dateAdded": self.dateAdded,
+ # "notes": [x.dict() for x in self.notes],
+ # "rating": self.rating,
+ # "orgURL": self.orgURL,
+ # "extras": RecipeModel._flatten_dict(self.extras),
+ # }
- return data
+ # return data
diff --git a/mealie/db/models/sign_up.py b/mealie/db/models/sign_up.py
index 2a7a8d251..631c3d167 100644
--- a/mealie/db/models/sign_up.py
+++ b/mealie/db/models/sign_up.py
@@ -1,5 +1,5 @@
from db.models.model_base import BaseMixins, SqlAlchemyBase
-from sqlalchemy import Column, Integer, String, Boolean
+from sqlalchemy import Boolean, Column, Integer, String
class SignUp(SqlAlchemyBase, BaseMixins):
@@ -19,11 +19,3 @@ class SignUp(SqlAlchemyBase, BaseMixins):
self.token = token
self.name = name
self.admin = admin
-
- def dict(self):
- return {
- "id": self.id,
- "name": self.name,
- "token": self.token,
- "admin": self.admin
- }
diff --git a/mealie/routes/backup_routes.py b/mealie/routes/backup_routes.py
index 94f1d93ec..f31274c0f 100644
--- a/mealie/routes/backup_routes.py
+++ b/mealie/routes/backup_routes.py
@@ -5,11 +5,11 @@ from core.config import BACKUP_DIR, TEMPLATE_DIR
from db.db_setup import generate_session
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
from schema.backup import BackupJob, ImportJob, Imports, LocalBackup
+from schema.snackbar import SnackResponse
from services.backups.exports import backup_all
from services.backups.imports import ImportDatabase
from sqlalchemy.orm.session import Session
from starlette.responses import FileResponse
-from schema.snackbar import SnackResponse
router = APIRouter(prefix="/api/backups", tags=["Backups"])
diff --git a/mealie/routes/meal_routes.py b/mealie/routes/meal_routes.py
index 5ea32392e..053dc3daf 100644
--- a/mealie/routes/meal_routes.py
+++ b/mealie/routes/meal_routes.py
@@ -1,20 +1,22 @@
+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, HTTPException
+from fastapi import APIRouter, Depends
+from schema.meal import MealPlanBase, MealPlanInDB
from schema.snackbar import SnackResponse
-from services.meal_services import MealPlan
+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[MealPlan])
+@router.get("/all", response_model=List[MealPlanInDB])
def get_all_meals(session: Session = Depends(generate_session)):
""" Returns a list of all available Meal Plan """
- return MealPlan.get_all(session)
+ return db.meals.get_all(session)
@router.get("/{id}/shopping-list")
@@ -22,7 +24,8 @@ def get_shopping_list(id: str, session: Session = Depends(generate_session)):
#! Refactor into Single Database Call
mealplan = db.meals.get(session, id)
- slugs = [x.get("slug") for x in mealplan.get("meals")]
+ mealplan: MealPlanInDB
+ slugs = [x.slug for x in mealplan.meals]
recipes = [db.recipes.get(session, x) for x in slugs]
ingredients = [
{"name": x.get("name"), "recipeIngredient": x.get("recipeIngredient")}
@@ -34,28 +37,29 @@ def get_shopping_list(id: str, session: Session = Depends(generate_session)):
@router.post("/create")
-def set_meal_plan(data: MealPlan, session: Session = Depends(generate_session)):
+def create_meal_plan(data: MealPlanBase, session: Session = Depends(generate_session)):
""" Creates a meal plan database entry """
- data.process_meals(session)
- data.save_to_db(session)
+ processed_plan = process_meals(session, data)
+ db.meals.create(session, processed_plan.dict())
return SnackResponse.success("Mealplan Created")
-@router.get("/this-week", response_model=MealPlan)
+@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 MealPlan.this_week(session)
+ return db.meals.get_all(session, limit=1, order_by="startDate")
@router.put("/{plan_id}")
def update_meal_plan(
- plan_id: str, meal_plan: MealPlan, session: Session = Depends(generate_session)
+ plan_id: str, meal_plan: MealPlanBase, session: Session = Depends(generate_session)
):
""" Updates a meal plan based off ID """
- meal_plan.process_meals(session)
- meal_plan.update(session, plan_id)
+ processed_plan = process_meals(session, meal_plan)
+ processed_plan = MealPlanInDB(uid=plan_id, **processed_plan.dict())
+ db.meals.update(session, plan_id, processed_plan.dict())
return SnackResponse.info("Mealplan Updated")
@@ -64,7 +68,7 @@ def update_meal_plan(
def delete_meal_plan(plan_id, session: Session = Depends(generate_session)):
""" Removes a meal plan from the database """
- MealPlan.delete(session, plan_id)
+ db.meals.delete(session, plan_id)
return SnackResponse.error("Mealplan Deleted")
@@ -76,4 +80,4 @@ def get_today(session: Session = Depends(generate_session)):
If no meal is scheduled nothing is returned
"""
- return MealPlan.today(session)
+ return get_todays_meal(session)
diff --git a/mealie/routes/recipe/recipe_crud_routes.py b/mealie/routes/recipe/recipe_crud_routes.py
index 58ace63a8..1a1702255 100644
--- a/mealie/routes/recipe/recipe_crud_routes.py
+++ b/mealie/routes/recipe/recipe_crud_routes.py
@@ -1,13 +1,13 @@
+from db.database import db
from db.db_setup import generate_session
from fastapi import APIRouter, Depends, File, Form, HTTPException
from fastapi.logger import logger
from fastapi.responses import FileResponse
-from schema.recipe import RecipeURLIn
+from schema.recipe import Recipe, RecipeURLIn
+from schema.snackbar import SnackResponse
from services.image_services import read_image, write_image
-from services.recipe_services import Recipe
from services.scraper.scraper import create_from_url
from sqlalchemy.orm.session import Session
-from schema.snackbar import SnackResponse
router = APIRouter(
prefix="/api/recipes",
@@ -16,49 +16,47 @@ router = APIRouter(
@router.post("/create", status_code=201, response_model=str)
-def create_from_json(data: Recipe, db: Session = Depends(generate_session)) -> str:
+def create_from_json(data: Recipe, session: Session = Depends(generate_session)) -> str:
""" Takes in a JSON string and loads data into the database as a new entry"""
- new_recipe_slug = data.save_to_db(db)
+ recipe: Recipe = db.recipes.create(session, data.dict())
- return new_recipe_slug
+ return recipe.slug
@router.post("/create-url", status_code=201, response_model=str)
-def parse_recipe_url(url: RecipeURLIn, db: Session = Depends(generate_session)):
+def parse_recipe_url(url: RecipeURLIn, session: Session = Depends(generate_session)):
""" Takes in a URL and attempts to scrape data and load it into the database """
recipe = create_from_url(url.url)
-
- recipe.save_to_db(db)
+ recipe: Recipe = db.recipes.create(session, recipe.dict())
return recipe.slug
@router.get("/{recipe_slug}", response_model=Recipe)
-def get_recipe(recipe_slug: str, db: Session = Depends(generate_session)):
+def get_recipe(recipe_slug: str, session: Session = Depends(generate_session)):
""" Takes in a recipe slug, returns all data for a recipe """
- recipe = Recipe.get_by_slug(db, recipe_slug)
- return recipe
+ return db.recipes.get(session, recipe_slug)
@router.put("/{recipe_slug}")
def update_recipe(
- recipe_slug: str, data: Recipe, db: Session = Depends(generate_session)
+ recipe_slug: str, data: Recipe, session: Session = Depends(generate_session)
):
""" Updates a recipe by existing slug and data. """
- new_slug = data.update(db, recipe_slug)
+ recipe: Recipe = db.recipes.update(session, recipe_slug, data.dict())
- return new_slug
+ return recipe.slug
@router.delete("/{recipe_slug}")
-def delete_recipe(recipe_slug: str, db: Session = Depends(generate_session)):
+def delete_recipe(recipe_slug: str, session: Session = Depends(generate_session)):
""" Deletes a recipe by slug """
try:
- Recipe.delete(db, recipe_slug)
+ db.recipes.delete(session, recipe_slug)
except:
raise HTTPException(
status_code=404, detail=SnackResponse.error("Unable to Delete Recipe")
@@ -86,6 +84,6 @@ def update_recipe_image(
):
""" Removes an existing image and replaces it with the incoming file. """
response = write_image(recipe_slug, image, extension)
- Recipe.update_image(session, recipe_slug, extension)
+ db.recipes.update_image(session, recipe_slug, extension)
return response
diff --git a/mealie/schema/category.py b/mealie/schema/category.py
index 977818b5f..de74f1003 100644
--- a/mealie/schema/category.py
+++ b/mealie/schema/category.py
@@ -1,7 +1,7 @@
from typing import List, Optional
from pydantic.main import BaseModel
-from services.recipe_services import Recipe
+from schema.recipe import Recipe
class RecipeCategoryResponse(BaseModel):
diff --git a/mealie/schema/meal.py b/mealie/schema/meal.py
index 71f369a7c..0e90a832d 100644
--- a/mealie/schema/meal.py
+++ b/mealie/schema/meal.py
@@ -1,29 +1,47 @@
from datetime import date
from typing import List, Optional
-from pydantic import BaseModel
+from pydantic import BaseModel, validator
-class Meal(BaseModel):
- slug: Optional[str]
+class MealIn(BaseModel):
name: Optional[str]
- date: date
- dateText: str
+ slug: Optional[str]
+ date: Optional[date]
+
+
+class MealOut(MealIn):
image: Optional[str]
description: Optional[str]
+ class Config:
+ orm_mode = True
+
+
+class MealPlanBase(BaseModel):
+ startDate: date
+ endDate: date
+ meals: List[MealIn]
+
+ @validator("endDate")
+ def endDate_after_startDate(cls, v, values, **kwargs):
+ if "startDate" in values and v < values["startDate"]:
+ raise ValueError("EndDate should be greater than StartDate")
+ return v
+
+class MealPlanProcessed(MealPlanBase):
+ meals: list[MealOut]
+
+class MealPlanInDB(MealPlanProcessed):
+ uid: str
+
+ class Config:
+ orm_mode = True
-class MealData(BaseModel):
- name: Optional[str]
- slug: str
- dateText: str
class MealPlan(BaseModel):
uid: Optional[str]
- startDate: date
- endDate: date
- meals: List[Meal]
class Config:
schema_extra = {
diff --git a/mealie/schema/recipe.py b/mealie/schema/recipe.py
index b176d48de..2a5e12c67 100644
--- a/mealie/schema/recipe.py
+++ b/mealie/schema/recipe.py
@@ -1,7 +1,10 @@
import datetime
from typing import Any, List, Optional
-from pydantic import BaseModel, validator
+from db.models.recipe.ingredient import RecipeIngredient
+from db.models.recipe.recipe import RecipeModel
+from pydantic import BaseModel, Schema, validator
+from pydantic.utils import GetterDict
from slugify import slugify
@@ -9,10 +12,16 @@ class RecipeNote(BaseModel):
title: str
text: str
+ class Config:
+ orm_mode = True
+
class RecipeStep(BaseModel):
text: str
+ class Config:
+ orm_mode = True
+
class Nutrition(BaseModel):
calories: Optional[str]
@@ -22,6 +31,9 @@ class Nutrition(BaseModel):
sodiumContent: Optional[str]
sugarContent: Optional[str]
+ class Config:
+ orm_mode = True
+
class Recipe(BaseModel):
# Standard Schema
@@ -30,8 +42,8 @@ class Recipe(BaseModel):
image: Optional[Any]
recipeYield: Optional[str]
recipeCategory: Optional[List[str]] = []
- recipeIngredient: Optional[list]
- recipeInstructions: Optional[list]
+ recipeIngredient: Optional[list[str]]
+ recipeInstructions: Optional[list[RecipeStep]]
nutrition: Optional[Nutrition]
totalTime: Optional[str] = None
@@ -48,6 +60,18 @@ class Recipe(BaseModel):
extras: Optional[dict] = {}
class Config:
+ orm_mode = True
+
+ @classmethod
+ def getter_dict(cls, name_orm: RecipeModel):
+ print(name_orm.recipeIngredient)
+ return {
+ **GetterDict(name_orm),
+ "recipeIngredient": [x.ingredient for x in name_orm.recipeIngredient],
+ "recipeCategory": [x.name for x in name_orm.recipeCategory],
+ "tags": [x.name for x in name_orm.tags]
+ }
+
schema_extra = {
"example": {
"name": "Chicken and Rice With Leeks and Salsa Verde",
diff --git a/mealie/schema/sign_up.py b/mealie/schema/sign_up.py
index 9c21c2314..84b73fb5f 100644
--- a/mealie/schema/sign_up.py
+++ b/mealie/schema/sign_up.py
@@ -12,3 +12,6 @@ class SignUpToken(SignUpIn):
class SignUpOut(SignUpToken):
id: int
+
+ class Config:
+ orm_mode = True
diff --git a/mealie/services/backups/exports.py b/mealie/services/backups/exports.py
index c54daceff..d0f2d6cd6 100644
--- a/mealie/services/backups/exports.py
+++ b/mealie/services/backups/exports.py
@@ -8,8 +8,7 @@ from db.database import db
from db.db_setup import create_session
from fastapi.logger import logger
from jinja2 import Template
-from services.meal_services import MealPlan
-from services.recipe_services import Recipe
+from schema.recipe import Recipe
class ExportDatabase:
@@ -57,15 +56,16 @@ class ExportDatabase:
dir.mkdir(parents=True, exist_ok=True)
def export_recipes(self):
- all_recipes = Recipe.get_all(self.session)
+ all_recipes = db.recipes.get_all(self.session)
for recipe in all_recipes:
+ recipe: Recipe
logger.info(f"Backing Up Recipes: {recipe}")
- filename = recipe.get("slug") + ".json"
+ filename = recipe.slug + ".json"
file_path = self.recipe_dir.joinpath(filename)
- ExportDatabase._write_json_file(recipe, file_path)
+ ExportDatabase._write_json_file(recipe.dict(), file_path)
if self.templates:
self._export_template(recipe)
@@ -101,7 +101,7 @@ class ExportDatabase:
def export_meals(self):
#! Problem Parseing Datetime Objects... May come back to this
- meal_plans = MealPlan.get_all(self.session)
+ meal_plans = db.meals.get_all(self.session)
if meal_plans:
meal_plans = [x.dict() for x in meal_plans]
diff --git a/mealie/services/backups/imports.py b/mealie/services/backups/imports.py
index 4c357865c..4a60322f1 100644
--- a/mealie/services/backups/imports.py
+++ b/mealie/services/backups/imports.py
@@ -6,10 +6,11 @@ from typing import List
from core.config import BACKUP_DIR, IMG_DIR, TEMP_DIR
from db.database import db
+from db.db_setup import create_session
from fastapi.logger import logger
+from schema.recipe import Recipe
from schema.restore import RecipeImport, SettingsImport, ThemeImport
from schema.theme import SiteTheme
-from services.recipe_services import Recipe
from sqlalchemy.orm.session import Session
@@ -75,6 +76,7 @@ class ImportDatabase:
}
def import_recipes(self):
+ session = create_session()
recipe_dir: Path = self.import_dir.joinpath("recipes")
imports = []
@@ -88,10 +90,9 @@ class ImportDatabase:
if recipe_dict.get("categories", False):
recipe_dict["recipeCategory"] = recipe_dict.get("categories")
del recipe_dict["categories"]
- print(recipe_dict)
recipe_obj = Recipe(**recipe_dict)
- recipe_obj.save_to_db(self.session)
+ db.recipes.create(session, recipe_obj.dict())
import_status = RecipeImport(
name=recipe_obj.name, slug=recipe_obj.slug, status=True
)
diff --git a/mealie/services/meal_services.py b/mealie/services/meal_services.py
index d681112b1..5fe566fe2 100644
--- a/mealie/services/meal_services.py
+++ b/mealie/services/meal_services.py
@@ -1,111 +1,43 @@
from datetime import date, timedelta
-from typing import List, Optional
from db.database import db
-from pydantic import BaseModel, validator
+from schema.meal import MealIn, MealOut, MealPlanBase, MealPlanProcessed
+from schema.recipe import Recipe
from sqlalchemy.orm.session import Session
-from services.recipe_services import Recipe
+
+def process_meals(session: Session, meal_plan_base: MealPlanBase) -> MealPlanProcessed:
+ meals = []
+ for x, meal in enumerate(meal_plan_base.meals):
+ meal: MealIn
+ try:
+ recipe: Recipe = db.recipes.get(session, meal.slug)
+
+ meal_data = MealOut(
+ slug=recipe.slug,
+ name=recipe.name,
+ date=meal_plan_base.startDate + timedelta(days=x),
+ image=recipe.image,
+ description=recipe.description,
+ )
+
+ except:
+
+ meal_data = MealOut(
+ date=meal_plan_base.startDate + timedelta(days=x),
+ )
+
+ meals.append(meal_data)
+
+ return MealPlanProcessed(
+ meals=meals, startDate=meal_plan_base.startDate, endDate=meal_plan_base.endDate
+ )
-class Meal(BaseModel):
- slug: Optional[str]
- name: Optional[str]
- date: date
- dateText: str
- image: Optional[str]
- description: Optional[str]
+def get_todays_meal(session):
+ meal_plan = db.meals.get_all(session, limit=1, order_by="startDate")
-
-class MealData(BaseModel):
- name: Optional[str]
- slug: str
- dateText: str
-
-
-class MealPlan(BaseModel):
- uid: Optional[str]
- startDate: date
- endDate: date
- meals: List[Meal]
-
- 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()},
- ],
- }
- }
-
- @validator('endDate')
- def endDate_after_startDate(cls, v, values, **kwargs):
- if 'startDate' in values and v < values['startDate']:
- raise ValueError('EndDate should be greater than StartDate')
- return v
-
- def process_meals(self, session: Session):
- meals = []
- for x, meal in enumerate(self.meals):
-
- try:
- recipe = Recipe.get_by_slug(session, meal.slug)
-
- meal_data = {
- "slug": recipe.slug,
- "name": recipe.name,
- "date": self.startDate + timedelta(days=x),
- "dateText": meal.dateText,
- "image": recipe.image,
- "description": recipe.description,
- }
- except:
- meal_data = {
- "date": self.startDate + timedelta(days=x),
- "dateText": meal.dateText,
- }
-
- meals.append(Meal(**meal_data))
-
- self.meals = meals
-
- def save_to_db(self, session: Session):
- db.meals.create(session, self.dict())
-
- @staticmethod
- def get_all(session: Session) -> List:
-
- all_meals = [
- MealPlan(**x) for x in db.meals.get_all(session, order_by="startDate")
- ]
-
- return all_meals
-
- def update(self, session, uid):
- db.meals.update(session, uid, self.dict())
-
- @staticmethod
- def delete(session, uid):
- db.meals.delete(session, uid)
-
- @staticmethod
- def today(session: Session) -> str:
- """ Returns the meal slug for Today """
- meal_plan = db.meals.get_all(session, limit=1, order_by="startDate")
-
- meal_docs = [Meal(**meal) for meal in meal_plan["meals"]]
-
- for meal in meal_docs:
- if meal.date == date.today():
- return meal.slug
-
- return "No Meal Today"
-
- @staticmethod
- def this_week(session: Session):
- meal_plan = db.meals.get_all(session, limit=1, order_by="startDate")
-
- return meal_plan
+ for meal in meal_plan:
+ meal: MealOut
+ if meal.date == date.today():
+ return meal.slug
diff --git a/mealie/services/migrations/chowdown.py b/mealie/services/migrations/chowdown.py
index 85bad0554..702164aca 100644
--- a/mealie/services/migrations/chowdown.py
+++ b/mealie/services/migrations/chowdown.py
@@ -3,7 +3,8 @@ from pathlib import Path
import yaml
from core.config import IMG_DIR, TEMP_DIR
-from services.recipe_services import Recipe
+from db.database import db
+from schema.recipe import Recipe
from sqlalchemy.orm.session import Session
from utils.unzip import unpack_zip
@@ -49,32 +50,42 @@ def read_chowdown_file(recipe_file: Path) -> Recipe:
"tags": recipe_data.get("tags").split(","),
}
- new_recipe = Recipe(**reformat_data)
+ print(reformat_data)
reformated_list = []
- for instruction in new_recipe.recipeInstructions:
+ for instruction in reformat_data["recipeInstructions"]:
reformated_list.append({"text": instruction})
+ reformat_data["recipeInstructions"] = reformated_list
- new_recipe.recipeInstructions = reformated_list
-
- return new_recipe
+ return Recipe(**reformat_data)
def chowdown_migrate(session: Session, zip_file: Path):
- temp_dir = unpack_zip(zip_file)
+ temp_dir = unpack_zip(zip_file)
+ print(temp_dir.name)
+
+ path = Path(temp_dir.name)
+ for p in path.iterdir():
+ print("ItterDir", p)
+ for p in p.iterdir():
+ print("Sub Itter", p)
with temp_dir as dir:
- image_dir = TEMP_DIR.joinpath(dir, zip_file.stem, "images")
- recipe_dir = TEMP_DIR.joinpath(dir, zip_file.stem, "_recipes")
+ chow_dir = next(Path(dir).iterdir())
+ image_dir = TEMP_DIR.joinpath(chow_dir, "images")
+ recipe_dir = TEMP_DIR.joinpath(chow_dir, "_recipes")
+
+ print(image_dir.exists())
+ print(recipe_dir.exists())
failed_recipes = []
successful_recipes = []
for recipe in recipe_dir.glob("*.md"):
try:
new_recipe = read_chowdown_file(recipe)
- new_recipe.save_to_db(session)
- successful_recipes.append(recipe.stem)
- except:
+ db.recipes.create(session, new_recipe.dict())
+ successful_recipes.append(new_recipe.name)
+ except Exception as inst:
failed_recipes.append(recipe.stem)
failed_images = []
@@ -82,7 +93,8 @@ def chowdown_migrate(session: Session, zip_file: Path):
try:
if not image.stem in failed_recipes:
shutil.copy(image, IMG_DIR.joinpath(image.name))
- except:
+ except Exception as inst:
+ print(inst)
failed_images.append(image.name)
report = {"successful": successful_recipes, "failed": failed_recipes}
diff --git a/mealie/services/migrations/nextcloud.py b/mealie/services/migrations/nextcloud.py
index fe8547a52..34991b540 100644
--- a/mealie/services/migrations/nextcloud.py
+++ b/mealie/services/migrations/nextcloud.py
@@ -5,9 +5,10 @@ import zipfile
from pathlib import Path
from core.config import IMG_DIR, MIGRATION_DIR, TEMP_DIR
-from services.recipe_services import Recipe
+from schema.recipe import Recipe
from services.scraper.cleaner import Cleaner
from core.config import IMG_DIR, TEMP_DIR
+from db.database import db
def process_selection(selection: Path) -> Path:
@@ -77,7 +78,8 @@ def migrate(session, selection: str):
try:
recipe = import_recipes(dir)
- recipe.save_to_db(session)
+ db.recipes.create(session, recipe.dict())
+
successful_imports.append(recipe.name)
except:
logging.error(f"Failed Nextcloud Import: {dir.name}")
diff --git a/mealie/services/recipe_services.py b/mealie/services/recipe_services.py
deleted file mode 100644
index 82b2451e1..000000000
--- a/mealie/services/recipe_services.py
+++ /dev/null
@@ -1,141 +0,0 @@
-import datetime
-from pathlib import Path
-from typing import Any, List, Optional
-
-from db.database import db
-from pydantic import BaseModel, validator
-from slugify import slugify
-from sqlalchemy.orm.session import Session
-
-from services.image_services import delete_image
-
-
-class RecipeNote(BaseModel):
- title: str
- text: str
-
-
-class RecipeStep(BaseModel):
- text: str
-
-
-class Nutrition(BaseModel):
- calories: Optional[str]
- fatContent: Optional[str]
- fiberContent: Optional[str]
- proteinContent: Optional[str]
- sodiumContent: Optional[str]
- sugarContent: Optional[str]
-
-
-class Recipe(BaseModel):
- # Standard Schema
- name: str
- description: Optional[str]
- image: Optional[Any]
- nutrition: Optional[Nutrition]
- recipeYield: Optional[str]
- recipeCategory: Optional[List[str]] = []
- recipeIngredient: Optional[list]
- recipeInstructions: Optional[list]
- tool: Optional[list[str]]
-
- totalTime: Optional[str] = None
- prepTime: Optional[str] = None
- performTime: Optional[str] = None
-
- # Mealie Specific
- slug: Optional[str] = ""
- tags: Optional[List[str]] = []
- dateAdded: Optional[datetime.date]
- notes: Optional[List[RecipeNote]] = []
- rating: Optional[int] = 0
- orgURL: Optional[str] = ""
- extras: Optional[dict] = {}
-
- class Config:
- schema_extra = {
- "example": {
- "name": "Chicken and Rice With Leeks and Salsa Verde",
- "description": "This one-skillet dinner gets deep oniony flavor from lots of leeks cooked down to jammy tenderness.",
- "image": "chicken-and-rice-with-leeks-and-salsa-verde.jpg",
- "recipeYield": "4 Servings",
- "recipeIngredient": [
- "1 1/2 lb. skinless, boneless chicken thighs (4-8 depending on size)",
- "Kosher salt, freshly ground pepper",
- "3 Tbsp. unsalted butter, divided",
- ],
- "recipeInstructions": [
- {
- "text": "Season chicken with salt and pepper.",
- },
- ],
- "slug": "chicken-and-rice-with-leeks-and-salsa-verde",
- "tags": ["favorite", "yummy!"],
- "recipeCategory": ["Dinner", "Pasta"],
- "notes": [{"title": "Watch Out!", "text": "Prep the day before!"}],
- "orgURL": "https://www.bonappetit.com/recipe/chicken-and-rice-with-leeks-and-salsa-verde",
- "rating": 3,
- "extras": {"message": "Don't forget to defrost the chicken!"},
- }
- }
-
- @validator("slug", always=True, pre=True)
- def validate_slug(slug: str, values):
- name: str = values["name"]
- calc_slug: str = slugify(name)
-
- if slug == calc_slug:
- return slug
- else:
- slug = calc_slug
- return slug
-
- @classmethod
- def get_by_slug(cls, session, slug: str):
- """ Returns a Recipe Object by Slug """
-
- document = db.recipes.get(session, slug, "slug")
-
- return cls(**document)
-
- def save_to_db(self, session) -> str:
- recipe_dict = self.dict()
-
- try:
- extension = Path(recipe_dict["image"]).suffix
- recipe_dict["image"] = recipe_dict.get("slug") + extension
- except:
- recipe_dict["image"] = "no image"
-
- recipe_doc = db.recipes.create(session, recipe_dict)
- recipe = Recipe(**recipe_doc)
-
- return recipe.slug
-
- @staticmethod
- def delete(session: Session, recipe_slug: str) -> str:
- """ Removes the recipe from the database by slug """
- delete_image(recipe_slug)
- db.recipes.delete(session, recipe_slug)
- return "Document Deleted"
-
- def update(self, session: Session, recipe_slug: str):
- """ Updates the recipe from the database by slug"""
- updated_slug = db.recipes.update(session, recipe_slug, self.dict())
- return updated_slug.get("slug")
-
- @staticmethod
- def update_image(session: Session, slug: str, extension: str = None) -> str:
- """A helper function to pass the new image name and extension
- into the database.
-
- Args:
- slug (str): The current recipe slug
- extension (str): the file extension of the new image
- """
- return db.recipes.update_image(session, slug, extension)
-
- @staticmethod
- def get_all(session: Session):
- return db.recipes.get_all(session)
diff --git a/mealie/services/scraper/cleaner.py b/mealie/services/scraper/cleaner.py
index 2b94c9a94..a35be6431 100644
--- a/mealie/services/scraper/cleaner.py
+++ b/mealie/services/scraper/cleaner.py
@@ -48,6 +48,8 @@ class Cleaner:
recipe_data["slug"] = slugify(recipe_data.get("name"))
recipe_data["orgURL"] = url
+ print(recipe_data["recipeIngredient"])
+
return recipe_data
@staticmethod
diff --git a/mealie/services/scraper/scraper.py b/mealie/services/scraper/scraper.py
index 2ecb044af..8c138da0a 100644
--- a/mealie/services/scraper/scraper.py
+++ b/mealie/services/scraper/scraper.py
@@ -6,7 +6,7 @@ import scrape_schema_recipe
from core.config import DEBUG_DIR
from fastapi.logger import logger
from services.image_services import scrape_image
-from services.recipe_services import Recipe
+from schema.recipe import Recipe
from services.scraper import open_graph
from services.scraper.cleaner import Cleaner
diff --git a/mealie/tests/test_migrations/test_nextcloud.py b/mealie/tests/test_migrations/test_nextcloud.py
index b6d363358..f8b0804c2 100644
--- a/mealie/tests/test_migrations/test_nextcloud.py
+++ b/mealie/tests/test_migrations/test_nextcloud.py
@@ -1,7 +1,8 @@
from pathlib import Path
-from core.config import TEMP_DIR
+
import pytest
from core.config import TEMP_DIR
+from schema.recipe import Recipe
from services.image_services import IMG_DIR
from services.migrations.nextcloud import (
cleanup,
@@ -9,7 +10,6 @@ from services.migrations.nextcloud import (
prep,
process_selection,
)
-from services.recipe_services import Recipe
from tests.test_config import TEST_NEXTCLOUD_DIR
CWD = Path(__file__).parent
diff --git a/mealie/tests/test_routes/test_meal_routes.py b/mealie/tests/test_routes/test_meal_routes.py
index f86e77c48..f783bbf9d 100644
--- a/mealie/tests/test_routes/test_meal_routes.py
+++ b/mealie/tests/test_routes/test_meal_routes.py
@@ -19,12 +19,10 @@ def get_meal_plan_template(first=None, second=None):
{
"slug": first,
"date": "2021-1-17",
- "dateText": "Monday, January 18, 2021",
},
{
"slug": second,
"date": "2021-1-18",
- "dateText": "Tueday, January 19, 2021",
},
],
}
diff --git a/mealie/tests/test_services/test_migrations/test_nextcloud.py b/mealie/tests/test_services/test_migrations/test_nextcloud.py
index b6d363358..f8b0804c2 100644
--- a/mealie/tests/test_services/test_migrations/test_nextcloud.py
+++ b/mealie/tests/test_services/test_migrations/test_nextcloud.py
@@ -1,7 +1,8 @@
from pathlib import Path
-from core.config import TEMP_DIR
+
import pytest
from core.config import TEMP_DIR
+from schema.recipe import Recipe
from services.image_services import IMG_DIR
from services.migrations.nextcloud import (
cleanup,
@@ -9,7 +10,6 @@ from services.migrations.nextcloud import (
prep,
process_selection,
)
-from services.recipe_services import Recipe
from tests.test_config import TEST_NEXTCLOUD_DIR
CWD = Path(__file__).parent
diff --git a/mealie/utils/post_webhooks.py b/mealie/utils/post_webhooks.py
index 9bc475039..33d61bc6c 100644
--- a/mealie/utils/post_webhooks.py
+++ b/mealie/utils/post_webhooks.py
@@ -4,8 +4,7 @@ import requests
from db.database import db
from db.db_setup import create_session
from schema.settings import SiteSettings
-from services.meal_services import MealPlan
-from services.recipe_services import Recipe
+from services.meal_services import get_todays_meal
def post_webhooks():
@@ -14,7 +13,8 @@ def post_webhooks():
all_settings = SiteSettings(**all_settings)
if all_settings.webhooks.enabled:
- todays_meal = Recipe.get_by_slug(MealPlan.today()).dict()
+ today_slug = get_todays_meal(session)
+ todays_meal = db.recipes.get(session, today_slug)
urls = all_settings.webhooks.webhookURLs
for url in urls: