fix: add tests to cover recipe image update router

This commit is contained in:
mariodz95 2025-08-02 13:23:12 +02:00
commit 15b56c32e0
4 changed files with 102 additions and 11 deletions

View file

@ -523,13 +523,12 @@ class RecipeController(BaseRecipeController):
@router.put("/{slug}/image", response_model=UpdateImageResponse, tags=["Recipe: Images and Assets"])
def update_recipe_image(self, slug: str, image: bytes = File(...), extension: str = Form(...)):
group_recipes = get_repositories(self.session, group_id=self.group_id, household_id=None).recipes
recipe = group_recipes.get_one(slug)
data_service = RecipeDataService(recipe.id)
data_service.write_image(image, extension)
new_version = self.group_recipes.update_image(slug, extension)
return UpdateImageResponse(image=new_version)
try:
new_version = self.service.update_recipe_image(slug, image, extension)
return UpdateImageResponse(image=new_version)
except Exception as e:
self.handle_exceptions(e)
return None
@router.post("/{slug}/assets", response_model=RecipeAsset, tags=["Recipe: Images and Assets"])
def upload_recipe_asset(
@ -551,8 +550,7 @@ class RecipeController(BaseRecipeController):
file_name = f"{file_slug}.{extension}"
asset_in = RecipeAsset(name=name, icon=icon, file_name=file_name)
group_recipes = get_repositories(self.session, group_id=self.group_id, household_id=None).recipes
recipe = group_recipes.get_one(slug)
recipe = self.service.get_one(slug)
dest = recipe.asset_dir / file_name
@ -569,8 +567,9 @@ class RecipeController(BaseRecipeController):
if not dest.is_file():
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)
recipe.assets.append(asset_in)
if recipe.assets is not None:
recipe.assets.append(asset_in)
group_recipes.update(slug, recipe)
self.service.update_one(slug, recipe)
return asset_in

View file

@ -408,6 +408,16 @@ class RecipeService(RecipeServiceBase):
self.check_assets(new_data, recipe.slug)
return new_data
def update_recipe_image(self, slug: str, image: bytes, extension: str):
recipe = self.get_one(slug)
if not self.can_update(recipe):
raise exceptions.PermissionDenied("You do not have permission to edit this recipe.")
data_service = RecipeDataService(recipe.id)
data_service.write_image(image, extension)
return self.group_recipes.update_image(slug, extension)
def patch_one(self, slug_or_id: str | UUID, patch_data: Recipe) -> Recipe:
recipe: Recipe = self._pre_update_check(slug_or_id, patch_data)

View file

@ -7,6 +7,7 @@ from fastapi.testclient import TestClient
from mealie.schema.cookbook.cookbook import SaveCookBook
from mealie.schema.recipe.recipe import Recipe
from mealie.schema.recipe.recipe_category import TagSave
from tests import data
from tests.utils import api_routes
from tests.utils.factories import random_string
from tests.utils.fixture_schemas import TestUser
@ -371,3 +372,53 @@ def test_cookbooks_from_other_households(api_client: TestClient, unique_user: Te
response = api_client.get(api_routes.recipes, params={"cookbook": h2_cookbook.slug}, headers=unique_user.token)
assert response.status_code == 200
@pytest.mark.parametrize("is_private_household", [True, False])
@pytest.mark.parametrize("household_lock_recipe_edits", [True, False])
def test_update_recipe_image_from_other_households(
api_client: TestClient,
unique_user: TestUser,
h2_user: TestUser,
is_private_household: bool,
household_lock_recipe_edits: bool,
):
household = unique_user.repos.households.get_one(h2_user.household_id)
assert household and household.preferences
household.preferences.private_household = is_private_household
household.preferences.lock_recipe_edits_from_other_households = household_lock_recipe_edits
unique_user.repos.household_preferences.update(household.id, household.preferences)
response = api_client.post(api_routes.recipes, json={"name": random_string()}, headers=h2_user.token)
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 = str(h2_recipe.id)
response = api_client.get(api_routes.recipes_slug(h2_recipe_id), headers=unique_user.token)
assert response.status_code == 200
recipe_json = response.json()
assert recipe_json["id"] == h2_recipe_id
image_version = response.json()["image"]
data_payload = {"extension": "jpg"}
file_payload = {"image": data.images_test_image_1.read_bytes()}
response = api_client.put(
api_routes.recipes_slug_image(recipe_json["slug"]),
data=data_payload,
files=file_payload,
headers=unique_user.token,
)
if household_lock_recipe_edits:
assert response.status_code == 403
response = api_client.get(api_routes.recipes_slug(h2_recipe_id), headers=unique_user.token)
recipe_respons = response.json()
assert recipe_respons["image"] == image_version
else:
assert response.status_code == 200
response = api_client.get(api_routes.recipes_slug(h2_recipe_id), headers=unique_user.token)
recipe_respons = response.json()
assert recipe_respons["image"] is not None

View file

@ -6,6 +6,7 @@ from fastapi.testclient import TestClient
from mealie.repos.repository_factory import AllRepositories
from mealie.schema.recipe.recipe import Recipe
from mealie.schema.recipe.recipe_settings import RecipeSettings
from tests import data
from tests.utils import api_routes
from tests.utils.factories import random_string
from tests.utils.fixture_schemas import TestUser
@ -180,3 +181,33 @@ def test_admin_can_delete_locked_recipe_owned_by_another_user(
response = api_client.delete(api_routes.recipes_slug(slug), headers=admin_user.token)
assert response.status_code == 200
def test_user_can_update_recipe_image(api_client: TestClient, unique_user: TestUser):
data_payload = {"extension": "jpg"}
file_payload = {"image": data.images_test_image_1.read_bytes()}
household = unique_user.repos.households.get_one(unique_user.household_id)
assert household and household.preferences
household.preferences.private_household = True
household.preferences.lock_recipe_edits_from_other_households = True
unique_user.repos.household_preferences.update(household.id, household.preferences)
response = api_client.post(api_routes.recipes, json={"name": random_string()}, headers=unique_user.token)
assert response.status_code == 201
recipe_json = unique_user.repos.recipes.get_one(response.json())
assert recipe_json and recipe_json.id
assert recipe_json.image is None
recipe_id = str(recipe_json.id)
response = api_client.put(
api_routes.recipes_slug_image(recipe_json.slug),
data=data_payload,
files=file_payload,
headers=unique_user.token,
)
assert response.status_code == 200
response = api_client.get(api_routes.recipes_slug(recipe_id), headers=unique_user.token)
recipe_respons = response.json()
assert recipe_respons["image"] is not None