mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-02-04 23:13:12 -05:00
refactor(backend): ♻️ align variable names, eliminate dead-code, and finalize recipe services
This commit is contained in:
@@ -5,10 +5,10 @@ from fastapi import Depends, Response
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
from mealie.core.dependencies import is_logged_in
|
||||
from mealie.core.root_logger import get_logger
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import SessionLocal, generate_session
|
||||
from mealie.core.dependencies import is_logged_in
|
||||
from mealie.schema.recipe import RecipeSummary
|
||||
|
||||
logger = get_logger()
|
||||
@@ -1,41 +0,0 @@
|
||||
from typing import Any
|
||||
|
||||
from fastapi import BackgroundTasks, Depends
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.core.dependencies import get_current_user, is_logged_in
|
||||
|
||||
|
||||
class CommonDeps(BaseModel):
|
||||
session: Session
|
||||
background_tasks: BackgroundTasks
|
||||
user: Any
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
def read_deps(
|
||||
background_tasks: BackgroundTasks,
|
||||
session: Session = Depends(generate_session),
|
||||
current_user=Depends(is_logged_in),
|
||||
):
|
||||
return CommonDeps(
|
||||
session=session,
|
||||
background_tasks=background_tasks,
|
||||
user=current_user,
|
||||
)
|
||||
|
||||
|
||||
def write_deps(
|
||||
background_tasks: BackgroundTasks,
|
||||
session: Session = Depends(generate_session),
|
||||
current_user=Depends(get_current_user),
|
||||
):
|
||||
return CommonDeps(
|
||||
session=session,
|
||||
background_tasks=background_tasks,
|
||||
user=current_user,
|
||||
)
|
||||
@@ -1,34 +0,0 @@
|
||||
from pathlib import Path
|
||||
from shutil import copytree, rmtree
|
||||
|
||||
from mealie.core.config import app_dirs
|
||||
from mealie.core.root_logger import get_logger
|
||||
from mealie.schema.recipe import Recipe
|
||||
|
||||
logger = get_logger()
|
||||
|
||||
|
||||
def check_assets(original_slug, recipe: Recipe) -> None:
|
||||
if original_slug != recipe.slug:
|
||||
current_dir = app_dirs.RECIPE_DATA_DIR.joinpath(original_slug)
|
||||
|
||||
try:
|
||||
copytree(current_dir, recipe.directory, dirs_exist_ok=True)
|
||||
|
||||
except FileNotFoundError:
|
||||
logger.error(f"Recipe Directory not Found: {original_slug}")
|
||||
logger.info(f"Renaming Recipe Directory: {original_slug} -> {recipe.slug}")
|
||||
|
||||
all_asset_files = [x.file_name for x in recipe.assets]
|
||||
for file in recipe.asset_dir.iterdir():
|
||||
file: Path
|
||||
if file.is_dir():
|
||||
continue
|
||||
if file.name not in all_asset_files:
|
||||
file.unlink()
|
||||
|
||||
|
||||
def delete_assets(recipe_slug):
|
||||
recipe_dir = Recipe(slug=recipe_slug).directory
|
||||
rmtree(recipe_dir, ignore_errors=True)
|
||||
logger.info(f"Recipe Directory Removed: {recipe_slug}")
|
||||
@@ -1,20 +1,33 @@
|
||||
from pathlib import Path
|
||||
from shutil import copytree, rmtree
|
||||
from typing import Union
|
||||
|
||||
from fastapi import BackgroundTasks, Depends, HTTPException, status
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
from mealie.core.config import get_settings
|
||||
from mealie.core.config import get_app_dirs, get_settings
|
||||
from mealie.core.dependencies import ReadDeps
|
||||
from mealie.core.dependencies.grouped import WriteDeps
|
||||
from mealie.core.root_logger import get_logger
|
||||
from mealie.db.database import get_database
|
||||
from mealie.db.db_setup import SessionLocal
|
||||
from mealie.schema.recipe.recipe import CreateRecipe, Recipe
|
||||
from mealie.schema.user.user import UserInDB
|
||||
from mealie.services.events import create_recipe_event
|
||||
from mealie.services.recipe.media import delete_assets
|
||||
|
||||
logger = get_logger(module=__name__)
|
||||
|
||||
|
||||
class RecipeService:
|
||||
recipe: Recipe
|
||||
"""
|
||||
Class Methods:
|
||||
`read_existing`: Reads an existing recipe from the database.
|
||||
`write_existing`: Updates an existing recipe in the database.
|
||||
`base`: Requires write permissions, but doesn't perform recipe checks
|
||||
"""
|
||||
|
||||
recipe: Recipe # Required for proper type hints
|
||||
|
||||
def __init__(self, session: Session, user: UserInDB, background_tasks: BackgroundTasks = None) -> None:
|
||||
self.session = session or SessionLocal()
|
||||
@@ -22,8 +35,9 @@ class RecipeService:
|
||||
self.background_tasks = background_tasks
|
||||
self.recipe: Recipe = None
|
||||
|
||||
# Static Globals
|
||||
# Static Globals Dependency Injection
|
||||
self.db = get_database()
|
||||
self.app_dirs = get_app_dirs()
|
||||
self.settings = get_settings()
|
||||
|
||||
@classmethod
|
||||
@@ -99,10 +113,11 @@ class RecipeService:
|
||||
raise HTTPException(status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# CRUD METHODS
|
||||
def create_recipe(self, new_recipe: CreateRecipe) -> Recipe:
|
||||
def create_recipe(self, create_data: Union[Recipe, CreateRecipe]) -> Recipe:
|
||||
if isinstance(create_data, CreateRecipe):
|
||||
create_data = Recipe(name=create_data.name)
|
||||
|
||||
try:
|
||||
create_data = Recipe(name=new_recipe.name)
|
||||
self.recipe = self.db.recipes.create(self.session, create_data)
|
||||
except IntegrityError:
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST, detail={"message": "RECIPE_ALREADY_EXISTS"})
|
||||
@@ -114,6 +129,32 @@ class RecipeService:
|
||||
|
||||
return self.recipe
|
||||
|
||||
def update_recipe(self, update_data: Recipe) -> Recipe:
|
||||
original_slug = self.recipe.slug
|
||||
|
||||
try:
|
||||
self.recipe = self.db.recipes.update(self.session, original_slug, update_data)
|
||||
except IntegrityError:
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST, detail={"message": "RECIPE_ALREADY_EXISTS"})
|
||||
|
||||
self._check_assets(original_slug)
|
||||
|
||||
return self.recipe
|
||||
|
||||
def patch_recipe(self, patch_data: Recipe) -> Recipe:
|
||||
original_slug = self.recipe.slug
|
||||
|
||||
try:
|
||||
self.recipe = self.db.recipes.patch(
|
||||
self.session, original_slug, patch_data.dict(exclude_unset=True, exclude_defaults=True)
|
||||
)
|
||||
except IntegrityError:
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST, detail={"message": "RECIPE_ALREADY_EXISTS"})
|
||||
|
||||
self._check_assets(original_slug)
|
||||
|
||||
return self.recipe
|
||||
|
||||
def delete_recipe(self) -> Recipe:
|
||||
"""removes a recipe from the database and purges the existing files from the filesystem.
|
||||
|
||||
@@ -126,7 +167,7 @@ class RecipeService:
|
||||
|
||||
try:
|
||||
recipe: Recipe = self.db.recipes.delete(self.session, self.recipe.slug)
|
||||
delete_assets(recipe_slug=self.recipe.slug)
|
||||
self._delete_assets()
|
||||
except Exception:
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@@ -135,3 +176,27 @@ class RecipeService:
|
||||
|
||||
def _create_event(self, title: str, message: str) -> None:
|
||||
self.background_tasks.add_task(create_recipe_event, title, message, self.session)
|
||||
|
||||
def _check_assets(self, original_slug) -> None:
|
||||
if original_slug != self.recipe.slug:
|
||||
current_dir = self.app_dirs.RECIPE_DATA_DIR.joinpath(original_slug)
|
||||
|
||||
try:
|
||||
copytree(current_dir, self.recipe.directory, dirs_exist_ok=True)
|
||||
logger.info(f"Renaming Recipe Directory: {original_slug} -> {self.recipe.slug}")
|
||||
except FileNotFoundError:
|
||||
logger.error(f"Recipe Directory not Found: {original_slug}")
|
||||
|
||||
all_asset_files = [x.file_name for x in self.recipe.assets]
|
||||
|
||||
for file in self.recipe.asset_dir.iterdir():
|
||||
file: Path
|
||||
if file.is_dir():
|
||||
continue
|
||||
if file.name not in all_asset_files:
|
||||
file.unlink()
|
||||
|
||||
def _delete_assets(self) -> None:
|
||||
recipe_dir = self.recipe.directory
|
||||
rmtree(recipe_dir, ignore_errors=True)
|
||||
logger.info(f"Recipe Directory Removed: {self.recipe.slug}")
|
||||
|
||||
@@ -5,6 +5,4 @@ Cron = collections.namedtuple("Cron", "hours minutes")
|
||||
|
||||
def cron_parser(time_str: str) -> Cron:
|
||||
time = time_str.split(":")
|
||||
cron = Cron(hours=int(time[0]), minutes=int(time[1]))
|
||||
|
||||
return cron
|
||||
return Cron(hours=int(time[0]), minutes=int(time[1]))
|
||||
|
||||
Reference in New Issue
Block a user