Feature/recipe instructions improvements (#785)

* feat(frontend):  split paragraph by 1. 1) or 1: regex matches

* feat(frontend):  Update frontend to support ingredient To step refs

* feat(backend):  Update backend to support ingredient to step refs

* fix title editor

* move about info to site-settings

* update change-log

Co-authored-by: Hayden K <hay-kot@pm.me>
This commit is contained in:
Hayden
2021-11-05 15:48:10 -08:00
committed by GitHub
parent 9f8c61a75a
commit 5cb4a1ade0
22 changed files with 621 additions and 210 deletions

View File

@@ -92,7 +92,7 @@ def handle_one_to_many_list(session: Session, get_attr, relation_cls, all_elemen
updated_elems.append(existing_elem)
new_elems = [safe_call(relation_cls, elem) for elem in elems_to_create]
new_elems = [safe_call(relation_cls, elem, session=session) for elem in elems_to_create]
return new_elems + updated_elems
@@ -159,7 +159,7 @@ def auto_init(): # sourcery no-metrics
setattr(self, key, instances)
elif relation_dir == ONETOMANY:
instance = safe_call(relation_cls, val)
instance = safe_call(relation_cls, val, session=session)
setattr(self, key, instance)
elif relation_dir == MANYTOONE and not use_list:

View File

@@ -0,0 +1,39 @@
import uuid
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.types import CHAR, TypeDecorator
class GUID(TypeDecorator):
"""Platform-independent GUID type.
Uses PostgreSQL's UUID type, otherwise uses
CHAR(32), storing as stringified hex values.
"""
impl = CHAR
def load_dialect_impl(self, dialect):
if dialect.name == "postgresql":
return dialect.type_descriptor(UUID())
else:
return dialect.type_descriptor(CHAR(32))
def process_bind_param(self, value, dialect):
if value is None:
return value
elif dialect.name == "postgresql":
return str(value)
else:
if not isinstance(value, uuid.UUID):
return "%.32x" % uuid.UUID(value).int
else:
# hexstring
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

View File

@@ -28,12 +28,16 @@ def get_valid_call(func: Callable, args_dict) -> dict:
return {k: v for k, v in args_dict.items() if k in valid_args}
def safe_call(func, dict) -> Any:
def safe_call(func, dict_args, **kwargs) -> Any:
"""
Safely calls the supplied function with the supplied dictionary of arguments.
by removing any invalid arguments.
"""
if kwargs:
dict_args.update(kwargs)
try:
return func(**get_valid_call(func, dict))
return func(**get_valid_call(func, dict_args))
except TypeError:
return func(**dict)
return func(**dict_args)

View File

@@ -3,6 +3,7 @@ from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, orm
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
from .._model_utils import auto_init
from .._model_utils.guid import GUID
class IngredientUnitModel(SqlAlchemyBase, BaseMixins):
@@ -48,6 +49,8 @@ class RecipeIngredient(SqlAlchemyBase, BaseMixins):
food = orm.relationship(IngredientFoodModel, uselist=False)
quantity = Column(Integer)
reference_id = Column(GUID()) # Reference Links
# Extras
@auto_init()

View File

@@ -1,6 +1,18 @@
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy import Column, ForeignKey, Integer, String, orm
from mealie.db.models._model_base import SqlAlchemyBase
from .._model_base import BaseMixins, SqlAlchemyBase
from .._model_utils import auto_init
from .._model_utils.guid import GUID
class RecipeIngredientRefLink(SqlAlchemyBase, BaseMixins):
__tablename__ = "recipe_ingredient_ref_link"
instruction_id = Column(Integer, ForeignKey("recipe_instructions.id"))
reference_id = Column(GUID())
@auto_init()
def __init__(self, **_) -> None:
pass
class RecipeInstruction(SqlAlchemyBase):
@@ -11,3 +23,9 @@ class RecipeInstruction(SqlAlchemyBase):
type = Column(String, default="")
title = Column(String)
text = Column(String)
ingredient_references = orm.relationship("RecipeIngredientRefLink", cascade="all, delete-orphan")
@auto_init()
def __init__(self, **_) -> None:
pass

View File

@@ -92,7 +92,6 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
"notes",
"nutrition",
"recipe_ingredient",
"recipe_instructions",
"settings",
"tools",
}
@@ -111,7 +110,6 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
notes: list[dict] = None,
nutrition: dict = None,
recipe_ingredient: list[str] = None,
recipe_instructions: list[dict] = None,
settings: dict = None,
tools: list[str] = None,
**_,
@@ -120,10 +118,10 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
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
]
# 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()