mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-02 20:15:24 +02:00
feat: Add Households to Mealie (#3970)
This commit is contained in:
parent
0c29cef17d
commit
eb170cc7e5
315 changed files with 6975 additions and 3577 deletions
|
@ -1,11 +1,14 @@
|
|||
from mealie.repos.repository_factory import AllRepositories
|
||||
from uuid import UUID
|
||||
|
||||
from mealie.schema.recipe.recipe import Recipe
|
||||
from mealie.schema.recipe.recipe_ingredient import RecipeIngredient, SaveIngredientFood
|
||||
from tests.utils.factories import random_string
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
def test_food_merger(database: AllRepositories, unique_user: TestUser):
|
||||
def test_food_merger(unique_user: TestUser):
|
||||
recipe: Recipe | None = None
|
||||
database = unique_user.repos
|
||||
slug1 = random_string(10)
|
||||
|
||||
food_1 = database.ingredient_foods.create(
|
||||
|
@ -25,8 +28,8 @@ def test_food_merger(database: AllRepositories, unique_user: TestUser):
|
|||
recipe = database.recipes.create(
|
||||
Recipe(
|
||||
name=slug1,
|
||||
user_id=unique_user.group_id,
|
||||
group_id=unique_user.group_id,
|
||||
user_id=unique_user.user_id,
|
||||
group_id=UUID(unique_user.group_id),
|
||||
recipe_ingredient=[
|
||||
RecipeIngredient(note="", food=food_1), # type: ignore
|
||||
RecipeIngredient(note="", food=food_2), # type: ignore
|
||||
|
@ -43,6 +46,7 @@ def test_food_merger(database: AllRepositories, unique_user: TestUser):
|
|||
database.ingredient_foods.merge(food_2.id, food_1.id)
|
||||
|
||||
recipe = database.recipes.get_one(recipe.slug)
|
||||
assert recipe
|
||||
|
||||
for ingredient in recipe.recipe_ingredient:
|
||||
assert ingredient.food.id == food_1.id # type: ignore
|
||||
|
|
|
@ -4,9 +4,9 @@ from mealie.repos.repository_factory import AllRepositories
|
|||
from tests.utils.factories import random_int, random_string
|
||||
|
||||
|
||||
def test_create_group_resolve_similar_names(database: AllRepositories):
|
||||
def test_create_group_resolve_similar_names(unfiltered_database: AllRepositories):
|
||||
base_group_name = random_string()
|
||||
groups = database.groups.create_many({"name": base_group_name} for _ in range(random_int(3, 10)))
|
||||
groups = unfiltered_database.groups.create_many({"name": base_group_name} for _ in range(random_int(3, 10)))
|
||||
|
||||
seen_names = set()
|
||||
seen_slugs = set()
|
||||
|
@ -19,17 +19,17 @@ def test_create_group_resolve_similar_names(database: AllRepositories):
|
|||
assert base_group_name in group.name
|
||||
|
||||
|
||||
def test_group_get_by_slug_or_id(database: AllRepositories):
|
||||
groups = [database.groups.create({"name": random_string()}) for _ in range(random_int(3, 10))]
|
||||
def test_group_get_by_slug_or_id(unfiltered_database: AllRepositories):
|
||||
groups = [unfiltered_database.groups.create({"name": random_string()}) for _ in range(random_int(3, 10))]
|
||||
for group in groups:
|
||||
assert database.groups.get_by_slug_or_id(group.id) == group
|
||||
assert database.groups.get_by_slug_or_id(group.slug) == group
|
||||
assert unfiltered_database.groups.get_by_slug_or_id(group.id) == group
|
||||
assert unfiltered_database.groups.get_by_slug_or_id(group.slug) == group
|
||||
|
||||
|
||||
def test_update_group_updates_slug(database: AllRepositories):
|
||||
group = database.groups.create({"name": random_string()})
|
||||
def test_update_group_updates_slug(unfiltered_database: AllRepositories):
|
||||
group = unfiltered_database.groups.create({"name": random_string()})
|
||||
assert group.slug == slugify(group.name)
|
||||
|
||||
new_name = random_string()
|
||||
group = database.groups.update(group.id, {"name": new_name})
|
||||
group = unfiltered_database.groups.update(group.id, {"name": new_name})
|
||||
assert group.slug == slugify(new_name)
|
||||
|
|
|
@ -12,7 +12,7 @@ from pydantic import UUID4
|
|||
|
||||
from mealie.repos.repository_factory import AllRepositories
|
||||
from mealie.repos.repository_units import RepositoryUnit
|
||||
from mealie.schema.group.group_shopping_list import (
|
||||
from mealie.schema.household.group_shopping_list import (
|
||||
ShoppingListItemCreate,
|
||||
ShoppingListMultiPurposeLabelCreate,
|
||||
ShoppingListMultiPurposeLabelOut,
|
||||
|
@ -64,14 +64,15 @@ def get_label_position_from_label_id(label_id: UUID4, label_settings: list[Shopp
|
|||
raise Exception("Something went wrong when parsing label settings")
|
||||
|
||||
|
||||
def test_repository_pagination(database: AllRepositories, unique_user: TestUser):
|
||||
def test_repository_pagination(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
group = database.groups.get_one(unique_user.group_id)
|
||||
assert group
|
||||
|
||||
seeder = SeederService(database, None, group) # type: ignore
|
||||
seeder = SeederService(AllRepositories(database.session, group_id=group.id))
|
||||
seeder.seed_foods("en-US")
|
||||
|
||||
foods_repo = database.ingredient_foods.by_group(unique_user.group_id) # type: ignore
|
||||
foods_repo = database.ingredient_foods
|
||||
|
||||
query = PaginationQuery(
|
||||
page=1,
|
||||
|
@ -99,14 +100,15 @@ def test_repository_pagination(database: AllRepositories, unique_user: TestUser)
|
|||
assert result.id not in seen
|
||||
|
||||
|
||||
def test_pagination_response_and_metadata(database: AllRepositories, unique_user: TestUser):
|
||||
def test_pagination_response_and_metadata(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
group = database.groups.get_one(unique_user.group_id)
|
||||
assert group
|
||||
|
||||
seeder = SeederService(database, None, group) # type: ignore
|
||||
seeder = SeederService(AllRepositories(database.session, group_id=group.id))
|
||||
seeder.seed_foods("en-US")
|
||||
|
||||
foods_repo = database.ingredient_foods.by_group(unique_user.group_id) # type: ignore
|
||||
foods_repo = database.ingredient_foods
|
||||
|
||||
# this should get all results
|
||||
query = PaginationQuery(
|
||||
|
@ -128,14 +130,15 @@ def test_pagination_response_and_metadata(database: AllRepositories, unique_user
|
|||
assert last_page_of_results.items[-1] == all_results.items[-1]
|
||||
|
||||
|
||||
def test_pagination_guides(database: AllRepositories, unique_user: TestUser):
|
||||
def test_pagination_guides(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
group = database.groups.get_one(unique_user.group_id)
|
||||
assert group
|
||||
|
||||
seeder = SeederService(database, None, group) # type: ignore
|
||||
seeder = SeederService(AllRepositories(database.session, group_id=group.id))
|
||||
seeder.seed_foods("en-US")
|
||||
|
||||
foods_repo = database.ingredient_foods.by_group(unique_user.group_id) # type: ignore
|
||||
foods_repo = database.ingredient_foods
|
||||
foods_route = (
|
||||
"/foods" # this doesn't actually have to be accurate, it's just a placeholder to test for query params
|
||||
)
|
||||
|
@ -173,7 +176,8 @@ def test_pagination_guides(database: AllRepositories, unique_user: TestUser):
|
|||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def query_units(database: AllRepositories, unique_user: TestUser):
|
||||
def query_units(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
unit_1 = database.ingredient_units.create(
|
||||
SaveIngredientUnit(name="test unit 1", group_id=unique_user.group_id, use_abbreviation=True)
|
||||
)
|
||||
|
@ -193,7 +197,7 @@ def query_units(database: AllRepositories, unique_user: TestUser):
|
|||
)
|
||||
|
||||
unit_ids = [unit.id for unit in [unit_1, unit_2, unit_3]]
|
||||
units_repo = database.ingredient_units.by_group(unique_user.group_id) # type: ignore
|
||||
units_repo = database.ingredient_units
|
||||
|
||||
yield units_repo, unit_1, unit_2, unit_3
|
||||
|
||||
|
@ -211,7 +215,8 @@ def test_pagination_filter_basic(query_units: tuple[RepositoryUnit, IngredientUn
|
|||
assert unit_results[0].id == unit_2.id
|
||||
|
||||
|
||||
def test_pagination_filter_null(database: AllRepositories, unique_user: TestUser):
|
||||
def test_pagination_filter_null(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
recipe_not_made_1 = database.recipes.create(
|
||||
Recipe(
|
||||
user_id=unique_user.user_id,
|
||||
|
@ -237,7 +242,7 @@ def test_pagination_filter_null(database: AllRepositories, unique_user: TestUser
|
|||
)
|
||||
)
|
||||
|
||||
recipe_repo = database.recipes.by_group(unique_user.group_id) # type: ignore
|
||||
recipe_repo = database.recipes
|
||||
|
||||
query = PaginationQuery(page=1, per_page=-1, query_filter="lastMade IS NONE")
|
||||
recipe_results = recipe_repo.page_all(query).items
|
||||
|
@ -300,7 +305,8 @@ def test_pagination_filter_in(query_units: tuple[RepositoryUnit, IngredientUnit,
|
|||
assert unit_3.id in result_ids
|
||||
|
||||
|
||||
def test_pagination_filter_in_advanced(database: AllRepositories, unique_user: TestUser):
|
||||
def test_pagination_filter_in_advanced(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
slug1, slug2 = (random_string(10) for _ in range(2))
|
||||
|
||||
tags = [
|
||||
|
@ -418,7 +424,8 @@ def test_pagination_filter_like(query_units: tuple[RepositoryUnit, IngredientUni
|
|||
assert unit_3.id in result_ids
|
||||
|
||||
|
||||
def test_pagination_filter_keyword_namespace_conflict(database: AllRepositories, unique_user: TestUser):
|
||||
def test_pagination_filter_keyword_namespace_conflict(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
recipe_rating_1 = database.recipes.create(
|
||||
Recipe(
|
||||
user_id=unique_user.user_id,
|
||||
|
@ -445,7 +452,7 @@ def test_pagination_filter_keyword_namespace_conflict(database: AllRepositories,
|
|||
)
|
||||
)
|
||||
|
||||
recipe_repo = database.recipes.by_group(unique_user.group_id) # type: ignore
|
||||
recipe_repo = database.recipes
|
||||
|
||||
# "rating" contains the word "in", but we should not parse this as the keyword "IN"
|
||||
query = PaginationQuery(page=1, per_page=-1, query_filter="rating > 2")
|
||||
|
@ -467,7 +474,8 @@ def test_pagination_filter_keyword_namespace_conflict(database: AllRepositories,
|
|||
assert recipe_rating_3.id in result_ids
|
||||
|
||||
|
||||
def test_pagination_filter_logical_namespace_conflict(database: AllRepositories, unique_user: TestUser):
|
||||
def test_pagination_filter_logical_namespace_conflict(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
categories = [
|
||||
CategorySave(group_id=unique_user.group_id, name=random_string(10)),
|
||||
CategorySave(group_id=unique_user.group_id, name=random_string(10)),
|
||||
|
@ -509,7 +517,7 @@ def test_pagination_filter_logical_namespace_conflict(database: AllRepositories,
|
|||
|
||||
# "recipeCategory" has the substring "or" in it, which shouldn't break queries
|
||||
query = PaginationQuery(page=1, per_page=-1, query_filter=f'recipeCategory.id = "{category_1.id}"')
|
||||
recipe_results = database.recipes.by_group(unique_user.group_id).page_all(query).items # type: ignore
|
||||
recipe_results = database.recipes.page_all(query).items
|
||||
assert len(recipe_results) == 1
|
||||
recipe_ids = {recipe.id for recipe in recipe_results}
|
||||
assert recipe_category_0.id not in recipe_ids
|
||||
|
@ -616,9 +624,8 @@ def test_pagination_filter_datetimes(
|
|||
[OrderDirection.asc, OrderDirection.desc],
|
||||
ids=["ascending", "descending"],
|
||||
)
|
||||
def test_pagination_order_by_multiple(
|
||||
database: AllRepositories, unique_user: TestUser, order_direction: OrderDirection
|
||||
):
|
||||
def test_pagination_order_by_multiple(unique_user: TestUser, order_direction: OrderDirection):
|
||||
database = unique_user.repos
|
||||
current_time = datetime.now(timezone.utc)
|
||||
|
||||
alphabet = ["a", "b", "c", "d", "e"]
|
||||
|
@ -676,11 +683,9 @@ def test_pagination_order_by_multiple(
|
|||
],
|
||||
)
|
||||
def test_pagination_order_by_multiple_directions(
|
||||
database: AllRepositories,
|
||||
unique_user: TestUser,
|
||||
order_by_str: str,
|
||||
order_direction: OrderDirection,
|
||||
unique_user: TestUser, order_by_str: str, order_direction: OrderDirection
|
||||
):
|
||||
database = unique_user.repos
|
||||
current_time = datetime.now(timezone.utc)
|
||||
|
||||
alphabet = ["a", "b", "c", "d", "e"]
|
||||
|
@ -726,9 +731,8 @@ def test_pagination_order_by_multiple_directions(
|
|||
[OrderDirection.asc, OrderDirection.desc],
|
||||
ids=["order_ascending", "order_descending"],
|
||||
)
|
||||
def test_pagination_order_by_nested_model(
|
||||
database: AllRepositories, unique_user: TestUser, order_direction: OrderDirection
|
||||
):
|
||||
def test_pagination_order_by_nested_model(unique_user: TestUser, order_direction: OrderDirection):
|
||||
database = unique_user.repos
|
||||
current_time = datetime.now(timezone.utc)
|
||||
|
||||
alphabet = ["a", "b", "c", "d", "e"]
|
||||
|
@ -758,7 +762,8 @@ def test_pagination_order_by_nested_model(
|
|||
assert query.items == sorted_foods
|
||||
|
||||
|
||||
def test_pagination_order_by_doesnt_filter(database: AllRepositories, unique_user: TestUser):
|
||||
def test_pagination_order_by_doesnt_filter(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
current_time = datetime.now(timezone.utc)
|
||||
|
||||
label = database.group_multi_purpose_labels.create(
|
||||
|
@ -771,7 +776,7 @@ def test_pagination_order_by_doesnt_filter(database: AllRepositories, unique_use
|
|||
SaveIngredientFood(name=random_string(), group_id=unique_user.group_id)
|
||||
)
|
||||
|
||||
query = database.ingredient_foods.by_group(unique_user.group_id).page_all(
|
||||
query = database.ingredient_foods.page_all(
|
||||
PaginationQuery(
|
||||
per_page=-1,
|
||||
query_filter=f"created_at>{current_time.isoformat()}",
|
||||
|
@ -800,11 +805,9 @@ def test_pagination_order_by_doesnt_filter(database: AllRepositories, unique_use
|
|||
],
|
||||
)
|
||||
def test_pagination_order_by_nulls(
|
||||
database: AllRepositories,
|
||||
unique_user: TestUser,
|
||||
null_position: OrderByNullPosition,
|
||||
order_direction: OrderDirection,
|
||||
unique_user: TestUser, null_position: OrderByNullPosition, order_direction: OrderDirection
|
||||
):
|
||||
database = unique_user.repos
|
||||
current_time = datetime.now(timezone.utc)
|
||||
|
||||
label = database.group_multi_purpose_labels.create(
|
||||
|
@ -836,7 +839,9 @@ def test_pagination_order_by_nulls(
|
|||
assert query.items[1] == food_without_label
|
||||
|
||||
|
||||
def test_pagination_shopping_list_items_with_labels(database: AllRepositories, unique_user: TestUser):
|
||||
def test_pagination_shopping_list_items_with_labels(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
|
||||
# create a shopping list and populate it with some items with labels, and some without labels
|
||||
shopping_list = database.group_shopping_lists.create(
|
||||
ShoppingListSave(
|
||||
|
@ -926,7 +931,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser):
|
|||
for mealplan_to_create in [mealplan_today, mealplan_tomorrow]:
|
||||
data = mealplan_to_create.model_dump()
|
||||
data["date"] = data["date"].strftime("%Y-%m-%d")
|
||||
response = api_client.post(api_routes.groups_mealplans, json=data, headers=unique_user.token)
|
||||
response = api_client.post(api_routes.households_mealplans, json=data, headers=unique_user.token)
|
||||
assert response.status_code == 201
|
||||
|
||||
## Yesterday
|
||||
|
@ -935,7 +940,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser):
|
|||
"perPage": -1,
|
||||
"queryFilter": f"date >= {yesterday.strftime('%Y-%m-%d')}",
|
||||
}
|
||||
response = api_client.get(api_routes.groups_mealplans, params=params, headers=unique_user.token)
|
||||
response = api_client.get(api_routes.households_mealplans, params=params, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
response_json = response.json()
|
||||
|
||||
|
@ -949,7 +954,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser):
|
|||
"perPage": -1,
|
||||
"queryFilter": f"date > {yesterday.strftime('%Y-%m-%d')}",
|
||||
}
|
||||
response = api_client.get(api_routes.groups_mealplans, params=params, headers=unique_user.token)
|
||||
response = api_client.get(api_routes.households_mealplans, params=params, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
response_json = response.json()
|
||||
|
||||
|
@ -964,7 +969,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser):
|
|||
"perPage": -1,
|
||||
"queryFilter": f"date >= {today.strftime('%Y-%m-%d')}",
|
||||
}
|
||||
response = api_client.get(api_routes.groups_mealplans, params=params, headers=unique_user.token)
|
||||
response = api_client.get(api_routes.households_mealplans, params=params, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
response_json = response.json()
|
||||
|
||||
|
@ -978,7 +983,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser):
|
|||
"perPage": -1,
|
||||
"queryFilter": f"date > {today.strftime('%Y-%m-%d')}",
|
||||
}
|
||||
response = api_client.get(api_routes.groups_mealplans, params=params, headers=unique_user.token)
|
||||
response = api_client.get(api_routes.households_mealplans, params=params, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
response_json = response.json()
|
||||
|
||||
|
@ -993,7 +998,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser):
|
|||
"perPage": -1,
|
||||
"queryFilter": f"date >= {tomorrow.strftime('%Y-%m-%d')}",
|
||||
}
|
||||
response = api_client.get(api_routes.groups_mealplans, params=params, headers=unique_user.token)
|
||||
response = api_client.get(api_routes.households_mealplans, params=params, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
response_json = response.json()
|
||||
|
||||
|
@ -1007,7 +1012,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser):
|
|||
"perPage": -1,
|
||||
"queryFilter": f"date > {tomorrow.strftime('%Y-%m-%d')}",
|
||||
}
|
||||
response = api_client.get(api_routes.groups_mealplans, params=params, headers=unique_user.token)
|
||||
response = api_client.get(api_routes.households_mealplans, params=params, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
response_json = response.json()
|
||||
|
||||
|
@ -1019,7 +1024,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser):
|
|||
"perPage": -1,
|
||||
"queryFilter": f"date >= {day_after_tomorrow.strftime('%Y-%m-%d')}",
|
||||
}
|
||||
response = api_client.get(api_routes.groups_mealplans, params=params, headers=unique_user.token)
|
||||
response = api_client.get(api_routes.households_mealplans, params=params, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
response_json = response.json()
|
||||
assert len(response_json["items"]) == 0
|
||||
|
@ -1029,7 +1034,7 @@ def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser):
|
|||
"perPage": -1,
|
||||
"queryFilter": f"date > {day_after_tomorrow.strftime('%Y-%m-%d')}",
|
||||
}
|
||||
response = api_client.get(api_routes.groups_mealplans, params=params, headers=unique_user.token)
|
||||
response = api_client.get(api_routes.households_mealplans, params=params, headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
response_json = response.json()
|
||||
assert len(response_json["items"]) == 0
|
||||
|
@ -1072,7 +1077,8 @@ def test_pagination_filter_advanced(query_units: tuple[RepositoryUnit, Ingredien
|
|||
assert unit_3.id not in result_ids
|
||||
|
||||
|
||||
def test_pagination_filter_advanced_frontend_sort(database: AllRepositories, unique_user: TestUser):
|
||||
def test_pagination_filter_advanced_frontend_sort(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
categories = [
|
||||
CategorySave(group_id=unique_user.group_id, name=random_string(10)),
|
||||
CategorySave(group_id=unique_user.group_id, name=random_string(10)),
|
||||
|
@ -1174,7 +1180,7 @@ def test_pagination_filter_advanced_frontend_sort(database: AllRepositories, uni
|
|||
)
|
||||
)
|
||||
|
||||
repo = database.recipes.by_group(unique_user.group_id) # type: ignore
|
||||
repo = database.recipes
|
||||
|
||||
qf = f'recipeCategory.id IN ["{category_1.id}"] AND tools.id IN ["{tool_1.id}"]'
|
||||
query = PaginationQuery(page=1, per_page=-1, query_filter=qf)
|
||||
|
|
|
@ -3,9 +3,12 @@ from typing import cast
|
|||
from uuid import UUID
|
||||
|
||||
import pytest
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from mealie.repos.all_repositories import get_repositories
|
||||
from mealie.repos.repository_factory import AllRepositories
|
||||
from mealie.repos.repository_recipes import RepositoryRecipes
|
||||
from mealie.schema.household.household import HouseholdCreate
|
||||
from mealie.schema.recipe import RecipeIngredient, SaveIngredientFood
|
||||
from mealie.schema.recipe.recipe import Recipe, RecipeCategory, RecipeSummary
|
||||
from mealie.schema.recipe.recipe_category import CategoryOut, CategorySave, TagSave
|
||||
|
@ -17,18 +20,34 @@ from tests.utils.fixture_schemas import TestUser
|
|||
|
||||
|
||||
@pytest.fixture()
|
||||
def unique_local_group_id(database: AllRepositories) -> str:
|
||||
return str(database.groups.create(GroupBase(name=random_string())).id)
|
||||
def unique_local_group_id(unfiltered_database: AllRepositories) -> str:
|
||||
return str(unfiltered_database.groups.create(GroupBase(name=random_string())).id)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def unique_local_user_id(database: AllRepositories, unique_local_group_id: str) -> str:
|
||||
def unique_local_household_id(unfiltered_database: AllRepositories, unique_local_group_id: str) -> str:
|
||||
database = get_repositories(unfiltered_database.session, group_id=UUID(unique_local_group_id), household_id=None)
|
||||
return str(
|
||||
database.households.create(HouseholdCreate(group_id=UUID(unique_local_group_id), name=random_string())).id
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def unique_local_user_id(
|
||||
unfiltered_database: AllRepositories, unique_local_group_id: str, unique_local_household_id: str
|
||||
) -> str:
|
||||
database = get_repositories(
|
||||
unfiltered_database.session, group_id=UUID(unique_local_group_id), household_id=UUID(unique_local_household_id)
|
||||
)
|
||||
group = database.groups.get_one(unique_local_group_id)
|
||||
household = database.households.get_one(unique_local_household_id)
|
||||
return str(
|
||||
database.users.create(
|
||||
{
|
||||
"username": random_string(),
|
||||
"email": random_email(),
|
||||
"group_id": unique_local_group_id,
|
||||
"group": group.name,
|
||||
"household": household.name,
|
||||
"full_name": random_string(),
|
||||
"password": random_string(),
|
||||
"admin": False,
|
||||
|
@ -38,11 +57,25 @@ def unique_local_user_id(database: AllRepositories, unique_local_group_id: str)
|
|||
|
||||
|
||||
@pytest.fixture()
|
||||
def search_recipes(database: AllRepositories, unique_local_group_id: str, unique_local_user_id: str) -> list[Recipe]:
|
||||
def unique_ids(
|
||||
unique_local_group_id: str, unique_local_household_id: str, unique_local_user_id: str
|
||||
) -> tuple[str, str, str]:
|
||||
return unique_local_group_id, unique_local_household_id, unique_local_user_id
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def unique_db(session: Session, unique_ids: tuple[str, str, str]):
|
||||
group_id, household_id, _ = unique_ids
|
||||
return get_repositories(session, group_id=group_id, household_id=household_id)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def search_recipes(unique_db: AllRepositories, unique_ids: tuple[str, str, str]) -> list[Recipe]:
|
||||
group_id, _, user_id = unique_ids
|
||||
recipes = [
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name="Steinbock Sloop",
|
||||
description="My favorite horns are delicious",
|
||||
recipe_ingredient=[
|
||||
|
@ -50,61 +83,63 @@ def search_recipes(database: AllRepositories, unique_local_group_id: str, unique
|
|||
],
|
||||
),
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name="Fiddlehead Fern Stir Fry",
|
||||
recipe_ingredient=[
|
||||
RecipeIngredient(note="moss"),
|
||||
],
|
||||
),
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name="Animal Sloop",
|
||||
),
|
||||
# Test diacritics
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name="Rátàtôuile",
|
||||
),
|
||||
# Add a bunch of recipes for stable randomization
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name=f"{random_string(10)} soup",
|
||||
),
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name=f"{random_string(10)} soup",
|
||||
),
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name=f"{random_string(10)} soup",
|
||||
),
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name=f"{random_string(10)} soup",
|
||||
),
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name=f"{random_string(10)} soup",
|
||||
),
|
||||
Recipe(
|
||||
user_id=unique_local_user_id,
|
||||
group_id=unique_local_group_id,
|
||||
group_id=group_id,
|
||||
user_id=user_id,
|
||||
name=f"{random_string(10)} soup",
|
||||
),
|
||||
]
|
||||
|
||||
return database.recipes.create_many(recipes)
|
||||
return unique_db.recipes.create_many(recipes)
|
||||
|
||||
|
||||
def test_recipe_repo_get_by_categories_basic(database: AllRepositories, unique_user: TestUser):
|
||||
def test_recipe_repo_get_by_categories_basic(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
|
||||
# Bootstrap the database with categories
|
||||
slug1, slug2, slug3 = (random_string(10) for _ in range(3))
|
||||
|
||||
|
@ -149,12 +184,13 @@ def test_recipe_repo_get_by_categories_basic(database: AllRepositories, unique_u
|
|||
# Get all recipes by category
|
||||
|
||||
for category in created_categories:
|
||||
repo: RepositoryRecipes = database.recipes.by_group(unique_user.group_id) # type: ignore
|
||||
repo: RepositoryRecipes = database.recipes
|
||||
recipes = repo.get_by_categories([cast(RecipeCategory, category)])
|
||||
|
||||
assert len(recipes) == 5
|
||||
|
||||
for recipe in recipes:
|
||||
assert recipe.recipe_category is not None
|
||||
found_cat = recipe.recipe_category[0]
|
||||
|
||||
assert found_cat.name == category.name
|
||||
|
@ -162,7 +198,8 @@ def test_recipe_repo_get_by_categories_basic(database: AllRepositories, unique_u
|
|||
assert found_cat.id == category.id
|
||||
|
||||
|
||||
def test_recipe_repo_get_by_categories_multi(database: AllRepositories, unique_user: TestUser):
|
||||
def test_recipe_repo_get_by_categories_multi(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
slug1, slug2 = (random_string(10) for _ in range(2))
|
||||
|
||||
categories = [
|
||||
|
@ -204,16 +241,18 @@ def test_recipe_repo_get_by_categories_multi(database: AllRepositories, unique_u
|
|||
database.recipes.create(recipe)
|
||||
|
||||
# Get all recipes by both categories
|
||||
repo: RepositoryRecipes = database.recipes.by_group(unique_local_group_id) # type: ignore
|
||||
repo: RepositoryRecipes = database.recipes
|
||||
by_category = repo.get_by_categories(cast(list[RecipeCategory], created_categories))
|
||||
|
||||
assert len(by_category) == 10
|
||||
for recipe_summary in by_category:
|
||||
assert recipe_summary.recipe_category is not None
|
||||
for recipe_category in recipe_summary.recipe_category:
|
||||
assert recipe_category.id in known_category_ids
|
||||
|
||||
|
||||
def test_recipe_repo_pagination_by_categories(database: AllRepositories, unique_user: TestUser):
|
||||
def test_recipe_repo_pagination_by_categories(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
slug1, slug2 = (random_string(10) for _ in range(2))
|
||||
|
||||
categories = [
|
||||
|
@ -270,6 +309,7 @@ def test_recipe_repo_pagination_by_categories(database: AllRepositories, unique_
|
|||
assert len(recipes_with_one_category) == 15
|
||||
|
||||
for recipe_summary in recipes_with_one_category:
|
||||
assert recipe_summary.recipe_category is not None
|
||||
category_ids = [category.id for category in recipe_summary.recipe_category]
|
||||
assert category_id in category_ids
|
||||
|
||||
|
@ -279,6 +319,7 @@ def test_recipe_repo_pagination_by_categories(database: AllRepositories, unique_
|
|||
assert len(recipes_with_one_category) == 15
|
||||
|
||||
for recipe_summary in recipes_with_one_category:
|
||||
assert recipe_summary.recipe_category is not None
|
||||
category_slugs = [category.slug for category in recipe_summary.recipe_category]
|
||||
assert category_slug in category_slugs
|
||||
|
||||
|
@ -289,6 +330,7 @@ def test_recipe_repo_pagination_by_categories(database: AllRepositories, unique_
|
|||
assert len(recipes_with_both_categories) == 10
|
||||
|
||||
for recipe_summary in recipes_with_both_categories:
|
||||
assert recipe_summary.recipe_category is not None
|
||||
category_ids = [category.id for category in recipe_summary.recipe_category]
|
||||
for category in created_categories:
|
||||
assert category.id in category_ids
|
||||
|
@ -308,7 +350,8 @@ def test_recipe_repo_pagination_by_categories(database: AllRepositories, unique_
|
|||
assert not all(i == random_ordered[0] for i in random_ordered)
|
||||
|
||||
|
||||
def test_recipe_repo_pagination_by_tags(database: AllRepositories, unique_user: TestUser):
|
||||
def test_recipe_repo_pagination_by_tags(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
slug1, slug2 = (random_string(10) for _ in range(2))
|
||||
|
||||
tags = [
|
||||
|
@ -365,6 +408,7 @@ def test_recipe_repo_pagination_by_tags(database: AllRepositories, unique_user:
|
|||
assert len(recipes_with_one_tag) == 15
|
||||
|
||||
for recipe_summary in recipes_with_one_tag:
|
||||
assert recipe_summary.tags is not None
|
||||
tag_ids = [tag.id for tag in recipe_summary.tags]
|
||||
assert tag_id in tag_ids
|
||||
|
||||
|
@ -374,6 +418,7 @@ def test_recipe_repo_pagination_by_tags(database: AllRepositories, unique_user:
|
|||
assert len(recipes_with_one_tag) == 15
|
||||
|
||||
for recipe_summary in recipes_with_one_tag:
|
||||
assert recipe_summary.tags is not None
|
||||
tag_slugs = [tag.slug for tag in recipe_summary.tags]
|
||||
assert tag_slug in tag_slugs
|
||||
|
||||
|
@ -382,6 +427,7 @@ def test_recipe_repo_pagination_by_tags(database: AllRepositories, unique_user:
|
|||
assert len(recipes_with_both_tags) == 10
|
||||
|
||||
for recipe_summary in recipes_with_both_tags:
|
||||
assert recipe_summary.tags is not None
|
||||
tag_ids = [tag.id for tag in recipe_summary.tags]
|
||||
for tag in created_tags:
|
||||
assert tag.id in tag_ids
|
||||
|
@ -402,7 +448,8 @@ def test_recipe_repo_pagination_by_tags(database: AllRepositories, unique_user:
|
|||
assert not all(i == random_ordered[0] for i in random_ordered)
|
||||
|
||||
|
||||
def test_recipe_repo_pagination_by_tools(database: AllRepositories, unique_user: TestUser):
|
||||
def test_recipe_repo_pagination_by_tools(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
slug1, slug2 = (random_string(10) for _ in range(2))
|
||||
|
||||
tools = [
|
||||
|
@ -498,7 +545,8 @@ def test_recipe_repo_pagination_by_tools(database: AllRepositories, unique_user:
|
|||
assert not all(i == random_ordered[0] for i in random_ordered)
|
||||
|
||||
|
||||
def test_recipe_repo_pagination_by_foods(database: AllRepositories, unique_user: TestUser):
|
||||
def test_recipe_repo_pagination_by_foods(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
slug1, slug2 = (random_string(10) for _ in range(2))
|
||||
|
||||
foods = [
|
||||
|
@ -606,13 +654,12 @@ def test_recipe_repo_pagination_by_foods(database: AllRepositories, unique_user:
|
|||
],
|
||||
)
|
||||
def test_basic_recipe_search(
|
||||
unique_db: AllRepositories,
|
||||
search: str,
|
||||
expected_names: list[str],
|
||||
database: AllRepositories,
|
||||
search_recipes: list[Recipe], # required so database is populated
|
||||
unique_local_group_id: str,
|
||||
):
|
||||
repo = database.recipes.by_group(unique_local_group_id) # type: ignore
|
||||
repo = unique_db.recipes
|
||||
pagination = PaginationQuery(page=1, per_page=-1, order_by="created_at", order_direction=OrderDirection.asc)
|
||||
results = repo.page_all(pagination, search=search).items
|
||||
|
||||
|
@ -626,15 +673,14 @@ def test_basic_recipe_search(
|
|||
|
||||
|
||||
def test_fuzzy_recipe_search(
|
||||
database: AllRepositories,
|
||||
unique_db: AllRepositories,
|
||||
search_recipes: list[Recipe], # required so database is populated
|
||||
unique_local_group_id: str,
|
||||
):
|
||||
# this only works on postgres
|
||||
if database.session.get_bind().name != "postgresql":
|
||||
if unique_db.session.get_bind().name != "postgresql":
|
||||
return
|
||||
|
||||
repo = database.recipes.by_group(unique_local_group_id) # type: ignore
|
||||
repo = unique_db.recipes
|
||||
pagination = PaginationQuery(page=1, per_page=-1, order_by="created_at", order_direction=OrderDirection.asc)
|
||||
results = repo.page_all(pagination, search="Steinbuck").items
|
||||
|
||||
|
@ -642,11 +688,10 @@ def test_fuzzy_recipe_search(
|
|||
|
||||
|
||||
def test_random_order_recipe_search(
|
||||
database: AllRepositories,
|
||||
unique_db: AllRepositories,
|
||||
search_recipes: list[Recipe], # required so database is populated
|
||||
unique_local_group_id: str,
|
||||
):
|
||||
repo = database.recipes.by_group(unique_local_group_id) # type: ignore
|
||||
repo = unique_db.recipes
|
||||
pagination = PaginationQuery(
|
||||
page=1,
|
||||
per_page=-1,
|
||||
|
@ -661,15 +706,16 @@ def test_random_order_recipe_search(
|
|||
assert not all(i == random_ordered[0] for i in random_ordered)
|
||||
|
||||
|
||||
def test_order_by_rating(database: AllRepositories, user_tuple: tuple[TestUser, TestUser]):
|
||||
def test_order_by_rating(user_tuple: tuple[TestUser, TestUser]):
|
||||
user_1, user_2 = user_tuple
|
||||
repo = database.recipes.by_group(UUID(user_1.group_id))
|
||||
database = user_1.repos
|
||||
repo = database.recipes
|
||||
|
||||
recipes: list[Recipe] = []
|
||||
for i in range(3):
|
||||
slug = f"recipe-{i+1}-{random_string(5)}"
|
||||
recipes.append(
|
||||
database.recipes.create(
|
||||
repo.create(
|
||||
Recipe(
|
||||
user_id=user_1.user_id,
|
||||
group_id=user_1.group_id,
|
||||
|
@ -768,7 +814,7 @@ def test_order_by_rating(database: AllRepositories, user_tuple: tuple[TestUser,
|
|||
)
|
||||
|
||||
pq = PaginationQuery(page=1, per_page=-1, order_by="rating", order_direction=OrderDirection.desc)
|
||||
data = database.recipes.by_group(UUID(user_1.group_id)).page_all(pq).items
|
||||
data = database.recipes.page_all(pq).items
|
||||
|
||||
assert len(data) == 3
|
||||
assert data[0].slug == recipe_1.slug # global rating == 4.25 (avg of 5 and 3.5)
|
||||
|
@ -776,7 +822,7 @@ def test_order_by_rating(database: AllRepositories, user_tuple: tuple[TestUser,
|
|||
assert data[2].slug == recipe_2.slug # global rating == 2.5 (avg of 4 and 1)
|
||||
|
||||
pq = PaginationQuery(page=1, per_page=-1, order_by="rating", order_direction=OrderDirection.asc)
|
||||
data = database.recipes.by_group(UUID(user_1.group_id)).page_all(pq).items
|
||||
data = database.recipes.page_all(pq).items
|
||||
|
||||
assert len(data) == 3
|
||||
assert data[0].slug == recipe_2.slug # global rating == 2.5 (avg of 4 and 1)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
from datetime import datetime, timezone
|
||||
|
||||
import pytest
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from mealie.repos.all_repositories import get_repositories
|
||||
from mealie.repos.repository_factory import AllRepositories
|
||||
from mealie.schema.recipe.recipe_ingredient import IngredientUnit, SaveIngredientUnit
|
||||
from mealie.schema.response.pagination import OrderDirection, PaginationQuery
|
||||
|
@ -10,12 +12,17 @@ from tests.utils.factories import random_int, random_string
|
|||
|
||||
|
||||
@pytest.fixture()
|
||||
def unique_local_group_id(database: AllRepositories) -> str:
|
||||
return str(database.groups.create(GroupBase(name=random_string())).id)
|
||||
def unique_local_group_id(unfiltered_database: AllRepositories) -> str:
|
||||
return str(unfiltered_database.groups.create(GroupBase(name=random_string())).id)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def search_units(database: AllRepositories, unique_local_group_id: str) -> list[IngredientUnit]:
|
||||
def unique_db(session: Session, unique_local_group_id: str):
|
||||
return get_repositories(session, group_id=unique_local_group_id)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def search_units(unique_db: AllRepositories, unique_local_group_id: str) -> list[IngredientUnit]:
|
||||
units = [
|
||||
SaveIngredientUnit(
|
||||
group_id=unique_local_group_id,
|
||||
|
@ -57,7 +64,7 @@ def search_units(database: AllRepositories, unique_local_group_id: str) -> list[
|
|||
]
|
||||
)
|
||||
|
||||
return database.ingredient_units.create_many(units)
|
||||
return unique_db.ingredient_units.create_many(units)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -82,11 +89,10 @@ def search_units(database: AllRepositories, unique_local_group_id: str) -> list[
|
|||
def test_basic_search(
|
||||
search: str,
|
||||
expected_names: list[str],
|
||||
database: AllRepositories,
|
||||
unique_db: AllRepositories,
|
||||
search_units: list[IngredientUnit], # required so database is populated
|
||||
unique_local_group_id: str,
|
||||
):
|
||||
repo = database.ingredient_units.by_group(unique_local_group_id)
|
||||
repo = unique_db.ingredient_units
|
||||
pagination = PaginationQuery(page=1, per_page=-1, order_by="created_at", order_direction=OrderDirection.asc)
|
||||
results = repo.page_all(pagination, search=search).items
|
||||
|
||||
|
@ -100,15 +106,14 @@ def test_basic_search(
|
|||
|
||||
|
||||
def test_fuzzy_search(
|
||||
database: AllRepositories,
|
||||
unique_db: AllRepositories,
|
||||
search_units: list[IngredientUnit], # required so database is populated
|
||||
unique_local_group_id: str,
|
||||
):
|
||||
# this only works on postgres
|
||||
if database.session.get_bind().name != "postgresql":
|
||||
if unique_db.session.get_bind().name != "postgresql":
|
||||
return
|
||||
|
||||
repo = database.ingredient_units.by_group(unique_local_group_id)
|
||||
repo = unique_db.ingredient_units
|
||||
pagination = PaginationQuery(page=1, per_page=-1, order_by="created_at", order_direction=OrderDirection.asc)
|
||||
results = repo.page_all(pagination, search="tabel spoone").items
|
||||
|
||||
|
@ -116,11 +121,10 @@ def test_fuzzy_search(
|
|||
|
||||
|
||||
def test_random_order_search(
|
||||
database: AllRepositories,
|
||||
unique_db: AllRepositories,
|
||||
search_units: list[IngredientUnit], # required so database is populated
|
||||
unique_local_group_id: str,
|
||||
):
|
||||
repo = database.ingredient_units.by_group(unique_local_group_id)
|
||||
repo = unique_db.ingredient_units
|
||||
pagination = PaginationQuery(
|
||||
page=1,
|
||||
per_page=-1,
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
from mealie.repos.repository_factory import AllRepositories
|
||||
from uuid import UUID
|
||||
|
||||
from mealie.schema.recipe.recipe import Recipe
|
||||
from mealie.schema.recipe.recipe_ingredient import RecipeIngredient, SaveIngredientUnit
|
||||
from tests.utils.factories import random_string
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
def test_unit_merger(database: AllRepositories, unique_user: TestUser):
|
||||
def test_unit_merger(unique_user: TestUser):
|
||||
database = unique_user.repos
|
||||
recipe: Recipe | None = None
|
||||
slug1 = random_string(10)
|
||||
|
||||
unit_1 = database.ingredient_units.create(
|
||||
|
@ -25,8 +28,8 @@ def test_unit_merger(database: AllRepositories, unique_user: TestUser):
|
|||
recipe = database.recipes.create(
|
||||
Recipe(
|
||||
name=slug1,
|
||||
user_id=unique_user.group_id,
|
||||
group_id=unique_user.group_id,
|
||||
user_id=unique_user.user_id,
|
||||
group_id=UUID(unique_user.group_id),
|
||||
recipe_ingredient=[
|
||||
RecipeIngredient(note="", unit=unit_1), # type: ignore
|
||||
RecipeIngredient(note="", unit=unit_2), # type: ignore
|
||||
|
@ -35,6 +38,7 @@ def test_unit_merger(database: AllRepositories, unique_user: TestUser):
|
|||
)
|
||||
|
||||
# Santiy check make sure recipe got created
|
||||
|
||||
assert recipe.id is not None
|
||||
|
||||
for ing in recipe.recipe_ingredient:
|
||||
|
@ -43,6 +47,7 @@ def test_unit_merger(database: AllRepositories, unique_user: TestUser):
|
|||
database.ingredient_units.merge(unit_2.id, unit_1.id)
|
||||
|
||||
recipe = database.recipes.get_one(recipe.slug)
|
||||
assert recipe
|
||||
|
||||
for ingredient in recipe.recipe_ingredient:
|
||||
assert ingredient.unit.id == unit_1.id # type: ignore
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from mealie.repos.all_repositories import AllRepositories
|
||||
from mealie.schema.user import PrivateUser
|
||||
from tests.utils.fixture_schemas import TestUser
|
||||
|
||||
|
||||
def test_user_directory_deleted_on_delete(database: AllRepositories, unique_user: TestUser) -> None:
|
||||
def test_user_directory_deleted_on_delete(unique_user: TestUser) -> None:
|
||||
database = unique_user.repos
|
||||
user_dir = PrivateUser.get_directory(unique_user.user_id)
|
||||
assert user_dir.exists()
|
||||
database.users.delete(unique_user.user_id)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue