mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-02-12 10:53:12 -05:00
Feature/restore-recipe-functionality (#810)
* feat(frontend): ✨ add back support for assets * feat(backend): ✨ add back support for assets * feat(frontend): ✨ add support for recipe tools * feat(backend): ✨ add support for recipe tools * feat(frontend): ✨ add onHand support for recipe toosl * feat(backend): ✨ add onHand support for backend * refactor(frontend): ♻️ move items to recipe folder and break apart types * feat(frontend): ✨ add support for recipe comments * feat(backend): ✨ Add support for recipe comments * fix(backend): 💥 disable comments import * fix(frontend): 🐛 fix rendering issue with titles when moving steps * add tools to changelog * fix type errors Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
@@ -13,6 +13,7 @@ from mealie.db.models.recipe.comment import RecipeComment
|
||||
from mealie.db.models.recipe.ingredient import IngredientFoodModel, IngredientUnitModel
|
||||
from mealie.db.models.recipe.recipe import RecipeModel
|
||||
from mealie.db.models.recipe.tag import Tag
|
||||
from mealie.db.models.recipe.tool import Tool
|
||||
from mealie.db.models.server.task import ServerTaskModel
|
||||
from mealie.db.models.sign_up import SignUp
|
||||
from mealie.db.models.users import LongLiveToken, User
|
||||
@@ -24,8 +25,9 @@ from mealie.schema.group.group_preferences import ReadGroupPreferences
|
||||
from mealie.schema.group.invite_token import ReadInviteToken
|
||||
from mealie.schema.group.webhook import ReadWebhook
|
||||
from mealie.schema.meal_plan.new_meal import ReadPlanEntry
|
||||
from mealie.schema.recipe import CommentOut, Recipe, RecipeCategoryResponse, RecipeTagResponse
|
||||
from mealie.schema.recipe import Recipe, RecipeCategoryResponse, RecipeCommentOut, RecipeTagResponse
|
||||
from mealie.schema.recipe.recipe_ingredient import IngredientFood, IngredientUnit
|
||||
from mealie.schema.recipe.recipe_tool import RecipeTool
|
||||
from mealie.schema.server import ServerTask
|
||||
from mealie.schema.user import GroupInDB, LongLiveTokenInDB, PrivateUser, SignUpOut
|
||||
from mealie.schema.user.user_passwords import PrivatePasswordResetToken
|
||||
@@ -78,8 +80,12 @@ class Database:
|
||||
return AccessModel(self.session, pk_id, IngredientUnitModel, IngredientUnit)
|
||||
|
||||
@cached_property
|
||||
def comments(self) -> AccessModel[CommentOut, RecipeComment]:
|
||||
return AccessModel(self.session, pk_id, RecipeComment, CommentOut)
|
||||
def tools(self) -> AccessModel[RecipeTool, Tool]:
|
||||
return AccessModel(self.session, pk_id, Tool, RecipeTool)
|
||||
|
||||
@cached_property
|
||||
def comments(self) -> AccessModel[RecipeCommentOut, RecipeComment]:
|
||||
return AccessModel(self.session, pk_id, RecipeComment, RecipeCommentOut)
|
||||
|
||||
@cached_property
|
||||
def categories(self) -> CategoryDataAccessModel:
|
||||
|
||||
@@ -11,6 +11,7 @@ class GUID(TypeDecorator):
|
||||
"""
|
||||
|
||||
impl = CHAR
|
||||
cache_ok = True
|
||||
|
||||
def load_dialect_impl(self, dialect):
|
||||
if dialect.name == "postgresql":
|
||||
@@ -31,9 +32,6 @@ class GUID(TypeDecorator):
|
||||
return "%.32x" % value.int
|
||||
|
||||
def process_result_value(self, value, dialect):
|
||||
if value is None:
|
||||
return value
|
||||
else:
|
||||
if not isinstance(value, uuid.UUID):
|
||||
value = uuid.UUID(value)
|
||||
return value
|
||||
if value is not None and not isinstance(value, uuid.UUID):
|
||||
value = uuid.UUID(value)
|
||||
return value
|
||||
|
||||
@@ -7,7 +7,7 @@ class ApiExtras(SqlAlchemyBase):
|
||||
__tablename__ = "api_extras"
|
||||
id = sa.Column(sa.Integer, primary_key=True)
|
||||
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
|
||||
key_name = sa.Column(sa.String, unique=True)
|
||||
key_name = sa.Column(sa.String)
|
||||
value = sa.Column(sa.String)
|
||||
|
||||
def __init__(self, key, value) -> None:
|
||||
|
||||
@@ -1,37 +1,28 @@
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, orm
|
||||
from sqlalchemy import Column, ForeignKey, Integer, String, orm
|
||||
|
||||
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||
from mealie.db.models.recipe.recipe import RecipeModel
|
||||
from mealie.db.models.users import User
|
||||
|
||||
|
||||
def generate_uuid():
|
||||
return str(uuid4())
|
||||
from mealie.db.models._model_utils import auto_init
|
||||
from mealie.db.models._model_utils.guid import GUID
|
||||
|
||||
|
||||
class RecipeComment(SqlAlchemyBase, BaseMixins):
|
||||
__tablename__ = "recipe_comments"
|
||||
id = Column(Integer, primary_key=True)
|
||||
uuid = Column(String, unique=True, nullable=False, default=generate_uuid)
|
||||
parent_id = Column(Integer, ForeignKey("recipes.id"), nullable=False)
|
||||
recipe = orm.relationship("RecipeModel", back_populates="comments")
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
user = orm.relationship("User", back_populates="comments", single_parent=True, foreign_keys=[user_id])
|
||||
date_added = Column(DateTime, default=datetime.now)
|
||||
id = Column(GUID(), primary_key=True, default=uuid4)
|
||||
text = Column(String)
|
||||
|
||||
def __init__(self, recipe_slug, user, text, session, date_added=None, **_) -> None:
|
||||
self.text = text
|
||||
self.recipe = RecipeModel.get_ref(session, recipe_slug, "slug")
|
||||
self.date_added = date_added or datetime.now()
|
||||
# Recipe Link
|
||||
recipe_id = Column(Integer, ForeignKey("recipes.id"), nullable=False)
|
||||
recipe = orm.relationship("RecipeModel", back_populates="comments")
|
||||
|
||||
if isinstance(user, dict):
|
||||
user = user.get("id")
|
||||
# User Link
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
user = orm.relationship("User", back_populates="comments", single_parent=True, foreign_keys=[user_id])
|
||||
|
||||
self.user = User.get_ref(session, user)
|
||||
@auto_init()
|
||||
def __init__(self, **_) -> None:
|
||||
pass
|
||||
|
||||
def update(self, text, **_) -> None:
|
||||
self.text = text
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from uuid import uuid4
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Integer, String, orm
|
||||
|
||||
from .._model_base import BaseMixins, SqlAlchemyBase
|
||||
@@ -17,7 +19,7 @@ class RecipeIngredientRefLink(SqlAlchemyBase, BaseMixins):
|
||||
|
||||
class RecipeInstruction(SqlAlchemyBase):
|
||||
__tablename__ = "recipe_instructions"
|
||||
id = Column(Integer, primary_key=True)
|
||||
id = Column(GUID(), primary_key=True, default=uuid4)
|
||||
parent_id = Column(Integer, ForeignKey("recipes.id"))
|
||||
position = Column(Integer)
|
||||
type = Column(String, default="")
|
||||
|
||||
@@ -18,7 +18,22 @@ from .note import Note
|
||||
from .nutrition import Nutrition
|
||||
from .settings import RecipeSettings
|
||||
from .tag import Tag, recipes2tags
|
||||
from .tool import Tool
|
||||
from .tool import recipes_to_tools
|
||||
|
||||
|
||||
# Decorator function to unpack the extras into a dict
|
||||
def recipe_extras(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
extras = kwargs.pop("extras")
|
||||
|
||||
if extras is None:
|
||||
extras = []
|
||||
|
||||
extras = [{"key": key, "value": value} for key, value in extras.items()]
|
||||
|
||||
return func(*args, extras=extras, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||
@@ -52,10 +67,10 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||
recipe_yield = sa.Column(sa.String)
|
||||
recipeCuisine = sa.Column(sa.String)
|
||||
|
||||
tools: list[Tool] = orm.relationship("Tool", cascade="all, delete-orphan")
|
||||
assets: list[RecipeAsset] = orm.relationship("RecipeAsset", cascade="all, delete-orphan")
|
||||
assets = orm.relationship("RecipeAsset", cascade="all, delete-orphan")
|
||||
nutrition: Nutrition = orm.relationship("Nutrition", uselist=False, cascade="all, delete-orphan")
|
||||
recipe_category: list = orm.relationship("Category", secondary=recipes2categories, back_populates="recipes")
|
||||
tools = orm.relationship("Tool", secondary=recipes_to_tools, back_populates="recipes")
|
||||
|
||||
recipe_ingredient: list[RecipeIngredient] = orm.relationship(
|
||||
"RecipeIngredient",
|
||||
@@ -88,45 +103,36 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||
get_attr = "slug"
|
||||
exclude = {
|
||||
"assets",
|
||||
"extras",
|
||||
"notes",
|
||||
"nutrition",
|
||||
"recipe_ingredient",
|
||||
"settings",
|
||||
"tools",
|
||||
}
|
||||
|
||||
@validates("name")
|
||||
def validate_name(self, key, name):
|
||||
def validate_name(self, _, name):
|
||||
assert name != ""
|
||||
return name
|
||||
|
||||
@recipe_extras
|
||||
@auto_init()
|
||||
def __init__(
|
||||
self,
|
||||
session,
|
||||
assets: list = None,
|
||||
extras: dict = None,
|
||||
notes: list[dict] = None,
|
||||
nutrition: dict = None,
|
||||
recipe_ingredient: list[str] = None,
|
||||
settings: dict = None,
|
||||
tools: list[str] = None,
|
||||
**_,
|
||||
) -> None:
|
||||
self.nutrition = Nutrition(**nutrition) if nutrition else Nutrition()
|
||||
self.tools = [Tool(tool=x) for x in tools] if tools else []
|
||||
self.recipe_ingredient = [RecipeIngredient(**ingr, session=session) for ingr in recipe_ingredient]
|
||||
self.assets = [RecipeAsset(**a) for a in assets]
|
||||
# self.recipe_instructions = [
|
||||
# RecipeInstruction(text=instruc.get("text"), title=instruc.get("title"), type=instruc.get("@type", None))
|
||||
# for instruc in recipe_instructions
|
||||
# ]
|
||||
|
||||
# Mealie Specific
|
||||
self.settings = RecipeSettings(**settings) if settings else RecipeSettings()
|
||||
self.notes = [Note(**note) for note in notes]
|
||||
self.extras = [ApiExtras(key=key, value=value) for key, value in extras.items()]
|
||||
|
||||
# Time Stampes
|
||||
self.date_updated = datetime.datetime.now()
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, Table, orm
|
||||
|
||||
from mealie.db.models._model_base import SqlAlchemyBase
|
||||
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||
from mealie.db.models._model_utils import auto_init
|
||||
|
||||
recipes_to_tools = Table(
|
||||
"recipes_to_tools",
|
||||
SqlAlchemyBase.metadata,
|
||||
Column("recipe_id", Integer, ForeignKey("recipes.id")),
|
||||
Column("tool_id", Integer, ForeignKey("tools.id")),
|
||||
)
|
||||
|
||||
|
||||
class Tool(SqlAlchemyBase):
|
||||
class Tool(SqlAlchemyBase, BaseMixins):
|
||||
__tablename__ = "tools"
|
||||
id = sa.Column(sa.Integer, primary_key=True)
|
||||
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
|
||||
tool = sa.Column(sa.String)
|
||||
name = Column(String, index=True, unique=True, nullable=False)
|
||||
on_hand = Column(Boolean, default=False)
|
||||
recipes = orm.relationship("RecipeModel", secondary=recipes_to_tools, back_populates="tools")
|
||||
|
||||
def __init__(self, tool) -> None:
|
||||
self.tool = tool
|
||||
@auto_init()
|
||||
def __init__(self, name, on_hand, **_) -> None:
|
||||
self.on_hand = on_hand
|
||||
self.name = name
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from . import admin, app, auth, categories, groups, parser, recipe, shopping_lists, tags, unit_and_foods, users
|
||||
from . import (
|
||||
admin,
|
||||
app,
|
||||
auth,
|
||||
categories,
|
||||
comments,
|
||||
groups,
|
||||
parser,
|
||||
recipe,
|
||||
shopping_lists,
|
||||
tags,
|
||||
tools,
|
||||
unit_and_foods,
|
||||
users,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api")
|
||||
|
||||
@@ -9,8 +23,10 @@ router.include_router(auth.router)
|
||||
router.include_router(users.router)
|
||||
router.include_router(groups.router)
|
||||
router.include_router(recipe.router)
|
||||
router.include_router(comments.router)
|
||||
router.include_router(parser.router)
|
||||
router.include_router(unit_and_foods.router)
|
||||
router.include_router(tools.router)
|
||||
router.include_router(categories.router)
|
||||
router.include_router(tags.router)
|
||||
router.include_router(shopping_lists.router)
|
||||
|
||||
8
mealie/routes/comments/__init__.py
Normal file
8
mealie/routes/comments/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from mealie.services._base_http_service.router_factory import RouterFactory
|
||||
from mealie.services.recipe.recipe_comments_service import RecipeCommentsService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
router.include_router(RouterFactory(RecipeCommentsService, prefix="/comments", tags=["Recipe: Comments"]))
|
||||
@@ -1,58 +1,20 @@
|
||||
from http.client import HTTPException
|
||||
|
||||
from fastapi import Depends, status
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
from mealie.core.dependencies import get_current_user
|
||||
from mealie.db.database import get_database
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.routers import UserAPIRouter
|
||||
from mealie.schema.recipe import CommentOut, CreateComment, SaveComment
|
||||
from mealie.schema.user import PrivateUser
|
||||
from mealie.schema.recipe.recipe_comments import RecipeCommentOut
|
||||
|
||||
router = UserAPIRouter()
|
||||
|
||||
|
||||
@router.post("/{slug}/comments")
|
||||
async def create_comment(
|
||||
@router.get("/{slug}/comments", response_model=list[RecipeCommentOut])
|
||||
async def get_recipe_comments(
|
||||
slug: str,
|
||||
new_comment: CreateComment,
|
||||
session: Session = Depends(generate_session),
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
):
|
||||
"""Create comment in the Database"""
|
||||
"""Get all comments for a recipe"""
|
||||
db = get_database(session)
|
||||
|
||||
new_comment = SaveComment(user=current_user.id, text=new_comment.text, recipe_slug=slug)
|
||||
return db.comments.create(new_comment)
|
||||
|
||||
|
||||
@router.put("/{slug}/comments/{id}")
|
||||
async def update_comment(
|
||||
id: int,
|
||||
new_comment: CreateComment,
|
||||
session: Session = Depends(generate_session),
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
):
|
||||
"""Update comment in the Database"""
|
||||
db = get_database(session)
|
||||
old_comment: CommentOut = db.comments.get(id)
|
||||
|
||||
if current_user.id != old_comment.user.id:
|
||||
raise HTTPException(status.HTTP_403_FORBIDDEN)
|
||||
|
||||
return db.comments.update(id, new_comment)
|
||||
|
||||
|
||||
@router.delete("/{slug}/comments/{id}")
|
||||
async def delete_comment(
|
||||
id: int, session: Session = Depends(generate_session), current_user: PrivateUser = Depends(get_current_user)
|
||||
):
|
||||
"""Delete comment from the Database"""
|
||||
db = get_database(session)
|
||||
comment: CommentOut = db.comments.get(id)
|
||||
if current_user.id == comment.user.id or current_user.admin:
|
||||
db.comments.delete(id)
|
||||
return
|
||||
|
||||
raise HTTPException(status.HTTP_403_FORBIDDEN)
|
||||
recipe = db.recipes.get_one(slug)
|
||||
return db.comments.multi_query({"recipe_id": recipe.id})
|
||||
|
||||
8
mealie/routes/tools/__init__.py
Normal file
8
mealie/routes/tools/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from mealie.services._base_http_service.router_factory import RouterFactory
|
||||
from mealie.services.recipe.recipe_tool_service import RecipeToolService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
router.include_router(RouterFactory(RecipeToolService, prefix="/tools", tags=["Recipes: Tools"]))
|
||||
@@ -11,12 +11,13 @@ from mealie.core.config import get_app_dirs
|
||||
from mealie.db.models.recipe.recipe import RecipeModel
|
||||
|
||||
from .recipe_asset import RecipeAsset
|
||||
from .recipe_comments import CommentOut
|
||||
from .recipe_comments import RecipeCommentOut
|
||||
from .recipe_ingredient import RecipeIngredient
|
||||
from .recipe_notes import RecipeNote
|
||||
from .recipe_nutrition import Nutrition
|
||||
from .recipe_settings import RecipeSettings
|
||||
from .recipe_step import RecipeStep
|
||||
from .recipe_tool import RecipeTool
|
||||
|
||||
app_dirs = get_app_dirs()
|
||||
|
||||
@@ -101,7 +102,7 @@ class Recipe(RecipeSummary):
|
||||
recipe_ingredient: Optional[list[RecipeIngredient]] = []
|
||||
recipe_instructions: Optional[list[RecipeStep]] = []
|
||||
nutrition: Optional[Nutrition]
|
||||
tools: Optional[list[str]] = []
|
||||
tools: list[RecipeTool] = []
|
||||
|
||||
# Mealie Specific
|
||||
settings: Optional[RecipeSettings] = RecipeSettings()
|
||||
@@ -109,7 +110,7 @@ class Recipe(RecipeSummary):
|
||||
notes: Optional[list[RecipeNote]] = []
|
||||
extras: Optional[dict] = {}
|
||||
|
||||
comments: Optional[list[CommentOut]] = []
|
||||
comments: Optional[list[RecipeCommentOut]] = []
|
||||
|
||||
@staticmethod
|
||||
def directory_from_slug(slug) -> Path:
|
||||
@@ -143,7 +144,6 @@ class Recipe(RecipeSummary):
|
||||
# "recipe_ingredient": [x.note for x in name_orm.recipe_ingredient],
|
||||
# "recipe_category": [x.name for x in name_orm.recipe_category],
|
||||
# "tags": [x.name for x in name_orm.tags],
|
||||
"tools": [x.tool for x in name_orm.tools],
|
||||
"extras": {x.key_name: x.value for x in name_orm.extras},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi_camelcase import CamelModel
|
||||
from pydantic.utils import GetterDict
|
||||
|
||||
|
||||
class UserBase(CamelModel):
|
||||
@@ -14,31 +14,27 @@ class UserBase(CamelModel):
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class CreateComment(CamelModel):
|
||||
class RecipeCommentCreate(CamelModel):
|
||||
recipe_id: int
|
||||
text: str
|
||||
|
||||
|
||||
class SaveComment(CreateComment):
|
||||
recipe_slug: str
|
||||
user: int
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
class RecipeCommentSave(RecipeCommentCreate):
|
||||
user_id: int
|
||||
|
||||
|
||||
class CommentOut(CreateComment):
|
||||
id: int
|
||||
uuid: str
|
||||
recipe_slug: str
|
||||
date_added: datetime
|
||||
class RecipeCommentUpdate(CamelModel):
|
||||
id: UUID
|
||||
text: str
|
||||
|
||||
|
||||
class RecipeCommentOut(RecipeCommentCreate):
|
||||
id: UUID
|
||||
recipe_id: int
|
||||
created_at: datetime
|
||||
update_at: datetime
|
||||
user_id: int
|
||||
user: UserBase
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
@classmethod
|
||||
def getter_dict(_cls, name_orm):
|
||||
return {
|
||||
**GetterDict(name_orm),
|
||||
"recipe_slug": name_orm.recipe.slug,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from fastapi_camelcase import CamelModel
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class IngredientReferences(CamelModel):
|
||||
@@ -16,6 +17,7 @@ class IngredientReferences(CamelModel):
|
||||
|
||||
|
||||
class RecipeStep(CamelModel):
|
||||
id: Optional[UUID] = Field(default_factory=uuid4)
|
||||
title: Optional[str] = ""
|
||||
text: str
|
||||
ingredient_references: list[IngredientReferences] = []
|
||||
|
||||
13
mealie/schema/recipe/recipe_tool.py
Normal file
13
mealie/schema/recipe/recipe_tool.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from fastapi_camelcase import CamelModel
|
||||
|
||||
|
||||
class RecipeToolCreate(CamelModel):
|
||||
name: str
|
||||
on_hand: bool = False
|
||||
|
||||
|
||||
class RecipeTool(RecipeToolCreate):
|
||||
id: int
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
@@ -8,15 +8,15 @@ from pydantic.main import BaseModel
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
from mealie.core.config import get_app_dirs
|
||||
|
||||
app_dirs = get_app_dirs()
|
||||
from mealie.db.database import get_database
|
||||
from mealie.schema.admin import CommentImport, GroupImport, NotificationImport, RecipeImport, UserImport
|
||||
from mealie.schema.events import EventNotificationIn
|
||||
from mealie.schema.recipe import CommentOut, Recipe
|
||||
from mealie.schema.recipe import Recipe, RecipeCommentOut
|
||||
from mealie.schema.user import PrivateUser, UpdateGroup
|
||||
from mealie.services.image import minify
|
||||
|
||||
app_dirs = get_app_dirs()
|
||||
|
||||
|
||||
class ImportDatabase:
|
||||
def __init__(
|
||||
@@ -57,7 +57,10 @@ class ImportDatabase:
|
||||
successful_imports = {}
|
||||
|
||||
recipes = ImportDatabase.read_models_file(
|
||||
file_path=recipe_dir, model=Recipe, single_file=False, migrate=ImportDatabase._recipe_migration
|
||||
file_path=recipe_dir,
|
||||
model=Recipe,
|
||||
single_file=False,
|
||||
migrate=ImportDatabase._recipe_migration,
|
||||
)
|
||||
|
||||
for recipe in recipes:
|
||||
@@ -76,7 +79,7 @@ class ImportDatabase:
|
||||
)
|
||||
|
||||
if import_status.status:
|
||||
successful_imports.update({recipe.slug: recipe})
|
||||
successful_imports[recipe.slug] = recipe
|
||||
|
||||
imports.append(import_status)
|
||||
|
||||
@@ -90,10 +93,10 @@ class ImportDatabase:
|
||||
if not comment_dir.exists():
|
||||
return
|
||||
|
||||
comments = ImportDatabase.read_models_file(file_path=comment_dir, model=CommentOut)
|
||||
comments = ImportDatabase.read_models_file(file_path=comment_dir, model=RecipeCommentOut)
|
||||
|
||||
for comment in comments:
|
||||
comment: CommentOut
|
||||
comment: RecipeCommentOut
|
||||
|
||||
self.import_model(
|
||||
db_table=self.db.comments,
|
||||
@@ -130,6 +133,8 @@ class ImportDatabase:
|
||||
if type(recipe_dict["extras"]) == list:
|
||||
recipe_dict["extras"] = {}
|
||||
|
||||
recipe_dict["comments"] = []
|
||||
|
||||
return recipe_dict
|
||||
|
||||
def _import_images(self, successful_imports: list[Recipe]):
|
||||
@@ -328,8 +333,8 @@ def import_database(
|
||||
if import_notifications:
|
||||
notification_report = import_session.import_notifications()
|
||||
|
||||
if import_recipes:
|
||||
import_session.import_comments()
|
||||
# if import_recipes:
|
||||
# import_session.import_comments()
|
||||
|
||||
import_session.clean_up()
|
||||
|
||||
|
||||
52
mealie/services/recipe/recipe_comments_service.py
Normal file
52
mealie/services/recipe/recipe_comments_service.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import cached_property
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import HTTPException
|
||||
|
||||
from mealie.schema.recipe.recipe_comments import (
|
||||
RecipeCommentCreate,
|
||||
RecipeCommentOut,
|
||||
RecipeCommentSave,
|
||||
RecipeCommentUpdate,
|
||||
)
|
||||
from mealie.services._base_http_service.crud_http_mixins import CrudHttpMixins
|
||||
from mealie.services._base_http_service.http_services import UserHttpService
|
||||
from mealie.services.events import create_recipe_event
|
||||
|
||||
|
||||
class RecipeCommentsService(
|
||||
CrudHttpMixins[RecipeCommentOut, RecipeCommentCreate, RecipeCommentCreate],
|
||||
UserHttpService[UUID, RecipeCommentOut],
|
||||
):
|
||||
event_func = create_recipe_event
|
||||
_restrict_by_group = False
|
||||
_schema = RecipeCommentOut
|
||||
|
||||
@cached_property
|
||||
def dal(self):
|
||||
return self.db.comments
|
||||
|
||||
def _check_comment_belongs_to_user(self) -> None:
|
||||
if self.item.user_id != self.user.id and not self.user.admin:
|
||||
raise HTTPException(detail="Comment does not belong to user")
|
||||
|
||||
def populate_item(self, id: UUID) -> RecipeCommentOut:
|
||||
self.item = self.dal.get_one(id)
|
||||
return self.item
|
||||
|
||||
def get_all(self) -> list[RecipeCommentOut]:
|
||||
return self.dal.get_all()
|
||||
|
||||
def create_one(self, data: RecipeCommentCreate) -> RecipeCommentOut:
|
||||
save_data = RecipeCommentSave(text=data.text, user_id=self.user.id, recipe_id=data.recipe_id)
|
||||
return self._create_one(save_data)
|
||||
|
||||
def update_one(self, data: RecipeCommentUpdate, item_id: UUID = None) -> RecipeCommentOut:
|
||||
self._check_comment_belongs_to_user()
|
||||
return self._update_one(data, item_id)
|
||||
|
||||
def delete_one(self, item_id: UUID = None) -> RecipeCommentOut:
|
||||
self._check_comment_belongs_to_user()
|
||||
return self._delete_one(item_id)
|
||||
37
mealie/services/recipe/recipe_tool_service.py
Normal file
37
mealie/services/recipe/recipe_tool_service.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import cached_property
|
||||
|
||||
from mealie.schema.recipe.recipe_tool import RecipeTool, RecipeToolCreate
|
||||
from mealie.services._base_http_service.crud_http_mixins import CrudHttpMixins
|
||||
from mealie.services._base_http_service.http_services import UserHttpService
|
||||
from mealie.services.events import create_recipe_event
|
||||
|
||||
|
||||
class RecipeToolService(
|
||||
CrudHttpMixins[RecipeTool, RecipeToolCreate, RecipeToolCreate],
|
||||
UserHttpService[int, RecipeTool],
|
||||
):
|
||||
event_func = create_recipe_event
|
||||
_restrict_by_group = False
|
||||
_schema = RecipeTool
|
||||
|
||||
@cached_property
|
||||
def dal(self):
|
||||
return self.db.tools
|
||||
|
||||
def populate_item(self, id: int) -> RecipeTool:
|
||||
self.item = self.dal.get_one(id)
|
||||
return self.item
|
||||
|
||||
def get_all(self) -> list[RecipeTool]:
|
||||
return self.dal.get_all()
|
||||
|
||||
def create_one(self, data: RecipeToolCreate) -> RecipeTool:
|
||||
return self._create_one(data)
|
||||
|
||||
def update_one(self, data: RecipeTool, item_id: int = None) -> RecipeTool:
|
||||
return self._update_one(data, item_id)
|
||||
|
||||
def delete_one(self, id: int = None) -> RecipeTool:
|
||||
return self._delete_one(id)
|
||||
Reference in New Issue
Block a user