From 05e13e607877086f04d844e20c1261a5fe6eb4d0 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 11 Mar 2024 00:13:57 +0000 Subject: [PATCH 1/2] account for slugs or recipes when constructing user favorites --- mealie/schema/user/user.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mealie/schema/user/user.py b/mealie/schema/user/user.py index 270e38fd55f..f0a456bf713 100644 --- a/mealie/schema/user/user.py +++ b/mealie/schema/user/user.py @@ -107,7 +107,7 @@ class UserOut(UserBase): group_slug: str tokens: list[LongLiveTokenOut] | None = None cache_key: str - favorite_recipes: Annotated[list[str] | None, Field(validate_default=True)] = [] + favorite_recipes: Annotated[list[str], Field(validate_default=True)] = [] model_config = ConfigDict(from_attributes=True) @property @@ -119,8 +119,18 @@ def loader_options(cls) -> list[LoaderOption]: return [joinedload(User.group), joinedload(User.favorite_recipes), joinedload(User.tokens)] @field_validator("favorite_recipes", mode="before") - def convert_favorite_recipes_to_slugs(cls, v): - return [recipe.slug for recipe in v] if v else v + def convert_favorite_recipes_to_slugs(cls, v: list[str | RecipeSummary] | None): + if not v: + return [] + + slugs: list[str] = [] + for recipe in v: + if isinstance(recipe, str): + slugs.append(recipe) + else: + slugs.append(recipe.slug) + + return slugs class UserPagination(PaginationBase): From 21d57735c9421df0b937903eef8e3634fc965b85 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 11 Mar 2024 00:25:44 +0000 Subject: [PATCH 2/2] added failsafe for bad input data --- mealie/schema/user/user.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mealie/schema/user/user.py b/mealie/schema/user/user.py index f0a456bf713..5803de0867d 100644 --- a/mealie/schema/user/user.py +++ b/mealie/schema/user/user.py @@ -1,6 +1,6 @@ from datetime import datetime, timedelta from pathlib import Path -from typing import Annotated +from typing import Annotated, Any from uuid import UUID from pydantic import UUID4, ConfigDict, Field, StringConstraints, field_validator @@ -119,16 +119,22 @@ def loader_options(cls) -> list[LoaderOption]: return [joinedload(User.group), joinedload(User.favorite_recipes), joinedload(User.tokens)] @field_validator("favorite_recipes", mode="before") - def convert_favorite_recipes_to_slugs(cls, v: list[str | RecipeSummary] | None): + def convert_favorite_recipes_to_slugs(cls, v: Any): if not v: return [] + if not isinstance(v, list): + return v slugs: list[str] = [] for recipe in v: if isinstance(recipe, str): slugs.append(recipe) else: - slugs.append(recipe.slug) + try: + slugs.append(recipe.slug) + except AttributeError: + # this isn't a list of recipes, so we quit early and let Pydantic's typical validation handle it + return v return slugs