fix: dash slug names (#5709)

Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com>
This commit is contained in:
Fernando Muñoz Paredes
2025-10-24 23:01:55 +02:00
committed by GitHub
parent 144d4caea6
commit 107dfc34de
4 changed files with 37 additions and 3 deletions

View File

@@ -22,6 +22,14 @@ class PermissionDenied(Exception):
pass
class SlugError(Exception):
"""
This exception is raised when the recipe name generates an invalid slug.
"""
pass
class NoEntryFound(Exception):
"""
This exception is raised when a user tries to access a resource that does not exist.

View File

@@ -4,6 +4,7 @@ from uuid import UUID
import orjson
import sqlalchemy
import sqlalchemy.exc
from fastapi import (
BackgroundTasks,
Depends,
@@ -80,13 +81,25 @@ class RecipeController(BaseRecipeController):
if thrownType == exceptions.PermissionDenied:
self.logger.error("Permission Denied on recipe controller action")
raise HTTPException(status_code=403, detail=ErrorResponse.respond(message="Permission Denied"))
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail=ErrorResponse.respond(message="Permission Denied")
)
elif thrownType == exceptions.NoEntryFound:
self.logger.error("No Entry Found on recipe controller action")
raise HTTPException(status_code=404, detail=ErrorResponse.respond(message="No Entry Found"))
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail=ErrorResponse.respond(message="No Entry Found")
)
elif thrownType == sqlalchemy.exc.IntegrityError:
self.logger.error("SQL Integrity Error on recipe controller action")
raise HTTPException(status_code=400, detail=ErrorResponse.respond(message="Recipe already exists"))
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorResponse.respond(message="Recipe already exists")
)
elif thrownType == exceptions.SlugError:
self.logger.error("Failed to generate a valid slug from recipe name")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ErrorResponse.respond(message="Unable to generate recipe slug"),
)
else:
self.logger.error("Unknown Error on recipe controller action")
self.logger.exception(ex)

View File

@@ -14,6 +14,7 @@ from sqlalchemy.orm import Session, joinedload, selectinload
from sqlalchemy.orm.interfaces import LoaderOption
from mealie.core.config import get_app_dirs
from mealie.core.exceptions import SlugError
from mealie.db.models.users.users import User
from mealie.schema._mealie import MealieModel, SearchType
from mealie.schema._mealie.mealie_model import UpdatedAtField
@@ -45,8 +46,13 @@ def create_recipe_slug(name: str, max_length: int = 250) -> str:
Returns:
A truncated slug string
Raises:
ValueError: If the name cannot be converted to a valid slug
"""
generated_slug = slugify(name)
if not generated_slug:
raise SlugError("Recipe name cannot be empty or contain only special characters")
if len(generated_slug) > max_length:
generated_slug = generated_slug[:max_length]
return generated_slug

View File

@@ -929,6 +929,13 @@ def test_create_recipe_with_extremely_long_slug(api_client: TestClient, unique_u
assert updated_recipe["slug"] == slugify(new_name)
def test_create_recipe_slug_not_empty(api_client: TestClient, unique_user: TestUser):
recipe_name = "---" # will result in an empty slug
response = api_client.post(api_routes.recipes, json={"name": recipe_name}, headers=unique_user.token)
assert response.status_code == 400
def test_create_recipe_slug_length_validation(api_client: TestClient, unique_user: TestUser):
"""Test that recipe slugs are properly truncated to a reasonable length."""
very_long_name = "A" * 500 # 500 character name