From b985aa283f9ddd4e9d5e0308bed871d981725bf8 Mon Sep 17 00:00:00 2001 From: Rithvik Sriram Date: Thu, 15 Jan 2026 15:24:21 +0100 Subject: [PATCH 1/5] added a special warning message when user tries to add duplicate ingredients --- .../client/scenes/FoodpalApplicationCtrl.java | 19 ++++++++++++------- .../scenes/recipe/IngredientsPopupCtrl.java | 9 ++++++++- .../java/client/utils/server/ServerUtils.java | 5 +++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java index 3242d21..d553712 100644 --- a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java +++ b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java @@ -534,13 +534,18 @@ public class FoodpalApplicationCtrl implements LocaleAware { // Wait for the user to enter a value Optional result = dialog.showAndWait(); - result.ifPresent(name -> { - // Create a new Ingredient object - Ingredient newIngredient = new Ingredient(); - newIngredient.setName(name); - - // Add the new ingredient to the ListView - ingredientListView.getItems().add(newIngredient); + result.ifPresent(recipeName ->{ + String trim = recipeName.trim(); + if(trim.isEmpty()){ + showError("Invalid Input", "Cannot have empty ingredient name"); + return; + } + if(ingredientListView.getItems().stream() + .map(Ingredient::getName) + .anyMatch(ingName -> ingName.equalsIgnoreCase(trim))){ + showError("Duplicate Ingredient", "Cannot have duplicate ingredients," + + " Please provide unique Ingredient names"); + } }); } diff --git a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java index de27245..7d6a4f3 100644 --- a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java +++ b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java @@ -66,7 +66,14 @@ public class IngredientsPopupCtrl { try { server.createIngredient(name); // calls POST /api/ingredients refresh(); // reload list from server - } catch (IOException | InterruptedException e) { + } catch (IOException e) { + if (e.getMessage() != null && e.getMessage().startsWith("DUPLICATE:")) { + showError("An ingredient with the name" + name + " already exists." + + " Please provide a different name."); + } else { + showError("Failed to create ingredient: " + e.getMessage()); + } + } catch (InterruptedException e){ showError("Failed to create ingredient: " + e.getMessage()); } } diff --git a/client/src/main/java/client/utils/server/ServerUtils.java b/client/src/main/java/client/utils/server/ServerUtils.java index 5330fdd..2d4bcc0 100644 --- a/client/src/main/java/client/utils/server/ServerUtils.java +++ b/client/src/main/java/client/utils/server/ServerUtils.java @@ -278,6 +278,11 @@ public class ServerUtils { .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 409) { + throw new IOException("An ingredient with the name '" + name + "' already exists."); + } + if (response.statusCode() != statusOK) { throw new IOException("Failed to create ingredient. Server responds with: " + response.body()); } From e5f7df7318326cab2286db34d2e2c1b930516684 Mon Sep 17 00:00:00 2001 From: Rithvik Sriram Date: Thu, 15 Jan 2026 16:35:31 +0100 Subject: [PATCH 2/5] Fixed pipeline issues and added comment --- .../java/client/scenes/recipe/IngredientsPopupCtrl.java | 5 +++-- client/src/main/java/client/utils/server/ServerUtils.java | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java index 7d6a4f3..203fb91 100644 --- a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java +++ b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java @@ -68,8 +68,9 @@ public class IngredientsPopupCtrl { refresh(); // reload list from server } catch (IOException e) { if (e.getMessage() != null && e.getMessage().startsWith("DUPLICATE:")) { - showError("An ingredient with the name" + name + " already exists." + - " Please provide a different name."); + showError("An ingredient with the name " + name + " already exists." + + " Please provide a different name."); //checks if error received has the DUPLICATE string and creates a showError instance with an appropriate error message and description + } else { showError("Failed to create ingredient: " + e.getMessage()); } diff --git a/client/src/main/java/client/utils/server/ServerUtils.java b/client/src/main/java/client/utils/server/ServerUtils.java index 2d4bcc0..3e2aa7e 100644 --- a/client/src/main/java/client/utils/server/ServerUtils.java +++ b/client/src/main/java/client/utils/server/ServerUtils.java @@ -278,9 +278,9 @@ public class ServerUtils { .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() == 409) { - throw new IOException("An ingredient with the name '" + name + "' already exists."); + final int DUPLICATE_STATUS_CODE = 409; + if (response.statusCode() == DUPLICATE_STATUS_CODE) { + throw new IOException("DUPLICATE: An ingredient with the name '" + name + "' already exists."); } if (response.statusCode() != statusOK) { From a1df0f5b24f6e9197f63b33048d033c98646b9a1 Mon Sep 17 00:00:00 2001 From: Rithvik Sriram Date: Fri, 16 Jan 2026 14:03:14 +0100 Subject: [PATCH 3/5] Made a Duplicate Exception class and made that be called instead for better robustness and consistency --- .../DuplicateIngredientException.java | 20 +++++++++++++++++++ .../scenes/Ingredient/IngredientListCtrl.java | 3 +++ .../scenes/recipe/IngredientsPopupCtrl.java | 16 +++++++-------- .../java/client/utils/server/ServerUtils.java | 5 +++-- 4 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 client/src/main/java/client/exception/DuplicateIngredientException.java diff --git a/client/src/main/java/client/exception/DuplicateIngredientException.java b/client/src/main/java/client/exception/DuplicateIngredientException.java new file mode 100644 index 0000000..af04346 --- /dev/null +++ b/client/src/main/java/client/exception/DuplicateIngredientException.java @@ -0,0 +1,20 @@ +package client.exception; + +public class DuplicateIngredientException extends Exception{ + private final String ingredientName; + + public DuplicateIngredientException(String ingredientName){ + super("An ingredient with name " + ingredientName + " already exists, please provide a different name"); + this.ingredientName = ingredientName; + } + + public DuplicateIngredientException(String ingredientName, String message){ + super(message); + this.ingredientName = ingredientName; + } + + public String getIngredientName() { + return ingredientName; + } + +} diff --git a/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java b/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java index 329eb56..38e6077 100644 --- a/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java +++ b/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java @@ -1,5 +1,6 @@ package client.scenes.Ingredient; +import client.exception.DuplicateIngredientException; import client.scenes.nutrition.NutritionDetailsCtrl; import client.utils.LocaleAware; import client.utils.LocaleManager; @@ -113,6 +114,8 @@ public class IngredientListCtrl implements LocaleAware { refresh(); // reload list from server } catch (IOException | InterruptedException e) { showError("Failed to create ingredient: " + e.getMessage()); + } catch (DuplicateIngredientException e) { + throw new RuntimeException(e); } } diff --git a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java index 203fb91..091befd 100644 --- a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java +++ b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java @@ -1,6 +1,7 @@ package client.scenes.recipe; import client.utils.server.ServerUtils; +import client.exception.DuplicateIngredientException; import commons.Ingredient; import jakarta.inject.Inject; import javafx.fxml.FXML; @@ -66,17 +67,16 @@ public class IngredientsPopupCtrl { try { server.createIngredient(name); // calls POST /api/ingredients refresh(); // reload list from server - } catch (IOException e) { - if (e.getMessage() != null && e.getMessage().startsWith("DUPLICATE:")) { - showError("An ingredient with the name " + name + " already exists." + - " Please provide a different name."); //checks if error received has the DUPLICATE string and creates a showError instance with an appropriate error message and description + } catch (IOException | InterruptedException e) { - } else { - showError("Failed to create ingredient: " + e.getMessage()); - } - } catch (InterruptedException e){ showError("Failed to create ingredient: " + e.getMessage()); + } catch (DuplicateIngredientException e) { + showError("An ingredient with the name " + name + " already exists." + + " Please provide a different name."); //checks if error received has the DUPLICATE string and creates a showError instance with an appropriate error message and description + } + + } diff --git a/client/src/main/java/client/utils/server/ServerUtils.java b/client/src/main/java/client/utils/server/ServerUtils.java index 3e2aa7e..c9a308d 100644 --- a/client/src/main/java/client/utils/server/ServerUtils.java +++ b/client/src/main/java/client/utils/server/ServerUtils.java @@ -1,6 +1,7 @@ package client.utils.server; import client.utils.ConfigService; +import client.exception.DuplicateIngredientException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.inject.Inject; @@ -270,7 +271,7 @@ public class ServerUtils { //creates new ingredients in the ingredient list - public Ingredient createIngredient(String name) throws IOException, InterruptedException { + public Ingredient createIngredient(String name) throws IOException, InterruptedException, DuplicateIngredientException { Ingredient ingredient = new Ingredient(name, 0.0, 0.0, 0.0); String json = objectMapper.writeValueAsString(ingredient); @@ -280,7 +281,7 @@ public class ServerUtils { HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); final int DUPLICATE_STATUS_CODE = 409; if (response.statusCode() == DUPLICATE_STATUS_CODE) { - throw new IOException("DUPLICATE: An ingredient with the name '" + name + "' already exists."); + throw new DuplicateIngredientException(name); } if (response.statusCode() != statusOK) { From cb4a93aeabbca4750752cc20f58750019657942c Mon Sep 17 00:00:00 2001 From: Rithvik Sriram Date: Thu, 22 Jan 2026 16:12:20 +0100 Subject: [PATCH 4/5] Fixed merge conflicts and rebased --- .../main/java/client/scenes/Ingredient/IngredientListCtrl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java b/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java index 38e6077..4fec975 100644 --- a/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java +++ b/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java @@ -122,7 +122,7 @@ public class IngredientListCtrl implements LocaleAware { @FXML private void refresh() { try { - List ingredients = server.getIngredients(); + List ingredients = server.getIngredients();g ingredientListView.getItems().setAll(ingredients); } catch (IOException | InterruptedException e) { showError("Failed to load ingredients: " + e.getMessage()); From 22dd603746f959cc8bb3a2e5b0ac70145106f350 Mon Sep 17 00:00:00 2001 From: Rithvik Sriram Date: Thu, 22 Jan 2026 16:12:58 +0100 Subject: [PATCH 5/5] stray typo fix --- .../main/java/client/scenes/Ingredient/IngredientListCtrl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java b/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java index 4fec975..38e6077 100644 --- a/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java +++ b/client/src/main/java/client/scenes/Ingredient/IngredientListCtrl.java @@ -122,7 +122,7 @@ public class IngredientListCtrl implements LocaleAware { @FXML private void refresh() { try { - List ingredients = server.getIngredients();g + List ingredients = server.getIngredients(); ingredientListView.getItems().setAll(ingredients); } catch (IOException | InterruptedException e) { showError("Failed to load ingredients: " + e.getMessage());