refactor: newest delivery from main
This commit is contained in:
commit
00e4bb03f4
32 changed files with 722 additions and 881 deletions
|
|
@ -34,21 +34,25 @@
|
||||||
<artifactId>jersey-client</artifactId>
|
<artifactId>jersey-client</artifactId>
|
||||||
<version>${version.jersey}</version>
|
<version>${version.jersey}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.glassfish.jersey.inject</groupId>
|
<groupId>org.glassfish.jersey.inject</groupId>
|
||||||
<artifactId>jersey-hk2</artifactId>
|
<artifactId>jersey-hk2</artifactId>
|
||||||
<version>${version.jersey}</version>
|
<version>${version.jersey}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.glassfish.jersey.media</groupId>
|
<groupId>org.glassfish.jersey.media</groupId>
|
||||||
<artifactId>jersey-media-json-jackson</artifactId>
|
<artifactId>jersey-media-json-jackson</artifactId>
|
||||||
<version>${version.jersey}</version>
|
<version>${version.jersey}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.activation</groupId>
|
<groupId>jakarta.activation</groupId>
|
||||||
<artifactId>jakarta.activation-api</artifactId>
|
<artifactId>jakarta.activation-api</artifactId>
|
||||||
<version>2.1.3</version>
|
<version>2.1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.inject</groupId>
|
<groupId>com.google.inject</groupId>
|
||||||
<artifactId>guice</artifactId>
|
<artifactId>guice</artifactId>
|
||||||
|
|
@ -61,11 +65,13 @@
|
||||||
<artifactId>javafx-fxml</artifactId>
|
<artifactId>javafx-fxml</artifactId>
|
||||||
<version>${version.jfx}</version>
|
<version>${version.jfx}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-controls</artifactId>
|
<artifactId>javafx-controls</artifactId>
|
||||||
<version>${version.jfx}</version>
|
<version>${version.jfx}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-web</artifactId>
|
<artifactId>javafx-web</artifactId>
|
||||||
|
|
@ -91,6 +97,27 @@
|
||||||
<version>${version.mockito}</version>
|
<version>${version.mockito}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- websockets -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-messaging</artifactId>
|
||||||
|
<version>6.2.12</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.glassfish.tyrus.bundles/tyrus-standalone-client -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.tyrus.bundles</groupId>
|
||||||
|
<artifactId>tyrus-standalone-client</artifactId>
|
||||||
|
<version>2.2.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-websocket</artifactId>
|
||||||
|
<version>6.2.12</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,18 @@ package client;
|
||||||
import client.scenes.FoodpalApplicationCtrl;
|
import client.scenes.FoodpalApplicationCtrl;
|
||||||
import client.scenes.recipe.IngredientListCtrl;
|
import client.scenes.recipe.IngredientListCtrl;
|
||||||
import client.scenes.recipe.RecipeStepListCtrl;
|
import client.scenes.recipe.RecipeStepListCtrl;
|
||||||
|
import client.utils.ConfigService;
|
||||||
import client.utils.LocaleManager;
|
import client.utils.LocaleManager;
|
||||||
|
import client.utils.ServerUtils;
|
||||||
|
import client.utils.WebSocketUtils;
|
||||||
import com.google.inject.Binder;
|
import com.google.inject.Binder;
|
||||||
import com.google.inject.Module;
|
import com.google.inject.Module;
|
||||||
import com.google.inject.Scopes;
|
import com.google.inject.Scopes;
|
||||||
|
|
||||||
import client.scenes.MainCtrl;
|
import client.scenes.MainCtrl;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
public class MyModule implements Module {
|
public class MyModule implements Module {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -33,6 +38,12 @@ public class MyModule implements Module {
|
||||||
binder.bind(FoodpalApplicationCtrl.class).in(Scopes.SINGLETON);
|
binder.bind(FoodpalApplicationCtrl.class).in(Scopes.SINGLETON);
|
||||||
binder.bind(IngredientListCtrl.class).in(Scopes.SINGLETON);
|
binder.bind(IngredientListCtrl.class).in(Scopes.SINGLETON);
|
||||||
binder.bind(RecipeStepListCtrl.class).in(Scopes.SINGLETON);
|
binder.bind(RecipeStepListCtrl.class).in(Scopes.SINGLETON);
|
||||||
|
|
||||||
binder.bind(LocaleManager.class).in(Scopes.SINGLETON);
|
binder.bind(LocaleManager.class).in(Scopes.SINGLETON);
|
||||||
|
binder.bind(ServerUtils.class).in(Scopes.SINGLETON);
|
||||||
|
binder.bind(WebSocketUtils.class).in(Scopes.SINGLETON);
|
||||||
|
|
||||||
|
binder.bind(ConfigService.class).toInstance(new ConfigService(Path.of("config.json")));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,17 +9,22 @@ import client.exception.UpdateException;
|
||||||
import client.scenes.recipe.IngredientListCtrl;
|
import client.scenes.recipe.IngredientListCtrl;
|
||||||
import client.scenes.recipe.RecipeStepListCtrl;
|
import client.scenes.recipe.RecipeStepListCtrl;
|
||||||
|
|
||||||
|
import client.utils.Config;
|
||||||
|
import client.utils.ConfigService;
|
||||||
import client.utils.DefaultRecipeFactory;
|
import client.utils.DefaultRecipeFactory;
|
||||||
import client.utils.LocaleAware;
|
import client.utils.LocaleAware;
|
||||||
import client.utils.LocaleManager;
|
import client.utils.LocaleManager;
|
||||||
import client.utils.ServerUtils;
|
import client.utils.ServerUtils;
|
||||||
|
import client.utils.WebSocketUtils;
|
||||||
import commons.Recipe;
|
import commons.Recipe;
|
||||||
|
|
||||||
|
import commons.ws.Topics;
|
||||||
|
import commons.ws.messages.Message;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ComboBox;
|
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
|
|
@ -31,6 +36,7 @@ import javafx.scene.text.Font;
|
||||||
|
|
||||||
public class FoodpalApplicationCtrl implements LocaleAware {
|
public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
private final ServerUtils server;
|
private final ServerUtils server;
|
||||||
|
private final WebSocketUtils webSocketUtils;
|
||||||
private final LocaleManager localeManager;
|
private final LocaleManager localeManager;
|
||||||
private final IngredientListCtrl ingredientListCtrl;
|
private final IngredientListCtrl ingredientListCtrl;
|
||||||
private final RecipeStepListCtrl stepListCtrl;
|
private final RecipeStepListCtrl stepListCtrl;
|
||||||
|
|
@ -41,10 +47,9 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
// everything in the left lane
|
// everything in the left lane
|
||||||
@FXML
|
@FXML
|
||||||
public Label recipesLabel;
|
public Label recipesLabel;
|
||||||
public ComboBox<String> langSelectMenu;
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<Recipe> recipeList;
|
public ListView<Recipe> recipeList;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Button addRecipeButton;
|
private Button addRecipeButton;
|
||||||
|
|
@ -55,6 +60,13 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
@FXML
|
@FXML
|
||||||
public Button cloneRecipeButton;
|
public Button cloneRecipeButton;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Button favouriteButton;
|
||||||
|
|
||||||
|
private Config config;
|
||||||
|
private final ConfigService configService;
|
||||||
|
|
||||||
|
|
||||||
// === CENTER: RECIPE DETAILS ===
|
// === CENTER: RECIPE DETAILS ===
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
|
@ -69,14 +81,20 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
@Inject
|
@Inject
|
||||||
public FoodpalApplicationCtrl(
|
public FoodpalApplicationCtrl(
|
||||||
ServerUtils server,
|
ServerUtils server,
|
||||||
|
WebSocketUtils webSocketUtils,
|
||||||
LocaleManager localeManager,
|
LocaleManager localeManager,
|
||||||
IngredientListCtrl ingredientListCtrl,
|
IngredientListCtrl ingredientListCtrl,
|
||||||
RecipeStepListCtrl stepListCtrl
|
RecipeStepListCtrl stepListCtrl,
|
||||||
|
ConfigService configService
|
||||||
) {
|
) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
this.webSocketUtils = webSocketUtils;
|
||||||
this.localeManager = localeManager;
|
this.localeManager = localeManager;
|
||||||
this.ingredientListCtrl = ingredientListCtrl;
|
this.ingredientListCtrl = ingredientListCtrl;
|
||||||
this.stepListCtrl = stepListCtrl;
|
this.stepListCtrl = stepListCtrl;
|
||||||
|
this.configService = configService;
|
||||||
|
|
||||||
|
initializeWebSocket();
|
||||||
}
|
}
|
||||||
private void initRecipeList() {
|
private void initRecipeList() {
|
||||||
// Show recipe name in the list
|
// Show recipe name in the list
|
||||||
|
|
@ -87,10 +105,12 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
setText(empty || item == null ? "" : item.getName());
|
setText(empty || item == null ? "" : item.getName());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// When your selection changes, update details in the panel
|
// When your selection changes, update details in the panel
|
||||||
recipeList.getSelectionModel().selectedItemProperty().addListener(
|
recipeList.getSelectionModel().selectedItemProperty().addListener(
|
||||||
(obs, oldRecipe, newRecipe) -> showRecipeDetails(newRecipe)
|
(obs, oldRecipe, newRecipe) -> {
|
||||||
|
showRecipeDetails(newRecipe);
|
||||||
|
updateFavouriteButton(newRecipe);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Double-click to go to detail screen
|
// Double-click to go to detail screen
|
||||||
|
|
@ -101,6 +121,27 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
private void initializeWebSocket() {
|
||||||
|
webSocketUtils.connect(() -> {
|
||||||
|
webSocketUtils.subscribe(Topics.RECIPES, (Message _) -> {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
Recipe selectedRecipe = recipeList.getSelectionModel().getSelectedItem();
|
||||||
|
refresh(); // refresh the left list
|
||||||
|
if (selectedRecipe == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// select last selected recipe if it still exists, first otherwise (done by refresh())
|
||||||
|
Recipe recipeInList = recipeList.getItems().stream()
|
||||||
|
.filter(r -> r.getId().equals(selectedRecipe.getId()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
showRecipeDetails(recipeInList);
|
||||||
|
}); // runLater as it's on another non-FX thread.
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
private void initStepsIngredientsList() {
|
private void initStepsIngredientsList() {
|
||||||
// Initialize callback for ingredient list updates
|
// Initialize callback for ingredient list updates
|
||||||
this.ingredientListCtrl.setUpdateCallback(newList -> {
|
this.ingredientListCtrl.setUpdateCallback(newList -> {
|
||||||
|
|
@ -134,12 +175,14 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void initializeComponents() {
|
public void initializeComponents() {
|
||||||
// TODO Reduce code duplication??
|
config = configService.getConfig();
|
||||||
|
|
||||||
initStepsIngredientsList();
|
initStepsIngredientsList();
|
||||||
initRecipeList();
|
initRecipeList();
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
|
updateFavouriteButton(recipeList.getSelectionModel().getSelectedItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showName(String name) {
|
private void showName(String name) {
|
||||||
final int NAME_FONT_SIZE = 20;
|
final int NAME_FONT_SIZE = 20;
|
||||||
editableTitleArea.getChildren().clear();
|
editableTitleArea.getChildren().clear();
|
||||||
|
|
@ -147,6 +190,7 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
nameLabel.setFont(new Font("System Bold", NAME_FONT_SIZE));
|
nameLabel.setFont(new Font("System Bold", NAME_FONT_SIZE));
|
||||||
editableTitleArea.getChildren().add(nameLabel);
|
editableTitleArea.getChildren().add(nameLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateText() {
|
public void updateText() {
|
||||||
addRecipeButton.setText(getLocaleString("menu.button.add.recipe"));
|
addRecipeButton.setText(getLocaleString("menu.button.add.recipe"));
|
||||||
|
|
@ -158,13 +202,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
printRecipeButton.setText(getLocaleString("menu.button.print"));
|
printRecipeButton.setText(getLocaleString("menu.button.print"));
|
||||||
|
|
||||||
recipesLabel.setText(getLocaleString("menu.label.recipes"));
|
recipesLabel.setText(getLocaleString("menu.label.recipes"));
|
||||||
|
|
||||||
// TODO propagate ResourceBundle lang changes to nested controller
|
|
||||||
// ingredientsLabel.setText(getLocaleString("menu.label.ingredients"));
|
|
||||||
// preparationLabel.setText(getLocaleString("menu.label.preparation"));
|
|
||||||
|
|
||||||
// addIngredientButton.setText(getLocaleString("menu.button.add.ingredient"));
|
|
||||||
// addPreparationStepButton.setText(getLocaleString("menu.button.add.step"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -200,11 +237,13 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
}
|
}
|
||||||
detailsScreen.visibleProperty().set(!recipes.isEmpty());
|
detailsScreen.visibleProperty().set(!recipes.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printError(String msg) {
|
private void printError(String msg) {
|
||||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
alert.setContentText(msg);
|
alert.setContentText(msg);
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a recipe, by providing a default name "Untitled recipe (n)".
|
* Adds a recipe, by providing a default name "Untitled recipe (n)".
|
||||||
* The UX flow is now:
|
* The UX flow is now:
|
||||||
|
|
@ -277,7 +316,7 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
try {
|
try {
|
||||||
server.updateRecipe(selected);
|
server.updateRecipe(selected);
|
||||||
refresh();
|
refresh();
|
||||||
recipeList.getSelectionModel().select(selected);
|
//recipeList.getSelectionModel().select(selected);
|
||||||
} catch (IOException | InterruptedException e) {
|
} catch (IOException | InterruptedException e) {
|
||||||
// throw a nice blanket UpdateException
|
// throw a nice blanket UpdateException
|
||||||
throw new UpdateException("Error occurred when updating recipe name!");
|
throw new UpdateException("Error occurred when updating recipe name!");
|
||||||
|
|
@ -287,7 +326,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
editableTitleArea.getChildren().add(edit);
|
editableTitleArea.getChildren().add(edit);
|
||||||
edit.requestFocus();
|
edit.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void makePrintable() {
|
private void makePrintable() {
|
||||||
System.out.println("Recipe printed");
|
System.out.println("Recipe printed");
|
||||||
|
|
@ -307,6 +345,39 @@ public class FoodpalApplicationCtrl implements LocaleAware {
|
||||||
recipeList.getSelectionModel().select(cloned);
|
recipeList.getSelectionModel().select(cloned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateFavouriteButton(Recipe recipe) {
|
||||||
|
if (recipe == null) {
|
||||||
|
favouriteButton.setDisable(true);
|
||||||
|
favouriteButton.setText("☆");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
favouriteButton.setDisable(false);
|
||||||
|
favouriteButton.setText(
|
||||||
|
config.isFavourite(recipe.getId()) ? "★" : "☆"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void toggleFavourite() {
|
||||||
|
Recipe selected = recipeList.getSelectionModel().getSelectedItem();
|
||||||
|
if (selected == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long id = selected.getId();
|
||||||
|
|
||||||
|
if (config.isFavourite(id)) {
|
||||||
|
config.removeFavourite(id);
|
||||||
|
} else {
|
||||||
|
config.addFavourite(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
configService.save();
|
||||||
|
updateFavouriteButton(selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package client.scenes.nutrition;
|
||||||
|
|
||||||
|
import client.utils.LocaleAware;
|
||||||
|
import client.utils.LocaleManager;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
|
|
||||||
|
public class NutritionDetailsCtrl implements LocaleAware {
|
||||||
|
private final LocaleManager manager;
|
||||||
|
|
||||||
|
public Label ingredientName;
|
||||||
|
public Label fatInputLabel;
|
||||||
|
public Label proteinInputLabel;
|
||||||
|
public Label carbInputLabel;
|
||||||
|
public Label estimatedKcalLabel;
|
||||||
|
public Label usageLabel;
|
||||||
|
|
||||||
|
public TextField fatInputElement;
|
||||||
|
public TextField proteinInputElement;
|
||||||
|
public TextField carbInputElement;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public NutritionDetailsCtrl(
|
||||||
|
LocaleManager manager
|
||||||
|
) {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void updateText() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocaleManager getLocaleManager() {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package client.scenes.nutrition;
|
||||||
|
|
||||||
|
import client.scenes.FoodpalApplicationCtrl;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import commons.Recipe;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.scene.control.ListView;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class NutritionViewCtrl {
|
||||||
|
private ObservableList<Recipe> recipes;
|
||||||
|
private HashMap<String, Integer> ingredientStats;
|
||||||
|
public ListView<String> nutritionIngredientsView;
|
||||||
|
private final NutritionDetailsCtrl nutritionDetailsCtrl;
|
||||||
|
|
||||||
|
// TODO into Ingredient class definition
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comedically verbose function to count unique appearances of an ingredient by name in each recipe.
|
||||||
|
* For each recipe:
|
||||||
|
* 1. Collect unique ingredients that appeared in that recipe.
|
||||||
|
* 2. For each unique ingredient in said recipe:
|
||||||
|
* 1. Initialize the appearance for that ingredient to 0.
|
||||||
|
* 2. For each recipe in list:
|
||||||
|
* 1. If the name of the ingredient exists in the recipe list, increment the statistic by 1.
|
||||||
|
* 2. Else maintain the same value for that statistic.
|
||||||
|
* @param recipeList
|
||||||
|
*/
|
||||||
|
private void updateIngredientStats(
|
||||||
|
List<Recipe> recipeList
|
||||||
|
) {
|
||||||
|
recipeList.forEach(recipe -> {
|
||||||
|
Set<String> uniqueIngredients = new HashSet<>(recipe.getIngredients());
|
||||||
|
nutritionIngredientsView.getItems().setAll(uniqueIngredients);
|
||||||
|
uniqueIngredients.forEach(ingredient -> {
|
||||||
|
ingredientStats.put(ingredient, 0);
|
||||||
|
recipeList.forEach(r ->
|
||||||
|
ingredientStats.put(
|
||||||
|
ingredient,
|
||||||
|
ingredientStats.get(ingredient) + (
|
||||||
|
(r.getIngredients().contains(ingredient))
|
||||||
|
? 1 : 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@Inject
|
||||||
|
public NutritionViewCtrl(
|
||||||
|
FoodpalApplicationCtrl foodpalApplicationCtrl,
|
||||||
|
NutritionDetailsCtrl nutritionDetailsCtrl
|
||||||
|
) {
|
||||||
|
this.recipes = foodpalApplicationCtrl.recipeList.getItems();
|
||||||
|
this.recipes.addListener((ListChangeListener<? super Recipe>) _ -> {
|
||||||
|
updateIngredientStats(this.recipes);
|
||||||
|
});
|
||||||
|
this.nutritionDetailsCtrl = nutritionDetailsCtrl;
|
||||||
|
this.nutritionIngredientsView.selectionModelProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,8 @@ public class Config {
|
||||||
private List<Long> favourites = new ArrayList<>();
|
private List<Long> favourites = new ArrayList<>();
|
||||||
private List<String> shoppingList = new ArrayList<>();
|
private List<String> shoppingList = new ArrayList<>();
|
||||||
|
|
||||||
public Config(){}
|
public Config() {
|
||||||
|
}
|
||||||
|
|
||||||
public String getLanguage() {
|
public String getLanguage() {
|
||||||
return language;
|
return language;
|
||||||
|
|
@ -22,10 +23,6 @@ public class Config {
|
||||||
return shoppingList;
|
return shoppingList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getFavourites() {
|
|
||||||
return favourites;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getServerUrl() {
|
public String getServerUrl() {
|
||||||
return serverUrl;
|
return serverUrl;
|
||||||
}
|
}
|
||||||
|
|
@ -45,4 +42,29 @@ public class Config {
|
||||||
public void setShoppingList(List<String> shoppingList) {
|
public void setShoppingList(List<String> shoppingList) {
|
||||||
this.shoppingList = shoppingList;
|
this.shoppingList = shoppingList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// favourite helper
|
||||||
|
|
||||||
|
public List<Long> getFavourites() {
|
||||||
|
if (favourites == null) {
|
||||||
|
favourites = new ArrayList<>();
|
||||||
|
}
|
||||||
|
return favourites;
|
||||||
|
}
|
||||||
|
// to avoid null pointers.
|
||||||
|
|
||||||
|
public boolean isFavourite(long recipeId) {
|
||||||
|
return getFavourites().contains(recipeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFavourite(long recipeId) {
|
||||||
|
if (!getFavourites().contains(recipeId)) {
|
||||||
|
getFavourites().add(recipeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFavourite(long recipeId) {
|
||||||
|
getFavourites().remove(recipeId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Delft University of Technology
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package client.utils;
|
|
||||||
|
|
||||||
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
|
|
||||||
|
|
||||||
import java.net.ConnectException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import jakarta.ws.rs.core.GenericType;
|
|
||||||
import org.glassfish.jersey.client.ClientConfig;
|
|
||||||
|
|
||||||
import commons.Quote;
|
|
||||||
import jakarta.ws.rs.ProcessingException;
|
|
||||||
import jakarta.ws.rs.client.ClientBuilder;
|
|
||||||
import jakarta.ws.rs.client.Entity;
|
|
||||||
|
|
||||||
public class ServerUtilsExample {
|
|
||||||
|
|
||||||
private static final String SERVER = "http://localhost:8080/";
|
|
||||||
|
|
||||||
// public void getQuotesTheHardWay() throws IOException, URISyntaxException {
|
|
||||||
// var url = new URI("http://localhost:8080/api/quotes").toURL();
|
|
||||||
// var is = url.openConnection().getInputStream();
|
|
||||||
// var br = new BufferedReader(new InputStreamReader(is));
|
|
||||||
// String line;
|
|
||||||
// while ((line = br.readLine()) != null) {
|
|
||||||
// System.out.println(line);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
public List<Quote> getQuotes() {
|
|
||||||
return ClientBuilder.newClient(new ClientConfig()) //
|
|
||||||
.target(SERVER).path("api/quotes") //
|
|
||||||
.request(APPLICATION_JSON) //
|
|
||||||
.get(new GenericType<List<Quote>>() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Quote addQuote(Quote quote) {
|
|
||||||
return ClientBuilder.newClient(new ClientConfig()) //
|
|
||||||
.target(SERVER).path("api/quotes") //
|
|
||||||
.request(APPLICATION_JSON) //
|
|
||||||
.post(Entity.entity(quote, APPLICATION_JSON), Quote.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isServerAvailable() {
|
|
||||||
try {
|
|
||||||
ClientBuilder.newClient(new ClientConfig()) //
|
|
||||||
.target(SERVER) //
|
|
||||||
.request(APPLICATION_JSON) //
|
|
||||||
.get();
|
|
||||||
} catch (ProcessingException e) {
|
|
||||||
if (e.getCause() instanceof ConnectException) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
111
client/src/main/java/client/utils/WebSocketUtils.java
Normal file
111
client/src/main/java/client/utils/WebSocketUtils.java
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
package client.utils;
|
||||||
|
|
||||||
|
import commons.ws.messages.Message;
|
||||||
|
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
||||||
|
import org.springframework.messaging.simp.stomp.StompSession;
|
||||||
|
import org.springframework.messaging.simp.stomp.StompHeaders;
|
||||||
|
import org.springframework.messaging.simp.stomp.StompCommand;
|
||||||
|
import org.springframework.messaging.simp.stomp.StompFrameHandler;
|
||||||
|
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
|
||||||
|
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
|
||||||
|
import org.springframework.web.socket.messaging.WebSocketStompClient;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public class WebSocketUtils {
|
||||||
|
private static final String WS_URL = "ws://localhost:8080/updates";
|
||||||
|
private WebSocketStompClient stompClient;
|
||||||
|
private StompSession stompSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to the websocket server.
|
||||||
|
* @param onConnected OnConnected callback
|
||||||
|
*/
|
||||||
|
public void connect(@Nullable Runnable onConnected) {
|
||||||
|
StandardWebSocketClient webSocketClient = new StandardWebSocketClient(); // Create WS Client
|
||||||
|
|
||||||
|
stompClient = new WebSocketStompClient(webSocketClient);
|
||||||
|
stompClient.setMessageConverter(new MappingJackson2MessageConverter()); // Use jackson
|
||||||
|
|
||||||
|
CompletableFuture<StompSession> sessionFuture = stompClient.connectAsync(
|
||||||
|
WS_URL,
|
||||||
|
new StompSessionHandlerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
|
||||||
|
stompSession = session;
|
||||||
|
System.out.println("WebSocket connected: " + session.getSessionId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleException(StompSession session, @Nullable StompCommand command,
|
||||||
|
StompHeaders headers, byte[] payload,
|
||||||
|
Throwable exception) {
|
||||||
|
System.err.println("STOMP error: " + exception.getMessage());
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleTransportError(StompSession session, Throwable exception) {
|
||||||
|
System.err.println("STOMP transport error: " + exception.getMessage());
|
||||||
|
exception.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sessionFuture.thenAccept(session -> {
|
||||||
|
stompSession = session;
|
||||||
|
System.out.println("Connection successful, session ready");
|
||||||
|
if (onConnected != null) {
|
||||||
|
onConnected.run();
|
||||||
|
}
|
||||||
|
}).exceptionally(throwable -> {
|
||||||
|
System.err.println("Failed to connect: " + throwable.getMessage());
|
||||||
|
throwable.printStackTrace();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to a topic.
|
||||||
|
* @param destination Destination to subscribe to, for example: /subscribe/recipe
|
||||||
|
* @param messageHandler Handler for received messages
|
||||||
|
*/
|
||||||
|
public void subscribe(String destination, Consumer<Message> messageHandler) {
|
||||||
|
if (stompSession == null || !stompSession.isConnected()) {
|
||||||
|
System.err.println("Cannot subscribe - not connected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stompSession.subscribe(destination, new StompFrameHandler() {
|
||||||
|
@Override
|
||||||
|
public Type getPayloadType(StompHeaders headers) {
|
||||||
|
return Message.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleFrame(StompHeaders headers, @Nullable Object payload) {
|
||||||
|
Message message = (Message) payload;
|
||||||
|
messageHandler.accept(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
System.out.println("Subscribed to: " + destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() {
|
||||||
|
if (stompSession != null && stompSession.isConnected()) {
|
||||||
|
stompSession.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stompClient != null) {
|
||||||
|
stompClient.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return stompSession != null && stompSession.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -69,6 +69,7 @@
|
||||||
<Button fx:id="editRecipeTitleButton" onAction="#editRecipeTitle" text="Edit" />
|
<Button fx:id="editRecipeTitleButton" onAction="#editRecipeTitle" text="Edit" />
|
||||||
<Button fx:id="removeRecipeButton2" mnemonicParsing="false" onAction="#removeSelectedRecipe" text="Remove Recipe" />
|
<Button fx:id="removeRecipeButton2" mnemonicParsing="false" onAction="#removeSelectedRecipe" text="Remove Recipe" />
|
||||||
<Button fx:id="printRecipeButton" mnemonicParsing="false" onAction="#makePrintable" text="Print Recipe" />
|
<Button fx:id="printRecipeButton" mnemonicParsing="false" onAction="#makePrintable" text="Print Recipe" />
|
||||||
|
<Button fx:id="favouriteButton" onAction="#toggleFavourite" text="☆" />
|
||||||
</HBox>
|
</HBox>
|
||||||
|
|
||||||
<!-- Ingredients -->
|
<!-- Ingredients -->
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import java.util.*?>
|
||||||
|
<?import javafx.scene.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
<?import javafx.scene.shape.Line?>
|
||||||
|
<AnchorPane xmlns="http://javafx.com/javafx"
|
||||||
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
|
fx:controller="client.scenes.nutrition.NutritionDetailsCtrl"
|
||||||
|
prefHeight="400.0" prefWidth="600.0">
|
||||||
|
<VBox visible="false">
|
||||||
|
<Label fx:id="ingredientName" />
|
||||||
|
<HBox>
|
||||||
|
<Label fx:id="fatInputLabel">Fat: </Label>
|
||||||
|
<TextField fx:id="fatInputElement" />
|
||||||
|
</HBox>
|
||||||
|
<HBox>
|
||||||
|
<Label fx:id="proteinInputLabel">Protein: </Label>
|
||||||
|
<TextField fx:id="proteinInputElement" />
|
||||||
|
</HBox>
|
||||||
|
<HBox>
|
||||||
|
<Label fx:id="carbInputLabel">Carbohydrates: </Label>
|
||||||
|
<TextField fx:id="carbInputElement" />
|
||||||
|
</HBox>
|
||||||
|
<Label fx:id="estimatedKcalLabel">Estimated: 0kcal</Label>
|
||||||
|
<Label fx:id="usageLabel">Not used in any recipes</Label>
|
||||||
|
</VBox>
|
||||||
|
|
||||||
|
</AnchorPane>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import java.lang.*?>
|
||||||
|
<?import java.util.*?>
|
||||||
|
<?import javafx.scene.*?>
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
<AnchorPane xmlns="http://javafx.com/javafx"
|
||||||
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
|
fx:controller="client.scenes.nutrition.NutritionViewCtrl"
|
||||||
|
prefHeight="400.0" prefWidth="600.0">
|
||||||
|
<SplitPane>
|
||||||
|
<ListView fx:id="nutritionIngredientsView" />
|
||||||
|
<AnchorPane>
|
||||||
|
<fx:include source="NutritionDetails.fxml" />
|
||||||
|
</AnchorPane>
|
||||||
|
</SplitPane>
|
||||||
|
</AnchorPane>
|
||||||
|
|
@ -45,6 +45,12 @@
|
||||||
<version>${version.mockito}</version>
|
<version>${version.mockito}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.20.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Delft University of Technology
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package commons;
|
|
||||||
|
|
||||||
import static org.apache.commons.lang3.builder.ToStringStyle.MULTI_LINE_STYLE;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.GeneratedValue;
|
|
||||||
import jakarta.persistence.GenerationType;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
public class Person {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
|
||||||
public long id;
|
|
||||||
|
|
||||||
public String firstName;
|
|
||||||
public String lastName;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private Person() {
|
|
||||||
// for object mapper
|
|
||||||
}
|
|
||||||
|
|
||||||
public Person(String firstName, String lastName) {
|
|
||||||
this.firstName = firstName;
|
|
||||||
this.lastName = lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return EqualsBuilder.reflectionEquals(this, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return HashCodeBuilder.reflectionHashCode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return ToStringBuilder.reflectionToString(this, MULTI_LINE_STYLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Delft University of Technology
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package commons;
|
|
||||||
|
|
||||||
import static org.apache.commons.lang3.builder.ToStringStyle.MULTI_LINE_STYLE;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.GeneratedValue;
|
|
||||||
import jakarta.persistence.GenerationType;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.OneToOne;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
public class Quote {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
|
||||||
public long id;
|
|
||||||
|
|
||||||
@OneToOne(cascade = CascadeType.PERSIST)
|
|
||||||
public Person person;
|
|
||||||
public String quote;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private Quote() {
|
|
||||||
// for object mappers
|
|
||||||
}
|
|
||||||
|
|
||||||
public Quote(Person person, String quote) {
|
|
||||||
this.person = person;
|
|
||||||
this.quote = quote;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return EqualsBuilder.reflectionEquals(this, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return HashCodeBuilder.reflectionHashCode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return ToStringBuilder.reflectionToString(this, MULTI_LINE_STYLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -10,6 +10,8 @@ import commons.Ingredient;
|
||||||
public class CreateIngredientMessage implements Message {
|
public class CreateIngredientMessage implements Message {
|
||||||
private Ingredient ingredient;
|
private Ingredient ingredient;
|
||||||
|
|
||||||
|
public CreateIngredientMessage() {} // for jackson
|
||||||
|
|
||||||
public CreateIngredientMessage(Ingredient ingredient) {
|
public CreateIngredientMessage(Ingredient ingredient) {
|
||||||
this.ingredient = ingredient;
|
this.ingredient = ingredient;
|
||||||
}
|
}
|
||||||
|
|
@ -27,4 +29,9 @@ public class CreateIngredientMessage implements Message {
|
||||||
public Ingredient getIngredient() {
|
public Ingredient getIngredient() {
|
||||||
return ingredient;
|
return ingredient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for jackson
|
||||||
|
public void setIngredient(Ingredient ingredient) {
|
||||||
|
this.ingredient = ingredient;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import commons.Recipe;
|
||||||
public class CreateRecipeMessage implements Message {
|
public class CreateRecipeMessage implements Message {
|
||||||
private Recipe recipe;
|
private Recipe recipe;
|
||||||
|
|
||||||
|
public CreateRecipeMessage() {} // for jackson
|
||||||
|
|
||||||
public CreateRecipeMessage(Recipe recipe) {
|
public CreateRecipeMessage(Recipe recipe) {
|
||||||
this.recipe = recipe;
|
this.recipe = recipe;
|
||||||
}
|
}
|
||||||
|
|
@ -27,4 +29,9 @@ public class CreateRecipeMessage implements Message {
|
||||||
public Recipe getRecipe() {
|
public Recipe getRecipe() {
|
||||||
return recipe;
|
return recipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for jackson
|
||||||
|
public void setRecipe(Recipe recipe) {
|
||||||
|
this.recipe = recipe;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ package commons.ws.messages;
|
||||||
public class DeleteIngredientMessage implements Message {
|
public class DeleteIngredientMessage implements Message {
|
||||||
private Long ingredientId;
|
private Long ingredientId;
|
||||||
|
|
||||||
|
public DeleteIngredientMessage() {} // for jackson
|
||||||
|
|
||||||
public DeleteIngredientMessage(Long ingredientId) {
|
public DeleteIngredientMessage(Long ingredientId) {
|
||||||
this.ingredientId = ingredientId;
|
this.ingredientId = ingredientId;
|
||||||
}
|
}
|
||||||
|
|
@ -25,4 +27,9 @@ public class DeleteIngredientMessage implements Message {
|
||||||
public Long getIngredientId() {
|
public Long getIngredientId() {
|
||||||
return ingredientId;
|
return ingredientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for jackson
|
||||||
|
public void setIngredientId(Long ingredientId) {
|
||||||
|
this.ingredientId = ingredientId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ package commons.ws.messages;
|
||||||
public class DeleteRecipeMessage implements Message {
|
public class DeleteRecipeMessage implements Message {
|
||||||
private Long recipeId;
|
private Long recipeId;
|
||||||
|
|
||||||
|
public DeleteRecipeMessage() {} // for jackson
|
||||||
|
|
||||||
public DeleteRecipeMessage(Long recipeId) {
|
public DeleteRecipeMessage(Long recipeId) {
|
||||||
this.recipeId = recipeId;
|
this.recipeId = recipeId;
|
||||||
}
|
}
|
||||||
|
|
@ -25,4 +27,9 @@ public class DeleteRecipeMessage implements Message {
|
||||||
public Long getRecipeId() {
|
public Long getRecipeId() {
|
||||||
return recipeId;
|
return recipeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for jackson
|
||||||
|
public void setRecipeId(Long recipeId) {
|
||||||
|
this.recipeId = recipeId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package commons.ws.messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message sent when a recipe becomes a favourite.
|
||||||
|
* @see commons.ws.messages.Message.Type#RECIPE_FAVOURITE
|
||||||
|
*/
|
||||||
|
public class FavouriteRecipeMessage implements Message{
|
||||||
|
|
||||||
|
private Long recipeId;
|
||||||
|
|
||||||
|
public FavouriteRecipeMessage(Long recipeId) {
|
||||||
|
this.recipeId = recipeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return Type.RECIPE_FAVOURITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the ID of the recipe that got favourite.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Long getRecipeId() {
|
||||||
|
return recipeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,21 @@
|
||||||
package commons.ws.messages;
|
package commons.ws.messages;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
|
||||||
|
@JsonTypeInfo(
|
||||||
|
use = JsonTypeInfo.Id.NAME,
|
||||||
|
property = "type"
|
||||||
|
)
|
||||||
|
@JsonSubTypes({
|
||||||
|
@JsonSubTypes.Type(value = CreateRecipeMessage.class, name = "RECIPE_CREATE"),
|
||||||
|
@JsonSubTypes.Type(value = UpdateRecipeMessage.class, name = "RECIPE_UPDATE"),
|
||||||
|
@JsonSubTypes.Type(value = DeleteRecipeMessage.class, name = "RECIPE_DELETE"),
|
||||||
|
@JsonSubTypes.Type(value = CreateIngredientMessage.class, name = "INGREDIENT_CREATE"),
|
||||||
|
@JsonSubTypes.Type(value = UpdateIngredientMessage.class, name = "INGREDIENT_UPDATE"),
|
||||||
|
@JsonSubTypes.Type(value = DeleteIngredientMessage.class, name = "INGREDIENT_DELETE")
|
||||||
|
})
|
||||||
public interface Message {
|
public interface Message {
|
||||||
public enum Type {
|
public enum Type {
|
||||||
/**
|
/**
|
||||||
|
|
@ -23,6 +39,15 @@ public interface Message {
|
||||||
*/
|
*/
|
||||||
RECIPE_DELETE,
|
RECIPE_DELETE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message sent when a recipe became a favourite.
|
||||||
|
*
|
||||||
|
* @see commons.ws.messages.FavouriteRecipeMessage
|
||||||
|
*/
|
||||||
|
|
||||||
|
RECIPE_FAVOURITE,
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message sent when a new ingredient is created.
|
* Message sent when a new ingredient is created.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import commons.Ingredient;
|
||||||
public class UpdateIngredientMessage implements Message {
|
public class UpdateIngredientMessage implements Message {
|
||||||
private Ingredient ingredient;
|
private Ingredient ingredient;
|
||||||
|
|
||||||
|
public UpdateIngredientMessage() {} // for jackson
|
||||||
|
|
||||||
public UpdateIngredientMessage(Ingredient ingredient) {
|
public UpdateIngredientMessage(Ingredient ingredient) {
|
||||||
this.ingredient = ingredient;
|
this.ingredient = ingredient;
|
||||||
}
|
}
|
||||||
|
|
@ -27,4 +29,9 @@ public class UpdateIngredientMessage implements Message {
|
||||||
public Ingredient getIngredient() {
|
public Ingredient getIngredient() {
|
||||||
return ingredient;
|
return ingredient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for jackson
|
||||||
|
public void setIngredient(Ingredient ingredient) {
|
||||||
|
this.ingredient = ingredient;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import commons.Recipe;
|
||||||
public class UpdateRecipeMessage implements Message {
|
public class UpdateRecipeMessage implements Message {
|
||||||
private Recipe recipe;
|
private Recipe recipe;
|
||||||
|
|
||||||
|
public UpdateRecipeMessage() {} // for jackson
|
||||||
|
|
||||||
public UpdateRecipeMessage(Recipe recipe) {
|
public UpdateRecipeMessage(Recipe recipe) {
|
||||||
this.recipe = recipe;
|
this.recipe = recipe;
|
||||||
}
|
}
|
||||||
|
|
@ -27,4 +29,9 @@ public class UpdateRecipeMessage implements Message {
|
||||||
public Recipe getRecipe() {
|
public Recipe getRecipe() {
|
||||||
return recipe;
|
return recipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for jackson
|
||||||
|
public void setRecipe(Recipe recipe) {
|
||||||
|
this.recipe = recipe;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Delft University of Technology
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package commons;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
public class PersonTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void checkConstructor() {
|
|
||||||
var p = new Person("f", "l");
|
|
||||||
assertEquals("f", p.firstName);
|
|
||||||
assertEquals("l", p.lastName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void equalsHashCode() {
|
|
||||||
var a = new Person("a", "b");
|
|
||||||
var b = new Person("a", "b");
|
|
||||||
assertEquals(a, b);
|
|
||||||
assertEquals(a.hashCode(), b.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void notEqualsHashCode() {
|
|
||||||
var a = new Person("a", "b");
|
|
||||||
var b = new Person("a", "c");
|
|
||||||
assertNotEquals(a, b);
|
|
||||||
assertNotEquals(a.hashCode(), b.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void hasToString() {
|
|
||||||
var actual = new Person("a", "b").toString();
|
|
||||||
assertTrue(actual.contains(Person.class.getSimpleName()));
|
|
||||||
assertTrue(actual.contains("\n"));
|
|
||||||
assertTrue(actual.contains("firstName"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Delft University of Technology
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package commons;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
public class QuoteTest {
|
|
||||||
|
|
||||||
private static final Person SOME_PERSON = new Person("a", "b");
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void checkConstructor() {
|
|
||||||
var q = new Quote(SOME_PERSON, "q");
|
|
||||||
assertEquals(SOME_PERSON, q.person);
|
|
||||||
assertEquals("q", q.quote);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void equalsHashCode() {
|
|
||||||
var a = new Quote(new Person("a", "b"), "c");
|
|
||||||
var b = new Quote(new Person("a", "b"), "c");
|
|
||||||
assertEquals(a, b);
|
|
||||||
assertEquals(a.hashCode(), b.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void notEqualsHashCode() {
|
|
||||||
var a = new Quote(new Person("a", "b"), "c");
|
|
||||||
var b = new Quote(new Person("a", "b"), "d");
|
|
||||||
assertNotEquals(a, b);
|
|
||||||
assertNotEquals(a.hashCode(), b.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void hasToString() {
|
|
||||||
var actual = new Quote(new Person("a", "b"), "c").toString();
|
|
||||||
assertTrue(actual.contains(Quote.class.getSimpleName()));
|
|
||||||
assertTrue(actual.contains("\n"));
|
|
||||||
assertTrue(actual.contains("person"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +1,134 @@
|
||||||
# Week 3 meeting agenda
|
# Week 6 meeting agenda
|
||||||
|
|
||||||
| Key | Value |
|
| Key | Value |
|
||||||
| ------------ |-----------------------------------------------------------------------------------------|
|
| ------------ |--------------------------------------------------------------------------------------------------|
|
||||||
| Date | Dec 18th |
|
| Date | Dec 18th |
|
||||||
| Time | 14:45 |
|
| Time | 14:45 |
|
||||||
| Location | Hall D |
|
| Location | Hall D |
|
||||||
| Chair | Rithvik Sriram |
|
| Chair | Rithvik Sriram |
|
||||||
| Minute Taker | Mei Chang van der Werff |
|
| Minute Taker | Mei Chang van der Werff |
|
||||||
| Attendees | Mei Chang van der Werff, Natalia Cholewa, Rithvik Sriram, Aysegul Aydinlik, Steven Liu |
|
| Attendees | Mei Chang van der Werff, Natalia Cholewa, Rithvik Sriram, Aysegul Aydinlik, Steven Liu (online) |
|
||||||
## Table of contents
|
## Table of contents
|
||||||
1. (1 min) Introduction by chair
|
* (Steven joins the meeting online)
|
||||||
2. (1 min) Any additions to the agenda?
|
|
||||||
3. (1-2 min) TA announcements?
|
|
||||||
4. (1 min) Go over TA feedback given
|
|
||||||
5. (1 min) Next meeting thursday after midterms.
|
|
||||||
6. (33 min) **Meeting content**
|
|
||||||
1. (5 min) Week 6 progress in terms of completion
|
|
||||||
- How far are we in terms of completion?
|
|
||||||
2. (5 min) Progress check in terms of feature/issue completion
|
|
||||||
- What have we completed/going to complete this week?
|
|
||||||
3. (3 min) Small Showcase of the product
|
|
||||||
|
|
||||||
4. (20 min) **Sprint planning week 7-8**
|
1. (1 min) Introduction by chair
|
||||||
- What needs to be done?
|
> Meeting starts at **14:46**
|
||||||
- How do we do it?
|
---
|
||||||
- Who does it?
|
|
||||||
5. (2 min) Designate teams.
|
2. (1 min) Any additions to the agenda?
|
||||||
6. (1 min) Who is the next chair and minute taker?
|
> Tomorrow is the deadline for technology, it's best to go over the requirements real quick. \
|
||||||
7. (2 min) Questions
|
> To prevent failing this assignment like the previous 2
|
||||||
8. (1 min) Summarize everything
|
---
|
||||||
9. (1 min) TA remarks
|
3. (1-2 min) TA announcements?
|
||||||
**Max time:** ~40 minutes
|
> If there are any questions about my feedback ask them now
|
||||||
|
4. (1 min) Go over TA feedback given
|
||||||
|
>*We've made a little summary of our feedback, and had a few questions*
|
||||||
|
> ### _Time Tracking_:
|
||||||
|
>- **What exactly is expected from us for the time tracking?** \
|
||||||
|
>We need to do an estimate of how long a task/issue might take. And after implementing it, you have to upload the actual taken time
|
||||||
|
>- **Are the Mr and issues time tracking connected?** \
|
||||||
|
>Yes, but not 100% sure. It's better to double-check it yourself
|
||||||
|
>
|
||||||
|
>### _Milestones_:
|
||||||
|
>- **What was the exact issue, they are too big?** \
|
||||||
|
>Our understanding of milestones is wrong, the milestones should be kinda our weekly tasks deadline. \
|
||||||
|
>And when we don't finish a task it should be moved to the next milestone, of the next week.
|
||||||
|
>
|
||||||
|
> ### _UserStory (backlog)_:
|
||||||
|
>- **How should we do this?** \
|
||||||
|
> You can just put it in the issue description.Don't make it your mr title! \
|
||||||
|
>A different groups makes the user story a parent issue and make children issues with the actual code, but we can choose what we want
|
||||||
|
>>For now, we will just put the user Story in the issue description, we will discuss it later if we want to change the method or not
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>### _Commit and MR issues_:
|
||||||
|
>- Not all commits are related to the Mr
|
||||||
|
>- Our commits are too big, editing ±20 files are way too many. Try too keep it to 3-5 files max.
|
||||||
|
>- Also do only client or only server in a commit, don't combine them.
|
||||||
|
> - `mvn clean verify` before pushing to check whether the pipeline fails or not
|
||||||
|
|
||||||
|
---
|
||||||
|
5. (33 min) Meeting content
|
||||||
|
* (5 min) Week 6 progress in terms of completion
|
||||||
|
- How far are we in terms of completion?
|
||||||
|
>* 4.1 We still need to merge to connection of the print function, the Mr needed some changes but we can do that later. But do Rebase the MR as the branch is behind with A LOT of commits
|
||||||
|
>* 4.2 We've done the websockets, we only need to merge it
|
||||||
|
>* 4.3 We've done some backend parts but they are not yet connected to the client side
|
||||||
|
>* 4.4 The favourite button and message were made this week
|
||||||
|
>* 4.4 The search bar is currently in prgress on both the client and server side
|
||||||
|
>* 4.5 We keep this for week 8 or next week if there are not enough tasks
|
||||||
|
> >Let's focus on just connecting everything next week and after that we can start implementing 4.5
|
||||||
|
|
||||||
|
* (5 min) Progress check in terms of feature/issue completion
|
||||||
|
- What have we completed/going to complete this week?
|
||||||
|
> **Rithvik**: the backend of the searchbar and favourites is in progress. \
|
||||||
|
> **Aysegul**: Made the favourite button and some UI elements, sadly enough no penguin icon yet :< \
|
||||||
|
> **Oskar**: Finished the websocket implementation, however there is a small TODO left. Steven is going to do that. Also connected the config \
|
||||||
|
> **Mei Chang**: Deleted all the left over example code, made the favourite recipe message(backend), created a test class, made unit use enums and did a small TODO about setters.\
|
||||||
|
> **Natalia**: Almost finished the search bar (frontend) and improved testing on the client side. Will do some refactoring tomorrow. \
|
||||||
|
> **Steven**: Forgot to ask. But did make the language buttons a dropdown box, and did some other things
|
||||||
|
* (3 min) Small Showcase of the product
|
||||||
|
>We didn't have a lot of time to review and merge our code, so there is not big difference compared to last week. \
|
||||||
|
> We've shown the language dropdown box
|
||||||
|
* (20 min) Sprint planning week 7-8
|
||||||
|
- What needs to be done?
|
||||||
|
- Handle Backend-Server code delegation
|
||||||
|
- How do we do it?
|
||||||
|
- Who does it?
|
||||||
|
>We didn't really divide the tasks, just the roles. We will distribute tasks on the monday meeting. \
|
||||||
|
> We did discuss some things general tasks that need to be done
|
||||||
|
>
|
||||||
|
> ### Server
|
||||||
|
> - Testing
|
||||||
|
> - Refactoring (Oskar)
|
||||||
|
> - Some backend websocket things
|
||||||
|
> - Add more endpoints
|
||||||
|
>
|
||||||
|
> ### Client
|
||||||
|
> - Connecting everything to the UI
|
||||||
|
> - Some frontend websocket things
|
||||||
|
|
||||||
|
|
||||||
|
* (2 min) Designate teams.
|
||||||
|
>There is not a lot of server code that needs to be done so we're keeping the 2/4 server/client distribution this week.\
|
||||||
|
> Since there are still 3 people who need their LOC in server they have prioriy
|
||||||
|
> - Ayse and Oskar will do Server
|
||||||
|
> - The others will do Client
|
||||||
|
|
||||||
|
* (1 min) Who is the next chair and minute taker?
|
||||||
|
> Mei Chang will be the Chair \
|
||||||
|
> Aysegul will be the minute taker
|
||||||
|
---
|
||||||
|
>### Some Questions
|
||||||
|
> **What's the criteria of production code in server?**\
|
||||||
|
> Answer: recommendation to do 50/50 or 60/40 production/test code.
|
||||||
|
>
|
||||||
|
> **Can we copy code from the internet?**\
|
||||||
|
> Answer: Yes, but do put the link of where you got the code from in comments
|
||||||
|
>
|
||||||
|
> **For a test I want to change the gitlab UI, is that allowed?**
|
||||||
|
> **And I need to write a docx file for this, is the team fine with that?**\
|
||||||
|
> Answer TA: Yes, but make sure it doesn't affect the other teammates \
|
||||||
|
> Team: Yeah we're fine with that
|
||||||
|
|
||||||
|
---
|
||||||
|
6. (2 min) Questions
|
||||||
|
> #### We haven't yet talked about the technology requirements.
|
||||||
|
> We might didn't split the ui correctly, there is too much logic in it.\
|
||||||
|
> Server utils isn't server decorated
|
||||||
|
>
|
||||||
|
> **What is business logic?** \
|
||||||
|
> Something about the fact that not everything should be in the same file, but split across files
|
||||||
|
---
|
||||||
|
7. (1 min) Summarize everything
|
||||||
|
>- 3 people still need to do server LOC; Aysegul, Oskar, Mei Chang.
|
||||||
|
>- Next week our priority is connecting everything
|
||||||
|
>- We need to improve our code contribution and planning based on the feedback
|
||||||
|
---
|
||||||
|
8. (1 min) TA remarks \
|
||||||
|
Max time: ~40 minutes
|
||||||
|
|
||||||
|
> Ta will look at technology on Tuesday
|
||||||
|
>
|
||||||
|
>Meeting ends: **15:18**\
|
||||||
|
>Actual meeting time: 32 minutes
|
||||||
|
|
|
||||||
68
docs/feedback/week-06.md
Normal file
68
docs/feedback/week-06.md
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
|
||||||
|
# Meeting feedback
|
||||||
|
|
||||||
|
**Quick Summary Scale**
|
||||||
|
|
||||||
|
Insufficient/Sufficient/Good/Excellent
|
||||||
|
|
||||||
|
|
||||||
|
#### Agenda
|
||||||
|
|
||||||
|
Feedback: **Sufficient**
|
||||||
|
|
||||||
|
- The agenda was not uploaded on time. Generally, the agenda should be uploaded at least 2 days before the meeting so all members can access it, but I usually look for the agenda to be uploaded at the latest a day before the meeting.
|
||||||
|
- The agenda was formatted according to the template.
|
||||||
|
- The individual points were clear.
|
||||||
|
- Try to slightly adjust the layout of the agenda to be easier to read. For example, you can have sections like Opening, Updates, Feedback, Closing etc. It is easier to follow the agenda if the points are separated based on the discussed topics.
|
||||||
|
|
||||||
|
#### Performance of the Previous Minute Taker
|
||||||
|
|
||||||
|
Feedback: **Good**
|
||||||
|
|
||||||
|
- The notes have been merged in the agenda file.
|
||||||
|
- The notes are clear, but try to organize them a bit more as it is difficult to read through the notes when they are placed right next to each other.
|
||||||
|
- You can group the notes based on discussed points.
|
||||||
|
- The agreements are clear and realistic.
|
||||||
|
- Everyone was assigned to a task. For better visualization, you can add a task distribution table.
|
||||||
|
- A similar table can be used for minutes: one column for discussed topics and another column for notes.
|
||||||
|
|
||||||
|
#### Chair performance
|
||||||
|
|
||||||
|
Feedback: **Excellent**
|
||||||
|
|
||||||
|
- You did a good job with starting the meeting and checking in with everyone.
|
||||||
|
- You covered all points from the agenda.
|
||||||
|
- I liked that you took the initiative and guided the team through your points, e.g. when you discussed the feedback and contribution status.
|
||||||
|
- You asked for everyone's input, which is great. Well done!
|
||||||
|
- I also liked that you did a quick summary at the end.
|
||||||
|
|
||||||
|
|
||||||
|
#### Attitude & Relation
|
||||||
|
|
||||||
|
Feedback: **Good - Excellent**
|
||||||
|
|
||||||
|
- Overall the atmosphere was constructive and positive.
|
||||||
|
- All ideas were listened to and considered by all team members.
|
||||||
|
- Everyone was active and involved in the meeting.
|
||||||
|
- Everyone took ownership of the meeting.
|
||||||
|
- Most of you contributed to the discussion, but some seemed to be more quiet this week.
|
||||||
|
|
||||||
|
|
||||||
|
#### Potentially Shippable Product
|
||||||
|
|
||||||
|
Feedback: **Excellent**
|
||||||
|
|
||||||
|
- The team presented the current state of the application.
|
||||||
|
- The application is shippable, includes all basic requirements and great progress has been made on the extensions as well.
|
||||||
|
- Progress has been made compared to last week. Keep up the good work!
|
||||||
|
- You are on a good track to create a fully working application by the end, including all extensions! :)
|
||||||
|
|
||||||
|
|
||||||
|
#### Work Contribution/Distribution in the Team
|
||||||
|
|
||||||
|
Feedback: **Excellent**
|
||||||
|
|
||||||
|
- I liked that everyone explained what they did for this week.
|
||||||
|
- Most of you reached your goals. I understand that some items are still pending to be merged. Make sure you stay on track with the tasks of this week.
|
||||||
|
- So far it feels like everyone is still contributing equally to the team.
|
||||||
|
- Try to review what you planned the previous week and check if everything was completed.
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2024 Sebastian Proksch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
package server.api;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import commons.Person;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/people")
|
|
||||||
public class PersonListingController {
|
|
||||||
|
|
||||||
private List<Person> people = new LinkedList<>();
|
|
||||||
|
|
||||||
public PersonListingController() {
|
|
||||||
people.add(new Person("Mickey", "Mouse"));
|
|
||||||
people.add(new Person("Donald", "Duck"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/")
|
|
||||||
public List<Person> list() {
|
|
||||||
return people;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/")
|
|
||||||
public List<Person> add(@RequestBody Person p) {
|
|
||||||
if (!people.contains(p)) {
|
|
||||||
people.add(p);
|
|
||||||
}
|
|
||||||
return people;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Delft University of Technology
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package server.api;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import commons.Quote;
|
|
||||||
import server.database.QuoteRepository;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/quotes")
|
|
||||||
public class QuoteController {
|
|
||||||
|
|
||||||
private final Random random;
|
|
||||||
private final QuoteRepository repo;
|
|
||||||
|
|
||||||
public QuoteController(Random random, QuoteRepository repo) {
|
|
||||||
this.random = random;
|
|
||||||
this.repo = repo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping(path = { "", "/" })
|
|
||||||
public List<Quote> getAll() {
|
|
||||||
return repo.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
public ResponseEntity<Quote> getById(@PathVariable("id") long id) {
|
|
||||||
if (id < 0 || !repo.existsById(id)) {
|
|
||||||
return ResponseEntity.badRequest().build();
|
|
||||||
}
|
|
||||||
return ResponseEntity.ok(repo.findById(id).get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping(path = { "", "/" })
|
|
||||||
public ResponseEntity<Quote> add(@RequestBody Quote quote) {
|
|
||||||
|
|
||||||
if (quote.person == null || isNullOrEmpty(quote.person.firstName) || isNullOrEmpty(quote.person.lastName)
|
|
||||||
|| isNullOrEmpty(quote.quote)) {
|
|
||||||
return ResponseEntity.badRequest().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
Quote saved = repo.save(quote);
|
|
||||||
return ResponseEntity.ok(saved);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isNullOrEmpty(String s) {
|
|
||||||
return s == null || s.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("rnd")
|
|
||||||
public ResponseEntity<Quote> getRandom() {
|
|
||||||
var quotes = repo.findAll();
|
|
||||||
var idx = random.nextInt((int) repo.count());
|
|
||||||
return ResponseEntity.ok(quotes.get(idx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Delft University of Technology
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package server.database;
|
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
|
|
||||||
import commons.Quote;
|
|
||||||
|
|
||||||
public interface QuoteRepository extends JpaRepository<Quote, Long> {}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2024 Sebastian Proksch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
package server.api;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import commons.Person;
|
|
||||||
|
|
||||||
public class PersonListingControllerTest {
|
|
||||||
|
|
||||||
private static final Person MICKEY = new Person("Mickey", "Mouse");
|
|
||||||
private static final Person DONALD = new Person("Donald", "Duck");
|
|
||||||
private static final Person SCROOGE = new Person("Scrooge", "McDuck");
|
|
||||||
|
|
||||||
private PersonListingController sut;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setup() {
|
|
||||||
sut = new PersonListingController();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void containsTwoDefaultNames() {
|
|
||||||
var actual = sut.list();
|
|
||||||
var expected = List.of(MICKEY, DONALD);
|
|
||||||
assertEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void canAddPeople() {
|
|
||||||
var actual = sut.add(SCROOGE);
|
|
||||||
var expected = List.of(MICKEY, DONALD, SCROOGE);
|
|
||||||
assertEquals(expected, actual);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Delft University of Technology
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package server.api;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import commons.Person;
|
|
||||||
import commons.Quote;
|
|
||||||
|
|
||||||
public class QuoteControllerTest {
|
|
||||||
|
|
||||||
public int nextInt;
|
|
||||||
private MyRandom random;
|
|
||||||
private TestQuoteRepository repo;
|
|
||||||
|
|
||||||
private QuoteController sut;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setup() {
|
|
||||||
random = new MyRandom();
|
|
||||||
repo = new TestQuoteRepository();
|
|
||||||
sut = new QuoteController(random, repo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void cannotAddNullPerson() {
|
|
||||||
var actual = sut.add(getQuote(null));
|
|
||||||
assertEquals(BAD_REQUEST, actual.getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void randomSelection() {
|
|
||||||
sut.add(getQuote("q1"));
|
|
||||||
sut.add(getQuote("q2"));
|
|
||||||
nextInt = 1;
|
|
||||||
var actual = sut.getRandom();
|
|
||||||
|
|
||||||
assertTrue(random.wasCalled);
|
|
||||||
assertEquals("q2", actual.getBody().quote);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void databaseIsUsed() {
|
|
||||||
sut.add(getQuote("q1"));
|
|
||||||
repo.calledMethods.contains("save");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Quote getQuote(String q) {
|
|
||||||
return new Quote(new Person(q, q), q);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class MyRandom extends Random {
|
|
||||||
|
|
||||||
public boolean wasCalled = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int nextInt(int bound) {
|
|
||||||
wasCalled = true;
|
|
||||||
return nextInt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,225 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Delft University of Technology
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package server.api;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import org.springframework.data.domain.Example;
|
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
import org.springframework.data.domain.Sort;
|
|
||||||
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
|
|
||||||
|
|
||||||
import commons.Quote;
|
|
||||||
import server.database.QuoteRepository;
|
|
||||||
|
|
||||||
public class TestQuoteRepository implements QuoteRepository {
|
|
||||||
|
|
||||||
public final List<Quote> quotes = new ArrayList<>();
|
|
||||||
public final List<String> calledMethods = new ArrayList<>();
|
|
||||||
|
|
||||||
private void call(String name) {
|
|
||||||
calledMethods.add(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Quote> findAll() {
|
|
||||||
calledMethods.add("findAll");
|
|
||||||
return quotes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Quote> findAll(Sort sort) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Quote> findAllById(Iterable<Long> ids) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> List<S> saveAll(Iterable<S> entities) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> S saveAndFlush(S entity) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> List<S> saveAllAndFlush(Iterable<S> entities) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteAllInBatch(Iterable<Quote> entities) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteAllByIdInBatch(Iterable<Long> ids) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteAllInBatch() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Quote getOne(Long id) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Quote getById(Long id) {
|
|
||||||
call("getById");
|
|
||||||
return find(id).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Quote getReferenceById(Long id) {
|
|
||||||
call("getReferenceById");
|
|
||||||
return find(id).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<Quote> find(Long id) {
|
|
||||||
return quotes.stream().filter(q -> q.id == id).findFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> List<S> findAll(Example<S> example) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> List<S> findAll(Example<S> example, Sort sort) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Page<Quote> findAll(Pageable pageable) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> S save(S entity) {
|
|
||||||
call("save");
|
|
||||||
entity.id = (long) quotes.size();
|
|
||||||
quotes.add(entity);
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Quote> findById(Long id) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean existsById(Long id) {
|
|
||||||
call("existsById");
|
|
||||||
return find(id).isPresent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long count() {
|
|
||||||
return quotes.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteById(Long id) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(Quote entity) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteAllById(Iterable<? extends Long> ids) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteAll(Iterable<? extends Quote> entities) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteAll() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> Optional<S> findOne(Example<S> example) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> Page<S> findAll(Example<S> example, Pageable pageable) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> long count(Example<S> example) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote> boolean exists(Example<S> example) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <S extends Quote, R> R findBy(Example<S> example, Function<FetchableFluentQuery<S>, R> queryFunction) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue