mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 10:13:32 -04:00 
			
		
		
		
	fix: Broken Social Preview Links (#4183)
This commit is contained in:
		| @@ -165,13 +165,13 @@ def serve_recipe_with_meta_public( | |||||||
|         public_repos = AllRepositories(session) |         public_repos = AllRepositories(session) | ||||||
|         group = public_repos.groups.get_by_slug_or_id(group_slug) |         group = public_repos.groups.get_by_slug_or_id(group_slug) | ||||||
|  |  | ||||||
|         if not group or group.preferences.private_group:  # type: ignore |         if not (group and group.preferences) or group.preferences.private_group: | ||||||
|             return response_404() |             return response_404() | ||||||
|  |  | ||||||
|         group_repos = AllRepositories(session, group_id=group.id) |         group_repos = AllRepositories(session, group_id=group.id, household_id=None) | ||||||
|         recipe = group_repos.recipes.get_one(recipe_slug) |         recipe = group_repos.recipes.get_one(recipe_slug) | ||||||
|  |  | ||||||
|         if not recipe or not recipe.settings.public:  # type: ignore |         if not (recipe and recipe.settings) or not recipe.settings.public: | ||||||
|             return response_404() |             return response_404() | ||||||
|  |  | ||||||
|         # Inject meta tags |         # Inject meta tags | ||||||
| @@ -190,9 +190,9 @@ async def serve_recipe_with_meta( | |||||||
|         return serve_recipe_with_meta_public(group_slug, recipe_slug, session) |         return serve_recipe_with_meta_public(group_slug, recipe_slug, session) | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         repos = AllRepositories(session, group_id=user.group_id) |         group_repos = AllRepositories(session, group_id=user.group_id, household_id=None) | ||||||
|  |  | ||||||
|         recipe = repos.recipes.get_one(recipe_slug, "slug") |         recipe = group_repos.recipes.get_one(recipe_slug, "slug") | ||||||
|         if recipe is None: |         if recipe is None: | ||||||
|             return response_404() |             return response_404() | ||||||
|  |  | ||||||
| @@ -204,8 +204,8 @@ async def serve_recipe_with_meta( | |||||||
|  |  | ||||||
| async def serve_shared_recipe_with_meta(group_slug: str, token_id: str, session: Session = Depends(generate_session)): | async def serve_shared_recipe_with_meta(group_slug: str, token_id: str, session: Session = Depends(generate_session)): | ||||||
|     try: |     try: | ||||||
|         repos = AllRepositories(session) |         public_repos = AllRepositories(session, group_id=None) | ||||||
|         token_summary = repos.recipe_share_tokens.get_one(token_id) |         token_summary = public_repos.recipe_share_tokens.get_one(token_id) | ||||||
|         if token_summary is None: |         if token_summary is None: | ||||||
|             raise Exception("Token Not Found") |             raise Exception("Token Not Found") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,46 @@ | |||||||
|  | import pytest | ||||||
| from bs4 import BeautifulSoup | from bs4 import BeautifulSoup | ||||||
|  |  | ||||||
| from mealie.routes.spa import MetaTag, inject_meta, inject_recipe_json | from mealie.routes import spa | ||||||
|  | from mealie.schema.recipe.recipe import Recipe | ||||||
|  | from mealie.schema.recipe.recipe_share_token import RecipeShareTokenSave | ||||||
| from tests import data as test_data | from tests import data as test_data | ||||||
| from tests.utils.factories import random_string | from tests.utils.factories import random_string | ||||||
|  | from tests.utils.fixture_schemas import TestUser | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture(autouse=True) | ||||||
|  | def set_spa_contents(): | ||||||
|  |     """Inject a simple HTML string into the SPA module to enable metadata injection""" | ||||||
|  |  | ||||||
|  |     spa.__contents = "<!DOCTYPE html><html><head></head><body></body></html>" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def set_group_is_private(unique_user: TestUser, *, is_private: bool): | ||||||
|  |     group = unique_user.repos.groups.get_by_slug_or_id(unique_user.group_id) | ||||||
|  |     assert group and group.preferences | ||||||
|  |     group.preferences.private_group = is_private | ||||||
|  |     unique_user.repos.group_preferences.update(group.id, group.preferences) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def set_recipe_is_public(unique_user: TestUser, recipe: Recipe, *, is_public: bool): | ||||||
|  |     assert recipe.settings | ||||||
|  |     recipe.settings.public = is_public | ||||||
|  |     unique_user.repos.recipes.update(recipe.slug, recipe) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def create_recipe(user: TestUser) -> Recipe: | ||||||
|  |     recipe = user.repos.recipes.create( | ||||||
|  |         Recipe( | ||||||
|  |             user_id=user.user_id, | ||||||
|  |             group_id=user.group_id, | ||||||
|  |             name=random_string(), | ||||||
|  |         ) | ||||||
|  |     ) | ||||||
|  |     set_group_is_private(user, is_private=False) | ||||||
|  |     set_recipe_is_public(user, recipe, is_public=True) | ||||||
|  |  | ||||||
|  |     return recipe | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_spa_metadata_injection(): | def test_spa_metadata_injection(): | ||||||
| @@ -22,9 +60,9 @@ def test_spa_metadata_injection(): | |||||||
|  |  | ||||||
|         assert title_tag and title_tag["content"] |         assert title_tag and title_tag["content"] | ||||||
|  |  | ||||||
|         new_title_tag = MetaTag(hid="og:title", property_name="og:title", content=random_string()) |         new_title_tag = spa.MetaTag(hid="og:title", property_name="og:title", content=random_string()) | ||||||
|         new_arbitrary_tag = MetaTag(hid=random_string(), property_name=random_string(), content=random_string()) |         new_arbitrary_tag = spa.MetaTag(hid=random_string(), property_name=random_string(), content=random_string()) | ||||||
|         new_html = inject_meta(str(soup), [new_title_tag, new_arbitrary_tag]) |         new_html = spa.inject_meta(str(soup), [new_title_tag, new_arbitrary_tag]) | ||||||
|  |  | ||||||
|     # verify changes were injected |     # verify changes were injected | ||||||
|     soup = BeautifulSoup(new_html, "lxml") |     soup = BeautifulSoup(new_html, "lxml") | ||||||
| @@ -63,8 +101,91 @@ def test_spa_recipe_json_injection(): | |||||||
|         soup = BeautifulSoup(f, "lxml") |         soup = BeautifulSoup(f, "lxml") | ||||||
|         assert "https://schema.org" not in str(soup) |         assert "https://schema.org" not in str(soup) | ||||||
|  |  | ||||||
|         html = inject_recipe_json(str(soup), schema) |         html = spa.inject_recipe_json(str(soup), schema) | ||||||
|  |  | ||||||
|     assert "@context" in html |     assert "@context" in html | ||||||
|     assert "https://schema.org" in html |     assert "https://schema.org" in html | ||||||
|     assert recipe_name in html |     assert recipe_name in html | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize("use_public_user", [True, False]) | ||||||
|  | @pytest.mark.asyncio | ||||||
|  | async def test_spa_serve_recipe_with_meta(unique_user: TestUser, use_public_user: bool): | ||||||
|  |     recipe = create_recipe(unique_user) | ||||||
|  |     user = unique_user.repos.users.get_by_username(unique_user.username) | ||||||
|  |     assert user | ||||||
|  |  | ||||||
|  |     response = await spa.serve_recipe_with_meta( | ||||||
|  |         user.group_slug, recipe.slug, user=None if use_public_user else user, session=unique_user.repos.session | ||||||
|  |     ) | ||||||
|  |     assert response.status_code == 200 | ||||||
|  |     assert "https://schema.org" in response.body.decode() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize("use_public_user", [True, False]) | ||||||
|  | @pytest.mark.asyncio | ||||||
|  | async def test_spa_serve_recipe_with_meta_invalid_data(unique_user: TestUser, use_public_user: bool): | ||||||
|  |     recipe = create_recipe(unique_user) | ||||||
|  |     user = unique_user.repos.users.get_by_username(unique_user.username) | ||||||
|  |     assert user | ||||||
|  |  | ||||||
|  |     response = await spa.serve_recipe_with_meta( | ||||||
|  |         random_string(), recipe.slug, user=None if use_public_user else user, session=unique_user.repos.session | ||||||
|  |     ) | ||||||
|  |     assert response.status_code == 404 | ||||||
|  |  | ||||||
|  |     response = await spa.serve_recipe_with_meta( | ||||||
|  |         user.group_slug, random_string(), user=None if use_public_user else user, session=unique_user.repos.session | ||||||
|  |     ) | ||||||
|  |     assert response.status_code == 404 | ||||||
|  |  | ||||||
|  |     set_recipe_is_public(unique_user, recipe, is_public=False) | ||||||
|  |     response = await spa.serve_recipe_with_meta( | ||||||
|  |         user.group_slug, recipe.slug, user=None if use_public_user else user, session=unique_user.repos.session | ||||||
|  |     ) | ||||||
|  |     if use_public_user: | ||||||
|  |         assert response.status_code == 404 | ||||||
|  |     else: | ||||||
|  |         assert response.status_code == 200 | ||||||
|  |  | ||||||
|  |     set_group_is_private(unique_user, is_private=True) | ||||||
|  |     set_recipe_is_public(unique_user, recipe, is_public=True) | ||||||
|  |     response = await spa.serve_recipe_with_meta( | ||||||
|  |         user.group_slug, recipe.slug, user=None if use_public_user else user, session=unique_user.repos.session | ||||||
|  |     ) | ||||||
|  |     if use_public_user: | ||||||
|  |         assert response.status_code == 404 | ||||||
|  |     else: | ||||||
|  |         assert response.status_code == 200 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize("use_private_group", [True, False]) | ||||||
|  | @pytest.mark.parametrize("use_public_recipe", [True, False]) | ||||||
|  | @pytest.mark.asyncio | ||||||
|  | async def test_spa_service_shared_recipe_with_meta( | ||||||
|  |     unique_user: TestUser, use_private_group: bool, use_public_recipe: bool | ||||||
|  | ): | ||||||
|  |     group = unique_user.repos.groups.get_by_slug_or_id(unique_user.group_id) | ||||||
|  |     assert group | ||||||
|  |     recipe = create_recipe(unique_user) | ||||||
|  |  | ||||||
|  |     # visibility settings shouldn't matter for shared recipes | ||||||
|  |     set_group_is_private(unique_user, is_private=use_private_group) | ||||||
|  |     set_recipe_is_public(unique_user, recipe, is_public=use_public_recipe) | ||||||
|  |  | ||||||
|  |     token = unique_user.repos.recipe_share_tokens.create( | ||||||
|  |         RecipeShareTokenSave(recipe_id=recipe.id, group_id=unique_user.group_id) | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     response = await spa.serve_shared_recipe_with_meta(group.slug, token.id, session=unique_user.repos.session) | ||||||
|  |     assert response.status_code == 200 | ||||||
|  |     assert "https://schema.org" in response.body.decode() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.asyncio | ||||||
|  | async def test_spa_service_shared_recipe_with_meta_invalid_data(unique_user: TestUser): | ||||||
|  |     group = unique_user.repos.groups.get_by_slug_or_id(unique_user.group_id) | ||||||
|  |     assert group | ||||||
|  |  | ||||||
|  |     response = await spa.serve_shared_recipe_with_meta(group.slug, random_string(), session=unique_user.repos.session) | ||||||
|  |     assert response.status_code == 404 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user