mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-02-02 18:52:18 -05:00
Compare commits
4 Commits
v3.10.0
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cee2c351a3 | ||
|
|
874dc94d81 | ||
|
|
9247204f59 | ||
|
|
bd23896e34 |
@@ -13,6 +13,22 @@
|
||||
{{ $t("general.discard-changes-description") }}
|
||||
</v-card-text>
|
||||
</BaseDialog>
|
||||
<BaseDialog
|
||||
v-model="saveErrorDialog"
|
||||
:title="$t('recipe.save-error')"
|
||||
color="error"
|
||||
:icon="$globals.icons.alertCircle"
|
||||
@cancel="saveErrorDialog = false"
|
||||
>
|
||||
<v-card-text>
|
||||
<p class="mb-2">
|
||||
<strong>{{ saveErrorMessage }}</strong>
|
||||
</p>
|
||||
<p>
|
||||
{{ $t('recipe.save-error-description') }}
|
||||
</p>
|
||||
</v-card-text>
|
||||
</BaseDialog>
|
||||
<RecipePageParseDialog
|
||||
:model-value="isParsing"
|
||||
:ingredients="recipe.recipeIngredient"
|
||||
@@ -246,6 +262,8 @@ const notLinkedIngredients = computed(() => {
|
||||
*/
|
||||
const originalRecipe = ref<Recipe | null>(null);
|
||||
const discardDialog = ref(false);
|
||||
const saveErrorDialog = ref(false);
|
||||
const saveErrorMessage = ref("");
|
||||
const pendingRoute = ref<RouteLocationNormalized | null>(null);
|
||||
|
||||
invoke(async () => {
|
||||
@@ -352,6 +370,11 @@ async function saveRecipe() {
|
||||
const { data, error } = await api.recipes.updateOne(recipe.value.slug, recipe.value);
|
||||
if (!error) {
|
||||
setMode(PageMode.VIEW);
|
||||
} else {
|
||||
// Show prominent error dialog for save failures
|
||||
saveErrorMessage.value = error?.response?.data?.detail?.message || "An error occurred while saving the recipe.";
|
||||
saveErrorDialog.value = true;
|
||||
return;
|
||||
}
|
||||
if (data?.slug) {
|
||||
router.push(`/g/${groupSlug.value}/r/` + data.slug);
|
||||
|
||||
@@ -530,6 +530,8 @@
|
||||
"recipe-settings": "Recipe Settings",
|
||||
"recipe-update-failed": "Recipe update failed",
|
||||
"recipe-updated": "Recipe updated",
|
||||
"save-error": "Unable to Save Recipe",
|
||||
"save-error-description": "Your changes have been preserved in the editor. Please fix the issue and try saving again.",
|
||||
"remove-from-favorites": "Remove from Favorites",
|
||||
"remove-section": "Remove Section",
|
||||
"saturated-fat-content": "Saturated fat",
|
||||
|
||||
@@ -92,7 +92,10 @@ class RecipeController(BaseRecipeController):
|
||||
elif thrownType == sqlalchemy.exc.IntegrityError:
|
||||
self.logger.error("SQL Integrity Error on recipe controller action")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorResponse.respond(message="Recipe already exists")
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=ErrorResponse.respond(
|
||||
message="A recipe with this name already exists. Please choose a different name and try saving again."
|
||||
)
|
||||
)
|
||||
elif thrownType == exceptions.RecursiveRecipe:
|
||||
self.logger.error("Recursive Recipe Link Error on recipe controller action")
|
||||
|
||||
@@ -1324,3 +1324,45 @@ def test_create_recipe_slug_length_validation(api_client: TestClient, unique_use
|
||||
|
||||
response = api_client.get(api_routes.recipes_slug(created_slug), headers=unique_user.token)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_recipe_update_duplicate_name_error(api_client: TestClient, unique_user: TestUser):
|
||||
"""Test that updating a recipe with a duplicate name returns a 400 error with a helpful message."""
|
||||
# Create two recipes with different names
|
||||
recipe1_name = random_string(10)
|
||||
recipe2_name = random_string(10)
|
||||
|
||||
response1 = api_client.post(api_routes.recipes, json={"name": recipe1_name}, headers=unique_user.token)
|
||||
assert response1.status_code == 201
|
||||
recipe1_slug = json.loads(response1.text)
|
||||
|
||||
response2 = api_client.post(api_routes.recipes, json={"name": recipe2_name}, headers=unique_user.token)
|
||||
assert response2.status_code == 201
|
||||
recipe2_slug = json.loads(response2.text)
|
||||
|
||||
# Fetch the full recipe2 object
|
||||
get_recipe2 = api_client.get(api_routes.recipes_slug(recipe2_slug), headers=unique_user.token)
|
||||
assert get_recipe2.status_code == 200
|
||||
recipe2 = json.loads(get_recipe2.text)
|
||||
|
||||
# Try to update recipe2 with recipe1's name (should fail)
|
||||
recipe2["name"] = recipe1_name
|
||||
update_response = api_client.put(
|
||||
api_routes.recipes_slug(recipe2_slug),
|
||||
json=recipe2,
|
||||
headers=unique_user.token
|
||||
)
|
||||
|
||||
# Should return 400 error with helpful message
|
||||
assert update_response.status_code == 400
|
||||
response_data = json.loads(update_response.text)
|
||||
error_message = response_data["detail"]["message"]
|
||||
assert "already exists" in error_message.lower()
|
||||
assert "choose a different name" in error_message.lower()
|
||||
assert "try saving again" in error_message.lower()
|
||||
|
||||
# Verify original recipe2 is unchanged in the database
|
||||
get_response = api_client.get(api_routes.recipes_slug(recipe2_slug), headers=unique_user.token)
|
||||
assert get_response.status_code == 200
|
||||
unchanged_recipe = json.loads(get_response.text)
|
||||
assert unchanged_recipe["name"] == recipe2_name
|
||||
|
||||
Reference in New Issue
Block a user