From 7f102f513d3067bb202a641bdb4619a558c0fd4f Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Wed, 23 Mar 2022 17:23:40 -0800 Subject: [PATCH] Feature/auto increment recipe name (#1088) * auto-increment-recipe-name * add test-case * re-implement as try/except --- mealie/repos/repository_recipes.py | 17 +++++++++++++ .../user_recipe_tests/test_recipe_crud.py | 24 +++++++++++++++++++ .../user_recipe_tests/test_recipe_owner.py | 5 ++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/mealie/repos/repository_recipes.py b/mealie/repos/repository_recipes.py index 6fafa24de2c2..c229c786f550 100644 --- a/mealie/repos/repository_recipes.py +++ b/mealie/repos/repository_recipes.py @@ -2,7 +2,9 @@ from random import randint from typing import Any, Optional from uuid import UUID +from slugify import slugify from sqlalchemy import and_, func +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import joinedload from mealie.db.models.recipe.category import Category @@ -17,6 +19,21 @@ from .repository_generic import RepositoryGeneric class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]): + def create(self, document: Recipe) -> Recipe: # type: ignore + max_retries = 10 + original_name: str = document.name # type: ignore + + for i in range(1, 11): + try: + return super().create(document) + except IntegrityError: + self.session.rollback() + document.name = f"{original_name} ({i})" + document.slug = slugify(document.name) + + if i >= max_retries: + raise + def by_group(self, group_id: UUID) -> "RepositoryRecipes": return super().by_group(group_id) # type: ignore diff --git a/tests/integration_tests/user_recipe_tests/test_recipe_crud.py b/tests/integration_tests/user_recipe_tests/test_recipe_crud.py index 576846f89b28..d490d4eed471 100644 --- a/tests/integration_tests/user_recipe_tests/test_recipe_crud.py +++ b/tests/integration_tests/user_recipe_tests/test_recipe_crud.py @@ -15,6 +15,7 @@ from mealie.services.recipe.recipe_data_service import RecipeDataService from mealie.services.scraper.scraper_strategies import RecipeScraperOpenGraph from tests import utils from tests.utils.app_routes import AppRoutes +from tests.utils.factories import random_string from tests.utils.fixture_schemas import TestUser from tests.utils.recipe_data import RecipeSiteTestCase, get_recipe_test_cases @@ -167,3 +168,26 @@ def test_recipe_crud_404(api_client: TestClient, api_routes: AppRoutes, unique_u response = api_client.patch(api_routes.recipes_create_url, json={"test": "stest"}, headers=unique_user.token) assert response.status_code == 404 + + +def test_create_recipe_same_name(api_client: TestClient, api_routes: AppRoutes, unique_user: TestUser): + slug = random_string(10) + + response = api_client.post("/api/recipes", json={"name": slug}, headers=unique_user.token) + assert response.status_code == 201 + assert json.loads(response.text) == slug + + response = api_client.post("/api/recipes", json={"name": slug}, headers=unique_user.token) + assert response.status_code == 201 + assert json.loads(response.text) == f"{slug}-1" + + +def test_create_recipe_too_many_time(api_client: TestClient, api_routes: AppRoutes, unique_user: TestUser): + slug = random_string(10) + + for _ in range(10): + response = api_client.post("/api/recipes", json={"name": slug}, headers=unique_user.token) + assert response.status_code == 201 + + response = api_client.post("/api/recipes", json={"name": slug}, headers=unique_user.token) + assert response.status_code == 400 diff --git a/tests/integration_tests/user_recipe_tests/test_recipe_owner.py b/tests/integration_tests/user_recipe_tests/test_recipe_owner.py index 67af89a8b65c..aefc18d54f35 100644 --- a/tests/integration_tests/user_recipe_tests/test_recipe_owner.py +++ b/tests/integration_tests/user_recipe_tests/test_recipe_owner.py @@ -62,9 +62,10 @@ def test_unique_slug_by_group(api_client: TestClient, unique_user: TestUser, g2_ response = api_client.post(Routes.base, json=create_data, headers=g2_user.token) assert response.status_code == 201 - # Try to create a recipe again with the same name + # Try to create a recipe again with the same name and check that the name was incremented response = api_client.post(Routes.base, json=create_data, headers=g2_user.token) - assert response.status_code == 400 + assert response.status_code == 201 + assert response.json() == create_data["name"] + "-1" def test_user_locked_recipe(api_client: TestClient, user_tuple: list[TestUser]) -> None: