mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-05 21:45:25 +02:00
feat: Move "on hand" and "last made" to household (#4616)
Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
parent
e565b919df
commit
e9892aba89
53 changed files with 1618 additions and 400 deletions
|
@ -1,6 +1,13 @@
|
|||
from datetime import datetime, timezone
|
||||
from uuid import UUID
|
||||
|
||||
from dateutil.parser import parse as parse_dt
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from mealie.db.models.household import HouseholdToRecipe
|
||||
from mealie.schema.recipe.recipe import Recipe
|
||||
from tests.utils import api_routes
|
||||
from tests.utils.factories import random_string
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
|
@ -18,3 +25,61 @@ def test_get_household_members(api_client: TestClient, user_tuple: list[TestUser
|
|||
assert str(usr_1.user_id) in all_ids
|
||||
assert str(usr_2.user_id) in all_ids
|
||||
assert str(h2_user.user_id) not in all_ids
|
||||
|
||||
|
||||
def test_get_household_recipe_default(api_client: TestClient, unique_user: TestUser):
|
||||
recipe = unique_user.repos.recipes.create(
|
||||
Recipe(
|
||||
user_id=unique_user.user_id,
|
||||
group_id=UUID(unique_user.group_id),
|
||||
name=random_string(),
|
||||
)
|
||||
)
|
||||
response = api_client.get(api_routes.households_self_recipes_recipe_slug(recipe.slug), headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["recipeId"] == str(recipe.id)
|
||||
assert response.json()["lastMade"] is None
|
||||
|
||||
|
||||
def test_get_household_recipe(api_client: TestClient, unique_user: TestUser, h2_user: TestUser):
|
||||
dt_now = datetime.now(tz=timezone.utc)
|
||||
recipe = unique_user.repos.recipes.create(
|
||||
Recipe(
|
||||
user_id=unique_user.user_id,
|
||||
group_id=UUID(unique_user.group_id),
|
||||
name=random_string(),
|
||||
)
|
||||
)
|
||||
|
||||
session = unique_user.repos.session
|
||||
session.add(
|
||||
HouseholdToRecipe(
|
||||
session=session,
|
||||
household_id=UUID(unique_user.household_id),
|
||||
recipe_id=recipe.id,
|
||||
last_made=dt_now,
|
||||
)
|
||||
)
|
||||
session.commit()
|
||||
|
||||
response = api_client.get(api_routes.households_self_recipes_recipe_slug(recipe.slug), headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
|
||||
data = response.json()
|
||||
assert data["recipeId"] == str(recipe.id)
|
||||
assert data["lastMade"]
|
||||
assert parse_dt(data["lastMade"]) == dt_now
|
||||
|
||||
response = api_client.get(api_routes.households_self_recipes_recipe_slug(recipe.slug), headers=h2_user.token)
|
||||
assert response.status_code == 200
|
||||
|
||||
h2_data = response.json()
|
||||
assert h2_data["recipeId"] == str(recipe.id)
|
||||
assert h2_data["lastMade"] is None
|
||||
|
||||
|
||||
def test_get_household_recipe_invalid_recipe(api_client: TestClient, unique_user: TestUser):
|
||||
response = api_client.get(
|
||||
api_routes.households_self_recipes_recipe_slug(random_string()), headers=unique_user.token
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from datetime import UTC, datetime
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import pytest
|
||||
from dateutil.parser import parse as parse_dt
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from mealie.schema.cookbook.cookbook import SaveCookBook
|
||||
|
@ -233,28 +234,50 @@ def test_user_can_update_last_made_on_other_household(
|
|||
assert response.status_code == 201
|
||||
h2_recipe = h2_user.repos.recipes.get_one(response.json())
|
||||
assert h2_recipe and h2_recipe.id
|
||||
h2_recipe_id = h2_recipe.id
|
||||
h2_recipe_slug = h2_recipe.slug
|
||||
|
||||
response = api_client.get(api_routes.recipes_slug(h2_recipe_slug), headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
recipe = response.json()
|
||||
assert recipe["id"] == str(h2_recipe_id)
|
||||
old_last_made = recipe["lastMade"]
|
||||
dt_1 = datetime.now(tz=UTC)
|
||||
dt_2 = dt_1 + timedelta(days=2)
|
||||
|
||||
now = datetime.now(UTC).isoformat().replace("+00:00", "Z")
|
||||
# set last made for unique_user and make sure it only updates globally and for unique_user
|
||||
response = api_client.patch(
|
||||
api_routes.recipes_slug_last_made(h2_recipe_slug), json={"timestamp": now}, headers=unique_user.token
|
||||
api_routes.recipes_slug_last_made(h2_recipe.slug),
|
||||
json={"timestamp": dt_2.isoformat()},
|
||||
headers=unique_user.token,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
# confirm the last made date was updated
|
||||
response = api_client.get(api_routes.recipes_slug(h2_recipe_slug), headers=unique_user.token)
|
||||
response = api_client.get(api_routes.households_self_recipes_recipe_slug(h2_recipe_slug), headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
recipe = response.json()
|
||||
assert recipe["id"] == str(h2_recipe_id)
|
||||
new_last_made = recipe["lastMade"]
|
||||
assert new_last_made == now != old_last_made
|
||||
assert (last_made_json := response.json()["lastMade"])
|
||||
assert parse_dt(last_made_json) == dt_2
|
||||
|
||||
response = api_client.get(api_routes.households_self_recipes_recipe_slug(h2_recipe_slug), headers=h2_user.token)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["lastMade"] is None
|
||||
|
||||
recipe = h2_user.repos.recipes.get_one(h2_recipe_slug)
|
||||
assert recipe
|
||||
assert recipe.last_made == dt_2
|
||||
|
||||
# set last made for h2_user and make sure it only updates globally and for h2_user
|
||||
response = api_client.patch(
|
||||
api_routes.recipes_slug_last_made(h2_recipe.slug), json={"timestamp": dt_1.isoformat()}, headers=h2_user.token
|
||||
)
|
||||
assert response.status_code == 200
|
||||
response = api_client.get(api_routes.households_self_recipes_recipe_slug(h2_recipe_slug), headers=h2_user.token)
|
||||
assert response.status_code == 200
|
||||
assert (last_made_json := response.json()["lastMade"])
|
||||
assert parse_dt(last_made_json) == dt_1
|
||||
|
||||
response = api_client.get(api_routes.households_self_recipes_recipe_slug(h2_recipe_slug), headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
assert (last_made_json := response.json()["lastMade"])
|
||||
assert parse_dt(last_made_json) == dt_2
|
||||
|
||||
# this shouldn't have updated since dt_2 is newer than dt_1
|
||||
recipe = h2_user.repos.recipes.get_one(h2_recipe_slug)
|
||||
assert recipe
|
||||
assert recipe.last_made == dt_2
|
||||
|
||||
|
||||
def test_cookbook_recipes_includes_all_households(api_client: TestClient, unique_user: TestUser, h2_user: TestUser):
|
||||
|
|
|
@ -14,14 +14,32 @@ from tests.utils.fixture_schemas import TestUser
|
|||
|
||||
|
||||
def create_food(user: TestUser, on_hand: bool = False):
|
||||
if on_hand:
|
||||
household = user.repos.households.get_by_slug_or_id(user.household_id)
|
||||
assert household
|
||||
households = [household.slug]
|
||||
else:
|
||||
households = []
|
||||
|
||||
return user.repos.ingredient_foods.create(
|
||||
SaveIngredientFood(id=uuid4(), name=random_string(), group_id=user.group_id, on_hand=on_hand)
|
||||
SaveIngredientFood(
|
||||
id=uuid4(), name=random_string(), group_id=user.group_id, households_with_ingredient_food=households
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def create_tool(user: TestUser, on_hand: bool = False):
|
||||
if on_hand:
|
||||
household = user.repos.households.get_by_slug_or_id(user.household_id)
|
||||
assert household
|
||||
households = [household.slug]
|
||||
else:
|
||||
households = []
|
||||
|
||||
return user.repos.tools.create(
|
||||
RecipeToolSave(id=uuid4(), name=random_string(), group_id=user.group_id, on_hand=on_hand)
|
||||
RecipeToolSave(
|
||||
id=uuid4(), name=random_string(), group_id=user.group_id, on_hand=on_hand, households_with_tool=households
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
@ -568,7 +586,7 @@ def test_include_cross_household_recipes(api_client: TestClient, unique_user: Te
|
|||
try:
|
||||
response = api_client.get(
|
||||
api_routes.recipes_suggestions,
|
||||
params={"maxMissingFoods": 0, "foods": [str(known_food.id)], "includeCrossHousehold": True},
|
||||
params={"maxMissingFoods": 0, "foods": [str(known_food.id)]},
|
||||
headers=h2_user.token,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
@ -579,3 +597,61 @@ def test_include_cross_household_recipes(api_client: TestClient, unique_user: Te
|
|||
finally:
|
||||
unique_user.repos.recipes.delete(recipe.slug)
|
||||
h2_user.repos.recipes.delete(other_recipe.slug)
|
||||
|
||||
|
||||
def test_respect_cross_household_on_hand_food(api_client: TestClient, unique_user: TestUser, h2_user: TestUser):
|
||||
on_hand_food = create_food(unique_user, on_hand=True) # only on-hand for unique_user
|
||||
other_food = create_food(unique_user)
|
||||
|
||||
recipe = create_recipe(unique_user, foods=[on_hand_food, other_food])
|
||||
try:
|
||||
response = api_client.get(
|
||||
api_routes.recipes_suggestions,
|
||||
params={"maxMissingFoods": 0, "foods": [str(other_food.id)]},
|
||||
headers=unique_user.token,
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
assert len(data["items"]) == 1
|
||||
assert data["items"][0]["recipe"]["id"] == str(recipe.id)
|
||||
|
||||
response = api_client.get(
|
||||
api_routes.recipes_suggestions,
|
||||
params={"maxMissingFoods": 0, "foods": [str(other_food.id)]},
|
||||
headers=h2_user.token,
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
assert len(data["items"]) == 0
|
||||
|
||||
finally:
|
||||
unique_user.repos.recipes.delete(recipe.slug)
|
||||
|
||||
|
||||
def test_respect_cross_household_on_hand_tool(api_client: TestClient, unique_user: TestUser, h2_user: TestUser):
|
||||
on_hand_tool = create_tool(unique_user, on_hand=True) # only on-hand for unique_user
|
||||
other_tool = create_tool(unique_user)
|
||||
|
||||
recipe = create_recipe(unique_user, tools=[on_hand_tool, other_tool])
|
||||
try:
|
||||
response = api_client.get(
|
||||
api_routes.recipes_suggestions,
|
||||
params={"maxMissingTools": 0, "tools": [str(other_tool.id)]},
|
||||
headers=unique_user.token,
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
assert len(data["items"]) == 1
|
||||
assert data["items"][0]["recipe"]["id"] == str(recipe.id)
|
||||
|
||||
response = api_client.get(
|
||||
api_routes.recipes_suggestions,
|
||||
params={"maxMissingTools": 0, "tools": [str(other_tool.id)]},
|
||||
headers=h2_user.token,
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
assert len(data["items"]) == 0
|
||||
|
||||
finally:
|
||||
unique_user.repos.recipes.delete(recipe.slug)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue