Merge branch 'feature/add-duplicate-error-message' into 'main'

Added a special warning message when user tries to add duplicate ingredients

See merge request cse1105/2025-2026/teams/csep-team-76!58
This commit is contained in:
Zhongheng Liu 2026-01-22 19:03:01 +01:00
commit 143b73c23f
5 changed files with 50 additions and 8 deletions

View file

@ -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;
}
}

View file

@ -534,13 +534,18 @@ public class FoodpalApplicationCtrl implements LocaleAware {
// Wait for the user to enter a value // Wait for the user to enter a value
Optional<String> result = dialog.showAndWait(); Optional<String> result = dialog.showAndWait();
result.ifPresent(name -> { result.ifPresent(recipeName ->{
// Create a new Ingredient object String trim = recipeName.trim();
Ingredient newIngredient = new Ingredient(); if(trim.isEmpty()){
newIngredient.setName(name); showError("Invalid Input", "Cannot have empty ingredient name");
return;
// Add the new ingredient to the ListView }
ingredientListView.getItems().add(newIngredient); if(ingredientListView.getItems().stream()
.map(Ingredient::getName)
.anyMatch(ingName -> ingName.equalsIgnoreCase(trim))){
showError("Duplicate Ingredient", "Cannot have duplicate ingredients," +
" Please provide unique Ingredient names");
}
}); });
} }

View file

@ -1,5 +1,6 @@
package client.scenes.Ingredient; package client.scenes.Ingredient;
import client.exception.DuplicateIngredientException;
import client.scenes.nutrition.NutritionDetailsCtrl; import client.scenes.nutrition.NutritionDetailsCtrl;
import client.utils.LocaleAware; import client.utils.LocaleAware;
import client.utils.LocaleManager; import client.utils.LocaleManager;
@ -113,6 +114,8 @@ public class IngredientListCtrl implements LocaleAware {
refresh(); // reload list from server refresh(); // reload list from server
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
showError("Failed to create ingredient: " + e.getMessage()); showError("Failed to create ingredient: " + e.getMessage());
} catch (DuplicateIngredientException e) {
throw new RuntimeException(e);
} }
} }

View file

@ -1,6 +1,7 @@
package client.scenes.recipe; package client.scenes.recipe;
import client.utils.server.ServerUtils; import client.utils.server.ServerUtils;
import client.exception.DuplicateIngredientException;
import commons.Ingredient; import commons.Ingredient;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -67,8 +68,15 @@ public class IngredientsPopupCtrl {
server.createIngredient(name); // calls POST /api/ingredients server.createIngredient(name); // calls POST /api/ingredients
refresh(); // reload list from server refresh(); // reload list from server
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
showError("Failed to create ingredient: " + e.getMessage()); 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
} }
} }

View file

@ -1,6 +1,7 @@
package client.utils.server; package client.utils.server;
import client.utils.ConfigService; import client.utils.ConfigService;
import client.exception.DuplicateIngredientException;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -267,7 +268,7 @@ public class ServerUtils {
//creates new ingredients in the ingredient list //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); Ingredient ingredient = new Ingredient(name, 0.0, 0.0, 0.0);
String json = objectMapper.writeValueAsString(ingredient); String json = objectMapper.writeValueAsString(ingredient);
@ -275,6 +276,11 @@ public class ServerUtils {
.build(); .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
final int DUPLICATE_STATUS_CODE = 409;
if (response.statusCode() == DUPLICATE_STATUS_CODE) {
throw new DuplicateIngredientException(name);
}
if (response.statusCode() != statusOK) { if (response.statusCode() != statusOK) {
throw new IOException("Failed to create ingredient. Server responds with: " + response.body()); throw new IOException("Failed to create ingredient. Server responds with: " + response.body());
} }