UTF-8
@@ -42,21 +41,26 @@
spring-boot-starter-test
test
-
-
+
+ org.xhtmlrenderer
+ flying-saucer-pdf
+ 9.1.18
+
+
+ org.apache.poi
+ poi-ooxml
+ 4.1.0
+
com.h2database
h2
runtime
-
commons-codec
commons-codec
1.11
-
-
com.itextpdf
itextpdf
@@ -67,6 +71,30 @@
pdfbox
2.0.4
+
+ org.mockito
+ mockito-core
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ org.projectlombok
+ lombok
+ 1.18.10
+ provided
+
+
+ org.springframework.boot
+ spring-boot-devtools
+
+
+ com.atlassian.commonmark
+ commonmark
+ 0.13.1
+
@@ -75,6 +103,23 @@
org.springframework.boot
spring-boot-maven-plugin
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+
+
+ test
+
+ run
+
+
+
+
+
+
+
+
+
diff --git a/recipes.mv.db b/recipes.mv.db
deleted file mode 100644
index 417112b..0000000
Binary files a/recipes.mv.db and /dev/null differ
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/ColorRecipesExplorerApplication.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/ColorRecipesExplorerApplication.java
similarity index 50%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/ColorRecipesExplorerApplication.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/ColorRecipesExplorerApplication.java
index 3d6efd4..3139f68 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/ColorRecipesExplorerApplication.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/ColorRecipesExplorerApplication.java
@@ -1,11 +1,13 @@
-package fyloz.trial.ColorRecipesExplorer;
+package dev.fyloz.trial.colorrecipesexplorer;
-import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler;
-import fyloz.trial.ColorRecipesExplorer.web.StringBank;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.PasswordService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.MessageSource;
import java.io.File;
import java.io.IOException;
@@ -15,26 +17,38 @@ import java.util.List;
@SpringBootApplication
public class ColorRecipesExplorerApplication {
- public static final Logger logger = LoggerFactory.getLogger(ColorRecipesExplorerApplication.class);
- // Chemin du fichier contenant les utilisateurs
+ public static final Logger LOGGER = LoggerFactory.getLogger(ColorRecipesExplorerApplication.class);
+ public static String UPLOAD_LOCATION;
public static final String USERS_FILE_NAME = "passwords";
+ public static boolean USE_PORT;
+
+ public static ColorRecipesExplorerApplication CREApp;
+
+ private MessageSource messageSource;
public static void main(String[] args) {
- logger.info("Le fichier des utilisateurs se situe à: " + new File(StringBank.UPLOAD_LOCATION + "/" + USERS_FILE_NAME).getAbsolutePath());
- loadPasswords();
+ UPLOAD_LOCATION = args[0] != null ? args[0] : "./";
SpringApplication.run(ColorRecipesExplorerApplication.class, args);
}
+ @Autowired
+ public ColorRecipesExplorerApplication(MessageSource messageSource) {
+ this.messageSource = messageSource;
+
+ CREApp = this;
+ LOGGER.info("Le fichier des utilisateurs se situe à: " + new File(UPLOAD_LOCATION + "/" + USERS_FILE_NAME).getAbsolutePath());
+
+ loadPasswords();
+ }
+
/**
* Charge les mots de passes contenus dans le fichier.
*
* Un mot de passe correspond à une ligne dans le fichier passwords.txt.
- *
- * @throws IOException
*/
- private static void loadPasswords() {
- FileHandler fileHandler = new FileHandler(USERS_FILE_NAME, FileHandler.FileContext.OTHERS, FileHandler.FileExtension.TXT);
+ private void loadPasswords() {
+ FileHandler fileHandler = new FileHandler(USERS_FILE_NAME, FileHandler.FileContext.OTHERS, FileHandler.FileExtension.TEXT);
if (!fileHandler.isValid()) {
fileHandler.createFile();
}
@@ -43,15 +57,19 @@ public class ColorRecipesExplorerApplication {
List fileContent = Files.readAllLines(fileHandler.getPath());
if (fileContent.size() < 1) {
- logger.warn("Aucun mot de passe trouvé. Il sera impossible d'utiliser certaines fonctionnalitées de l'application.");
+ LOGGER.warn("Aucun mot de passe trouvé. Il sera impossible d'utiliser certaines fonctionnalitées de l'application.");
}
for (String line : fileContent) {
- PasswordValidator.addPassword(line);
+ PasswordService.addPassword(line);
}
} catch (IOException e) {
- logger.error("Une erreur est survenue lors du chargement du fichier des utilisateurs", e);
- logger.warn("Il sera impossible d'utiliser certaines fonctionnalitées de l'application.");
+ LOGGER.error("Une erreur est survenue lors du chargement du fichier des utilisateurs", e);
+ LOGGER.warn("Il sera impossible d'utiliser certaines fonctionnalitées de l'application.");
}
}
+
+ public MessageSource getMessageSource() {
+ return messageSource;
+ }
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/InitialDataLoader.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/InitialDataLoader.java
new file mode 100644
index 0000000..a2d5f66
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/InitialDataLoader.java
@@ -0,0 +1,41 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.configuration;
+
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class InitialDataLoader implements ApplicationListener {
+
+ private MaterialTypeService materialTypeService;
+
+ @Autowired
+ public InitialDataLoader(MaterialTypeService materialTypeService) {
+ this.materialTypeService = materialTypeService;
+ }
+
+ @Override
+ public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
+ if (!materialTypeService.getByName(MaterialType.DEFAULT_MATERIAL_TYPE_NAME).isPresent()) {
+ createDefaultMaterialType();
+ }
+ }
+
+ private void createDefaultMaterialType() {
+ MaterialType defaultMaterialType = new MaterialType(MaterialType.DEFAULT_MATERIAL_TYPE_NAME, "", false);
+
+ Optional optionalSavedMaterialType = materialTypeService.save(defaultMaterialType);
+ if (!optionalSavedMaterialType.isPresent()) {
+ ColorRecipesExplorerApplication.LOGGER.warn("Échec de la création du type de produit par défaut.");
+ }
+ }
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LocaleConfiguration.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LocaleConfiguration.java
similarity index 79%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LocaleConfiguration.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LocaleConfiguration.java
index d42819b..c014431 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LocaleConfiguration.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LocaleConfiguration.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.core.configuration;
+package dev.fyloz.trial.colorrecipesexplorer.core.configuration;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
@@ -18,19 +18,11 @@ public class LocaleConfiguration implements WebMvcConfigurer {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
-// messageSource.setBasenames("classpath:lang/messages", "classpath:lang/responses");
- messageSource.setBasename("classpath:lang/responses");
+ messageSource.setBasenames("classpath:lang/messages", "classpath:lang/responses");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
-// @Bean
-// public MessageSource responsesMessageSource() {
-// ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
-// messageSource.setBasename("classpath:lang/responses");
-// return messageSource;
-// }
-
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LoggingConfiguration.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LoggingConfiguration.java
similarity index 94%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LoggingConfiguration.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LoggingConfiguration.java
index 1573517..25f7338 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/configuration/LoggingConfiguration.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/LoggingConfiguration.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.core.configuration;
+package dev.fyloz.trial.colorrecipesexplorer.core.configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/SpringConfiguration.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/SpringConfiguration.java
new file mode 100644
index 0000000..fc61ecd
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/configuration/SpringConfiguration.java
@@ -0,0 +1,19 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.configuration;
+
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SpringConfiguration {
+
+ @Value("${response.useport}")
+ public boolean usePort;
+
+ @Bean
+ public void setUsePort() {
+ ColorRecipesExplorerApplication.USE_PORT = usePort;
+ }
+
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/FileHandler.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/FileHandler.java
similarity index 87%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/FileHandler.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/FileHandler.java
index 451075e..9ebb7c3 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/FileHandler.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/FileHandler.java
@@ -1,6 +1,6 @@
-package fyloz.trial.ColorRecipesExplorer.core.io;
+package dev.fyloz.trial.colorrecipesexplorer.core.io.file;
-import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication;
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
import org.slf4j.Logger;
import java.io.File;
@@ -9,12 +9,10 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import static fyloz.trial.ColorRecipesExplorer.web.StringBank.UPLOAD_LOCATION;
-
public class FileHandler {
protected String name;
- protected Logger logger = ColorRecipesExplorerApplication.logger;
+ protected Logger logger = ColorRecipesExplorerApplication.LOGGER;
private FileContext context;
private FileExtension extension;
@@ -91,7 +89,7 @@ public class FileHandler {
}
public Path getPath() {
- return Paths.get(String.format("%s/%s/%s%s", UPLOAD_LOCATION, context.getPath(), name, extension.getExtension()));
+ return Paths.get(String.format("%s/%s/%s%s", ColorRecipesExplorerApplication.UPLOAD_LOCATION, context.getPath(), name, extension.getExtension()));
}
public File getFile() {
@@ -118,8 +116,9 @@ public class FileHandler {
public enum FileExtension {
JPEG("jpeg"),
PDF("pdf"),
- TXT("txt"),
- DB("db");
+ TEXT("txt"),
+ DATABASE("db"),
+ MARKDOWN("md");
private String extension;
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/ImageHandler.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/ImageHandler.java
similarity index 77%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/ImageHandler.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/ImageHandler.java
index 7e13c22..d53848b 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/io/ImageHandler.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/file/ImageHandler.java
@@ -1,13 +1,16 @@
-package fyloz.trial.ColorRecipesExplorer.core.io;
+package dev.fyloz.trial.colorrecipesexplorer.core.io.file;
-import fyloz.trial.ColorRecipesExplorer.model.Recipe;
-import fyloz.trial.ColorRecipesExplorer.services.RecipeService;
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
import java.util.List;
import java.util.stream.Collectors;
public class ImageHandler extends FileHandler {
+ public static final String IMAGES_LOCATION = ColorRecipesExplorerApplication.UPLOAD_LOCATION + "/images";
+
private Recipe recipe;
private int index = 0;
private RecipeService recipeService;
@@ -22,6 +25,8 @@ public class ImageHandler extends FileHandler {
public ImageHandler(String name, RecipeService recipeService) {
super(name.replace(".jpeg", ""), FileContext.IMAGE, FileExtension.JPEG);
+ this.recipeService = recipeService;
+
String[] nameParts = name.split("-");
index = Integer.parseInt(nameParts[1].replace(".jpeg", ""));
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/JSONResponseBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/JSONResponseBuilder.java
new file mode 100644
index 0000000..755bec6
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/JSONResponseBuilder.java
@@ -0,0 +1,25 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
+
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import org.springframework.context.i18n.LocaleContextHolder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class JSONResponseBuilder extends ResponseBuilder> {
+
+ @Override
+ protected void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters) {
+ Map attributeContent = new HashMap<>();
+
+ // Récupère le message depuis le fichier des messages de la bonne language et rajoute ces paramètres.
+ String message = ColorRecipesExplorerApplication.CREApp.getMessageSource().getMessage(responseMessagePath, parameters, LocaleContextHolder.getLocale());
+ attributeContent.put("message", message);
+
+ addAttribute(responseCodeType, attributeContent);
+ }
+
+ public Map build() {
+ return attributes;
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ModelResponseBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ModelResponseBuilder.java
new file mode 100644
index 0000000..1d676b1
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ModelResponseBuilder.java
@@ -0,0 +1,50 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
+
+import org.springframework.web.servlet.ModelAndView;
+
+public class ModelResponseBuilder extends ResponseBuilder {
+
+ private static final String PATH_PARAMETER_PATTERN = "(\\{\\w+\\})";
+
+ private ModelAndView model;
+
+ public ModelResponseBuilder() {
+ this.model = new ModelAndView();
+ }
+
+ public ModelResponseBuilder(String view) {
+ this(new ModelAndView(view));
+ }
+
+ public ModelResponseBuilder(ModelAndView model) {
+ this.model = model == null ? new ModelAndView() : model;
+ }
+
+ public ModelResponseBuilder withView(String path) {
+ model.setViewName(path);
+
+ return this;
+ }
+
+ public ModelResponseBuilder withRedirect(String path, Object... parameters) {
+ for (Object parameter : parameters) path = path.replaceFirst(PATH_PARAMETER_PATTERN, parameter.toString());
+ model.setViewName("redirect:/" + path);
+
+ return this;
+ }
+
+ @Override
+ protected void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters) {
+ addAttribute(responseCodeType, responseMessagePath);
+
+ for (int i = 0; i < parameters.length; i++) {
+ addAttribute(String.format("responseArg%s", i + 1), parameters[i]);
+ }
+ }
+
+ public ModelAndView build() {
+ model.addAllObjects(attributes);
+
+ return model;
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseBuilder.java
new file mode 100644
index 0000000..87734db
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseBuilder.java
@@ -0,0 +1,112 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
+
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
+
+import javax.validation.constraints.NotNull;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public abstract class ResponseBuilder {
+
+ protected static final String RESPONSE_PREFIX = "response.";
+ protected static final String ERROR_ATTRIBUTE_NAME = "error";
+ protected static final String SUCCESS_ATTRIBUTE_NAME = "success";
+
+ protected Map attributes;
+
+ private boolean containsErrors = false;
+
+ public ResponseBuilder() {
+ attributes = new HashMap<>();
+
+ // Ajoute l'URL de base à toutes les réponses
+ attributes.put("baseUrl", ControllerUtils.getCurrentBaseUrl());
+ }
+
+ protected abstract void addResponseCodeToAttribute(String responseCodeType, String responseMessagePath, String[] parameters);
+
+ protected abstract R build();
+
+ public T addResponseCode(ResponseCode responseCode, Object... parameters) {
+ String[] parametersAsStr = new String[parameters.length];
+
+ for (int i = 0; i < parameters.length; i++) {
+ parametersAsStr[i] = parameters[i].toString();
+ }
+
+ return addResponseCode(responseCode, parametersAsStr);
+ }
+
+ public T addResponseCode(ResponseCode responseCode, String... parameters) {
+ int requiredParametersNumber = responseCode.getParametersNumber();
+ int givenParametersNumber = parameters.length;
+
+ if (requiredParametersNumber != givenParametersNumber) {
+ throw new IllegalArgumentException(String.format("Mauvais nombre de paramètre dans une réponse de modèle: %s requis, %s fournis", requiredParametersNumber, givenParametersNumber));
+ }
+
+ // Ajoute les paramètres, si nécessaire
+ if (requiredParametersNumber > 0) {
+ // Avertit s'il y a plus de paramètres que le nombre de paramètres supporté par le template thymeleaf (aussi MAX_PARAMETERS_NUMBER)
+ int maxParametersNumber = ResponseCode.MAX_PARAMETERS_NUMBER;
+ if (givenParametersNumber > maxParametersNumber) {
+ ColorRecipesExplorerApplication.LOGGER.warn(String.format("Trop de paramètres fournis pour le code de réponse %s: %s maximum, %s fournis", responseCode.name(), maxParametersNumber, givenParametersNumber));
+ }
+ }
+
+ String responseCodeType;
+ if (responseCode.getType() == ResponseCode.ResponseCodeType.ERROR) {
+ containsErrors = true;
+ responseCodeType = ERROR_ATTRIBUTE_NAME;
+ } else {
+ responseCodeType = SUCCESS_ATTRIBUTE_NAME;
+ }
+
+ String responseMessagePath = RESPONSE_PREFIX + responseCode.getCode();
+ addResponseCodeToAttribute(responseCodeType, responseMessagePath, parameters);
+
+ return (T) this;
+ }
+
+ public T addResponseData(ResponseDataType responseDataType, @NotNull Object data) {
+ Class requiredDataTypeClass = responseDataType.getDataType();
+ Class requiredListDataTypeClass = responseDataType.getListDataType();
+ Class givenDataTypeClass = data.getClass();
+
+ // Vérifie le type de l'objet
+ if (!requiredDataTypeClass.equals(givenDataTypeClass)) {
+ throw new IllegalArgumentException(String.format("L'objet passé en paramètre n'est pas du bon type. Requis: %s, fournis: %s", requiredDataTypeClass.getName(), givenDataTypeClass.getName()));
+ }
+
+ // Si l'objet est une liste, vérifie qu'elle n'est pas vide et qu'elle est du bon type
+ if (requiredDataTypeClass.equals(List.class) && requiredListDataTypeClass != null) {
+ List listData = (List) data;
+
+ if (listData.size() < 1) {
+ throw new IllegalArgumentException("La liste passée en paramètre ne contient aucun élément");
+ }
+
+ Class givenListDataTypeClass = listData.get(0).getClass();
+ if (givenDataTypeClass.equals(requiredListDataTypeClass)) {
+ throw new IllegalArgumentException(String.format("La liste passée en paramètre contient des éléments du mauvais type. Requis: %s, fournis: %s", requiredListDataTypeClass.getName(), givenListDataTypeClass.getName()));
+ }
+ }
+
+ // Ajoute l'attribut dans le Map
+ addAttribute(responseDataType.getDataTypeName(), data);
+
+ return (T) this;
+ }
+
+ public T addAttribute(String attributeName, Object content) {
+ attributes.put(attributeName, content);
+
+ return (T) this;
+ }
+
+ public boolean containsErrors() {
+ return containsErrors;
+ }
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ResponseCode.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseCode.java
similarity index 68%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/ResponseCode.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseCode.java
index 027938a..fa8dda0 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ResponseCode.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseCode.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.core;
+package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
public enum ResponseCode {
SUCCESS_USING_MATERIALS(1, ResponseCodeType.SUCCESS, 0),
@@ -18,7 +18,21 @@ public enum ResponseCode {
COMPANY_LINKED(15, ResponseCodeType.ERROR, 1),
MIX_NOT_ASSOCIATED_WITH_RECIPE(16, ResponseCodeType.ERROR, 2),
NOT_ENOUGH_MATERIAL(17, ResponseCodeType.ERROR, 1),
- MIX_TYPE_ALREADY_USED(18, ResponseCodeType.ERROR, 1);
+ MIX_TYPE_ALREADY_USED(18, ResponseCodeType.ERROR, 1),
+ MATERIAL_TYPE_NOT_FOUND(19, ResponseCodeType.ERROR, 1),
+ MATERIAL_TYPE_ALREADY_EXIST_PREFIX(20, ResponseCodeType.ERROR, 1),
+ MATERIAL_TYPE_LINKED(21, ResponseCodeType.ERROR, 1),
+ NO_COMPANY(22, ResponseCodeType.ERROR, 0),
+ NO_MATERIAL(23, ResponseCodeType.ERROR, 0),
+ FILE_NOT_IMAGE(24, ResponseCodeType.ERROR, 0),
+ RECIPE_NOT_FOUND_NO_PARAMS(25, ResponseCodeType.ERROR, 0),
+ MATERIAL_NOT_FOUND_BY_NAME(26, ResponseCodeType.ERROR, 1),
+
+ // HTTP Errors
+ _500(100, ResponseCodeType.ERROR, 0),
+ _404(101, ResponseCodeType.ERROR, 0),
+ _401(102, ResponseCodeType.ERROR, 0),
+ ;
public static final int MAX_PARAMETERS_NUMBER = 2;
@@ -48,4 +62,5 @@ public enum ResponseCode {
ERROR,
SUCCESS
}
+
}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelDataType.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseDataType.java
similarity index 79%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelDataType.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseDataType.java
index 50d23d4..19a55c8 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelDataType.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/io/response/ResponseDataType.java
@@ -1,12 +1,12 @@
-package fyloz.trial.ColorRecipesExplorer.core;
+package dev.fyloz.trial.colorrecipesexplorer.core.io.response;
-import fyloz.trial.ColorRecipesExplorer.model.*;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.stream.Stream;
-public enum ModelDataType {
+public enum ResponseDataType {
MATERIAL("material", Material.class),
MATERIALS("materials", ArrayList.class, MATERIAL),
MATERIAL_ID("materialID", Integer.class),
@@ -14,6 +14,7 @@ public enum ModelDataType {
MATERIAL_TYPE("materialType", MaterialType.class),
MATERIAL_TYPES("materialTypes", ArrayList.class, MATERIAL_TYPE),
+ MATERIAL_TYPE_NAME("materialTypeName", String.class),
RECIPE("recipe", Recipe.class),
RECIPES("recipes", ArrayList.class, RECIPE),
@@ -40,17 +41,19 @@ public enum ModelDataType {
COMPANY_NAME("companyName", String.class),
IMAGE("image", String.class),
- IMAGES("images", ArrayList.class, IMAGE);
+ IMAGES("images", ArrayList.class, IMAGE),
+
+ BLOCK_BUTTON("blockButton", Boolean.class);
private String dataTypeName;
private Class dataType;
private Class listDataType;
- ModelDataType(String dataTypeName, Class dataType) {
+ ResponseDataType(String dataTypeName, Class dataType) {
this(dataTypeName, dataType, null);
}
- ModelDataType(String dataTypeName, Class dataType, ModelDataType listDataType) {
+ ResponseDataType(String dataTypeName, Class dataType, ResponseDataType listDataType) {
this.dataTypeName = dataTypeName;
this.dataType = dataType;
@@ -76,7 +79,7 @@ public enum ModelDataType {
return getDataTypeName();
}
- public static ModelDataType getModelDataTypeFromDataType(Class dataType) {
+ public static ResponseDataType getModelDataTypeFromDataType(Class dataType) {
return Stream.of(values()).filter(r -> r.getDataType().equals(dataType)).findFirst().orElse(null);
}
}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/BeanModel.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/BeanModel.java
similarity index 56%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/BeanModel.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/BeanModel.java
index f374df9..a9a1690 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/BeanModel.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/BeanModel.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.model;
+package dev.fyloz.trial.colorrecipesexplorer.core.model;
public abstract class BeanModel {
public abstract Integer getID();
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Company.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Company.java
similarity index 96%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/Company.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Company.java
index 63ed96b..a9650e1 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Company.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Company.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.model;
+package dev.fyloz.trial.colorrecipesexplorer.core.model;
import org.hibernate.validator.constraints.Length;
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Material.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Material.java
similarity index 98%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/Material.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Material.java
index 2c25ae2..a796832 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Material.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Material.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.model;
+package dev.fyloz.trial.colorrecipesexplorer.core.model;
import org.hibernate.annotations.ColumnDefault;
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MaterialType.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MaterialType.java
similarity index 94%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/MaterialType.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MaterialType.java
index 007ed60..e9140ce 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MaterialType.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MaterialType.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.model;
+package dev.fyloz.trial.colorrecipesexplorer.core.model;
import org.hibernate.annotations.ColumnDefault;
@@ -11,6 +11,8 @@ import java.util.Objects;
@Entity
public class MaterialType extends BeanModel implements Serializable {
+ public static final String DEFAULT_MATERIAL_TYPE_NAME = "Aucun";
+
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer materialTypeID;
@@ -19,6 +21,7 @@ public class MaterialType extends BeanModel implements Serializable {
@NotNull
private String materialTypeName;
+ @Column(unique = true)
@NotNull
private String prefix;
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Mix.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Mix.java
similarity index 95%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/Mix.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Mix.java
index 6e77016..3d79705 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Mix.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Mix.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.model;
+package dev.fyloz.trial.colorrecipesexplorer.core.model;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
@@ -23,7 +23,7 @@ public class Mix extends BeanModel implements Serializable {
@ManyToOne
private MixType mixType;
- @OneToMany(mappedBy = "mix")
+ @OneToMany(mappedBy = "mix", cascade = CascadeType.ALL)
private List mixQuantities;
// Casier
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixQuantity.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixQuantity.java
similarity index 97%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixQuantity.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixQuantity.java
index dce9916..71694f1 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixQuantity.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixQuantity.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.model;
+package dev.fyloz.trial.colorrecipesexplorer.core.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixType.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixType.java
similarity index 94%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixType.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixType.java
index a0c5f79..6c223bd 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/MixType.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/MixType.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.model;
+package dev.fyloz.trial.colorrecipesexplorer.core.model;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
@@ -6,7 +6,7 @@ import java.io.Serializable;
import java.util.Objects;
@Entity
-@Table(name = "mixTypes")
+@Table(name = "mixTypes") // TODO retirer @Table
public class MixType extends BeanModel implements Serializable {
@Id
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Recipe.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Recipe.java
similarity index 94%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/Recipe.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Recipe.java
index 286f71a..3c83fcc 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/Recipe.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/Recipe.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.model;
+package dev.fyloz.trial.colorrecipesexplorer.core.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.validator.constraints.Length;
@@ -6,6 +6,7 @@ import org.hibernate.validator.constraints.Length;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -38,10 +39,10 @@ public class Recipe extends BeanModel implements Serializable {
private String note;
@JsonIgnore
- @OneToMany(mappedBy = "recipe")
+ @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
private List recipeMixes;
- @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
+ @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List recipeSteps;
public Recipe() {
@@ -131,7 +132,7 @@ public class Recipe extends BeanModel implements Serializable {
}
public List getRecipeSteps() {
- return recipeSteps;
+ return recipeSteps == null ? new ArrayList<>() : recipeSteps;
}
public void setRecipeSteps(List recipeSteps) {
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/RecipeStep.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/RecipeStep.java
similarity index 95%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/model/RecipeStep.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/RecipeStep.java
index 3616b14..70117ce 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/RecipeStep.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/RecipeStep.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.model;
+package dev.fyloz.trial.colorrecipesexplorer.core.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -15,7 +15,7 @@ public class RecipeStep extends BeanModel implements Serializable {
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private int stepID;
- @ManyToOne
+ @ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
private Recipe recipe;
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/dto/MixCreationFormDto.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/dto/MixCreationFormDto.java
new file mode 100644
index 0000000..10586fb
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/model/dto/MixCreationFormDto.java
@@ -0,0 +1,21 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.model.dto;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class MixCreationFormDto {
+
+ private Recipe recipe;
+
+ private String mixTypeName;
+
+ private List materials;
+
+ private List quantities;
+
+ public MixCreationFormDto() {
+ }
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/GenericService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/GenericService.java
similarity index 52%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/services/GenericService.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/GenericService.java
index 6e3d6f9..2acc38a 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/GenericService.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/GenericService.java
@@ -1,27 +1,29 @@
-package fyloz.trial.ColorRecipesExplorer.services;
+package dev.fyloz.trial.colorrecipesexplorer.core.services;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
-import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication;
-import fyloz.trial.ColorRecipesExplorer.model.BeanModel;
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.BeanModel;
import org.slf4j.Logger;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.lang.NonNull;
import java.util.List;
+import java.util.Optional;
-public abstract class GenericService implements IGenericService {
+public abstract class GenericService> implements IGenericService {
- protected Logger logger = ColorRecipesExplorerApplication.logger;
+ protected Logger logger = ColorRecipesExplorerApplication.LOGGER;
- protected JpaRepository dao;
+ protected R dao;
- public GenericService(JpaRepository dao) {
+ public GenericService(R dao) {
this.dao = dao;
}
@Override
- public T getByID(int id) {
- return dao.findById(id).get();
+ public Optional getByID(int id) {
+ return dao.findById(id);
}
@Override
@@ -30,36 +32,42 @@ public abstract class GenericService implements IGenericSer
}
@Override
- public T save(T entity) {
+ public Optional save(T entity) {
if (isValidForCreation(entity)) {
- return dao.save(entity);
+ return Optional.of(dao.save(entity));
}
- return null;
+ return Optional.empty();
}
@Override
- public boolean saveAll(List entities) {
+ public boolean saveAll(Iterable entities) {
+ if (entities == null) return false;
+
for (T e : entities) {
- if (save(e) == null) {
+ if (!save(e).isPresent()) {
return false;
}
}
+ dao.saveAll(entities);
+
return true;
}
@Override
- public T update(T entity) {
- if (exists(entity)) {
- return dao.save(entity);
+ public Optional update(@NonNull T entity) {
+ if (isValidForUpdate(entity)) {
+ return Optional.of(dao.save(entity));
}
- return null;
+ return Optional.empty();
}
@Override
public boolean delete(T entity) {
+ if (entity == null) return false;
+
if (exists(entity)) {
dao.delete(entity);
return true;
@@ -70,12 +78,13 @@ public abstract class GenericService implements IGenericSer
@Override
public boolean deleteAll(List entities) {
- for (T e : entities) {
- if (!delete(e)) {
- return false;
- }
+ if (entities == null) return false;
+
+ for (T entity : entities) {
+ if (!exists(entity)) return false;
}
+ dao.deleteAll(entities);
return true;
}
@@ -89,6 +98,16 @@ public abstract class GenericService implements IGenericSer
return entity != null && !exists(entity);
}
+ /**
+ * Vérifie si une entité est valide pour la création dans la base de données.
+ *
+ * @param entity L'entité à vérifier.
+ * @return Si l'entité est valide pour l'édition.
+ */
+ public boolean isValidForUpdate(@NonNull T entity) {
+ return exists(entity);
+ }
+
/**
* Vérifie si une entité existe dans la base de données.
*
@@ -97,7 +116,12 @@ public abstract class GenericService implements IGenericSer
*/
@Override
public boolean exists(T entity) {
- return dao.findById(entity.getID()).isPresent();
+ return entity != null && existsById(entity.getID());
+ }
+
+ @Override
+ public boolean existsById(int id) {
+ return dao.existsById(id);
}
/**
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/IGenericService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/IGenericService.java
similarity index 83%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/services/IGenericService.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/IGenericService.java
index 7dbae0f..45a2275 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/IGenericService.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/IGenericService.java
@@ -1,16 +1,17 @@
-package fyloz.trial.ColorRecipesExplorer.services;
+package dev.fyloz.trial.colorrecipesexplorer.core.services;
-import fyloz.trial.ColorRecipesExplorer.model.BeanModel;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.BeanModel;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
+import java.util.Optional;
public interface IGenericService {
/**
* Récupère toutes les entités du même type dans la base de données.
*
- * @return Une liste de toutes les entités du même type.
+ * @return Une collection contenant toutes les entités du même type.
*/
List getAll();
@@ -20,7 +21,7 @@ public interface IGenericService {
* @param id L'identifiant de l'entité
* @return L'entité correspondant à l'identifiant.
*/
- T getByID(int id);
+ Optional getByID(int id);
/**
* Sauvegarde une entité dans la base de données.
@@ -30,7 +31,7 @@ public interface IGenericService {
* @param entity L'entité à sauvegarder
* @return Si la sauvegarde a fonctionné.
*/
- T save(T entity);
+ Optional save(T entity);
/**
* Sauvegarde des entités dans la base de données.
@@ -41,7 +42,7 @@ public interface IGenericService {
* @return Si la sauvegarde a fonctionné.
*/
@Transactional
- boolean saveAll(List entities);
+ boolean saveAll(Iterable entities);
/**
* Met à jour une entité dans la base de données.
@@ -51,7 +52,7 @@ public interface IGenericService {
* @param entity L'entité à mettre à jour
* @return Si la mise à jour a fonctionné.
*/
- T update(T entity);
+ Optional update(T entity);
/**
* Supprime une entité dans la base de données.
@@ -75,4 +76,6 @@ public interface IGenericService {
boolean deleteAll(List entities);
boolean exists(T entity);
+
+ boolean existsById(int id);
}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/InventoryService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/InventoryService.java
similarity index 65%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/services/InventoryService.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/InventoryService.java
index 4c094de..f230ded 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/InventoryService.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/InventoryService.java
@@ -1,10 +1,12 @@
-package fyloz.trial.ColorRecipesExplorer.services;
+package dev.fyloz.trial.colorrecipesexplorer.core.services;
-import fyloz.trial.ColorRecipesExplorer.model.Material;
-import fyloz.trial.ColorRecipesExplorer.model.Mix;
-import fyloz.trial.ColorRecipesExplorer.model.MixQuantity;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
import org.springframework.stereotype.Service;
+import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -32,12 +34,13 @@ public class InventoryService {
}
public boolean useMix(Mix mix, Map quantities) {
- for (Material material : mix.getMixQuantities().stream().map(MixQuantity::getMaterial).collect(Collectors.toList())) {
+ List materials = mix.getMixQuantities().stream().map(MixQuantity::getMaterial).collect(Collectors.toList());
+ for (Material material : materials) {
if (!material.isMixType()) {
float quantity = quantities.get(material);
material.setInventoryQuantity(material.getInventoryQuantity() - quantity);
- if (materialService.update(material) == null) return false;
+ if (!materialService.update(material).isPresent()) return false;
}
}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/PasswordValidator.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/PasswordService.java
similarity index 77%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/PasswordValidator.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/PasswordService.java
index 7cad7f5..306b562 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/PasswordValidator.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/PasswordService.java
@@ -1,9 +1,9 @@
-package fyloz.trial.ColorRecipesExplorer;
+package dev.fyloz.trial.colorrecipesexplorer.core.services;
import java.util.ArrayList;
import java.util.List;
-public class PasswordValidator {
+public class PasswordService {
private static List passwords = new ArrayList<>();
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/CompanyService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/CompanyService.java
new file mode 100644
index 0000000..bed4aa5
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/CompanyService.java
@@ -0,0 +1,40 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
+import dev.fyloz.trial.colorrecipesexplorer.dao.CompanyDao;
+import dev.fyloz.trial.colorrecipesexplorer.dao.RecipeDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CompanyService extends GenericService {
+
+ private RecipeDao recipeDao; // Utilise le Dao pour éviter une erreur au démarrage, citant une récursion (CompanyService -> RecipeService -> CompanyService -> ...)
+
+ @Autowired
+ public CompanyService(CompanyDao companyDao, RecipeDao recipeDao) {
+ super(companyDao);
+ this.recipeDao = recipeDao;
+ }
+
+ @Override
+ public boolean isValidForCreation(Company entity) {
+ return super.isValidForCreation(entity) && !existsByName(entity.getCompanyName());
+ }
+
+ public boolean existsByName(String name) {
+ return dao.existsByCompanyName(name);
+ }
+
+ public boolean isLinkedToRecipes(Company company) {
+ return !recipeDao.findAllByCompany(company).isEmpty();
+ }
+
+ public boolean deleteIfNotLinked(Company company) {
+ if (company == null) return false;
+ if (isLinkedToRecipes(company)) return false;
+
+ return delete(company);
+ }
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialService.java
similarity index 58%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialService.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialService.java
index b4c4fd2..5f81a5d 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialService.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialService.java
@@ -1,17 +1,23 @@
-package fyloz.trial.ColorRecipesExplorer.services;
+package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
-import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler;
-import fyloz.trial.ColorRecipesExplorer.dao.MaterialDao;
-import fyloz.trial.ColorRecipesExplorer.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
+import dev.fyloz.trial.colorrecipesexplorer.dao.MaterialDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
@Service
-public class MaterialService extends GenericService {
+public class MaterialService extends GenericService {
private MixQuantityService mixQuantityService;
@@ -21,14 +27,14 @@ public class MaterialService extends GenericService {
this.mixQuantityService = mixQuantityService;
}
- /**
- * Récupère la produit ayant le code spécifié dans la base de données.
- *
- * @param materialCode Le code du produit
- * @return Le produit correspondant au code.
- */
- public Material getByMaterialCode(String materialCode) {
- return ((MaterialDao) dao).findByMaterialCode(materialCode);
+ public Optional getByMaterialCode(String materialCode) {
+ return dao.findByMaterialCode(materialCode);
+ }
+
+ public List getAllByMaterialType(MaterialType materialType) {
+ if (materialType == null) return new ArrayList<>();
+
+ return dao.findAllByMaterialType(materialType);
}
/**
@@ -38,21 +44,43 @@ public class MaterialService extends GenericService {
* @return Si le produit est lié à d'autres mélanges.
*/
public boolean isLinkedToMixes(Material material) {
- return !mixQuantityService.getByMaterial(material).isEmpty();
+ return mixQuantityService.existsByMaterial(material);
}
public boolean deleteIfNotLinked(Material material) {
if (!isLinkedToMixes(material)) {
- return super.delete(material);
+ return delete(material);
}
return false;
}
@Override
- public boolean exists(Material entity) {
- Material material = getByMaterialCode(entity.getMaterialCode());
- return super.exists(entity) || material != null;
+ public boolean exists(Material material) {
+ return material != null && (super.exists(material) || dao.existsByMaterialCode(material.getMaterialCode()));
+ }
+
+ @Override
+ public boolean isValidForUpdate(Material material) {
+ if (material == null) return false;
+
+ Optional materialByCode = dao.findByMaterialCode(material.getMaterialCode());
+ return super.isValidForUpdate(material) && (!materialByCode.isPresent() || material.getMaterialID().equals(materialByCode.get().getMaterialID()));
+ }
+
+ public List getAllBySearchString(String searchString) {
+ return dao.findAllByMaterialCodeContainingIgnoreCase(searchString).stream().filter(m -> !m.isMixType()).collect(Collectors.toList());
+ }
+
+ /**
+ * Crée un FileHandler pour le produit passé en paramètre.
+ *
+ * @param material Le produit dont on veut créer un FileHandler
+ * @return Le FileHandler correspondant au produit.
+ */
+ private FileHandler getFileHandlerForMaterial(Material material) {
+ String filename = String.format("%s_%s", material.getMaterialID(), material.getMaterialCode());
+ return new FileHandler(filename, FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF);
}
/**
@@ -66,9 +94,9 @@ public class MaterialService extends GenericService {
* @return Si le fichier SIMDUT à bien été créé ou non.
*/
public boolean addSimdut(MultipartFile simdut, Material material) {
- if (simdut.getSize() <= 0) return true;
+ if (simdut.getSize() <= 0) return false;
- FileHandler fileHandler = getFilesServiceForMaterial(material);
+ FileHandler fileHandler = getFileHandlerForMaterial(material);
if (!fileHandler.createFile()) {
return false;
@@ -92,7 +120,7 @@ public class MaterialService extends GenericService {
* @return Si la suppression du fichier SIMDUT s'est effectuée.
*/
public boolean removeSimdut(Material material) {
- FileHandler fileHandler = getFilesServiceForMaterial(material);
+ FileHandler fileHandler = getFileHandlerForMaterial(material);
if (fileHandler.getFile().exists()) {
return fileHandler.deleteFile();
@@ -100,15 +128,4 @@ public class MaterialService extends GenericService {
return true;
}
-
- /**
- * Crée un FileHandler pour le produit passé en paramètre.
- *
- * @param material Le produit dont on veut créer un FileHandler
- * @return Le FileHandler correspondant au produit.
- */
- private FileHandler getFilesServiceForMaterial(Material material) {
- String filename = String.format("%s_%s", material.getMaterialID(), material.getMaterialCode());
- return new FileHandler(filename, FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF);
- }
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialTypeService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialTypeService.java
new file mode 100644
index 0000000..99aa914
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MaterialTypeService.java
@@ -0,0 +1,69 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
+import dev.fyloz.trial.colorrecipesexplorer.dao.MaterialTypeDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+@Service
+public class MaterialTypeService extends GenericService {
+
+ private MaterialService materialService;
+
+ @Autowired
+ public MaterialTypeService(MaterialTypeDao materialTypeDao, MaterialService materialService) {
+ super(materialTypeDao);
+ this.materialService = materialService;
+ }
+
+ public boolean isLinkedToMaterials(MaterialType materialType) {
+ return !materialService.getAllByMaterialType(materialType).isEmpty();
+ }
+
+ public boolean deleteIfNotLinked(MaterialType materialType) {
+ if (!isLinkedToMaterials(materialType)) {
+ return delete(materialType);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isValidForCreation(MaterialType entity) {
+ return entity != null && !existsByName(entity.getMaterialTypeName());
+ }
+
+ @Override
+ public boolean isValidForUpdate(MaterialType materialType) {
+ return super.isValidForUpdate(materialType)
+ && isValidForUpdateName(materialType)
+ && isValidForUpdatePrefix(materialType);
+ }
+
+ public boolean isValidForUpdateName(MaterialType materialType) {
+ Optional materialTypeByName = dao.findByMaterialTypeName(materialType.getMaterialTypeName());
+
+ return !materialTypeByName.isPresent() || materialType.getMaterialTypeID().equals(materialTypeByName.get().getMaterialTypeID());
+ }
+
+ public boolean isValidForUpdatePrefix(MaterialType materialType) {
+ Optional materialTypeByPrefix = dao.findByPrefix(materialType.getPrefix());
+
+ return !materialTypeByPrefix.isPresent() || materialType.getMaterialTypeID().equals(materialTypeByPrefix.get().getMaterialTypeID());
+ }
+
+ public Optional getByName(String name) {
+ return dao.findByMaterialTypeName(name);
+ }
+
+ public Optional getDefaultMaterialType() {
+ return getByName(MaterialType.DEFAULT_MATERIAL_TYPE_NAME);
+ }
+
+ public boolean existsByName(String name) {
+ return getByName(name).isPresent();
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixQuantityService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixQuantityService.java
new file mode 100644
index 0000000..7774f78
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixQuantityService.java
@@ -0,0 +1,21 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
+import dev.fyloz.trial.colorrecipesexplorer.dao.MixQuantityDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MixQuantityService extends GenericService {
+
+ @Autowired
+ public MixQuantityService(MixQuantityDao mixQuantityDao) {
+ super(mixQuantityDao);
+ }
+
+ public boolean existsByMaterial(Material material) {
+ return dao.existsByMaterial(material);
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixService.java
new file mode 100644
index 0000000..e83e7ba
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixService.java
@@ -0,0 +1,130 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.*;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.dto.MixCreationFormDto;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
+import dev.fyloz.trial.colorrecipesexplorer.dao.MixDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.validation.constraints.NotNull;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class MixService extends GenericService {
+
+ private MaterialService materialService;
+ private MixQuantityService mixQuantityService;
+ private MixTypeService mixTypeService;
+ private RecipeService recipeService;
+
+ @Autowired
+ public MixService(MixDao mixDao, MaterialService materialService, MixQuantityService mixQuantityService, MixTypeService mixTypeService, RecipeService recipeService) {
+ super(mixDao);
+ this.materialService = materialService;
+ this.mixQuantityService = mixQuantityService;
+ this.mixTypeService = mixTypeService;
+ this.recipeService = recipeService;
+ }
+
+ @Transactional
+ public ModelResponseBuilder create(MixCreationFormDto formDto, @NotNull Recipe recipe) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
+
+ List materials = new ArrayList<>();
+ for (String materialCode : formDto.getMaterials()) {
+ Optional found = materialService.getByMaterialCode(materialCode);
+ if (!found.isPresent()) {
+ return modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND_BY_NAME, materialCode);
+ }
+
+ materials.add(found.get());
+ }
+
+ Optional optionalMixType = mixTypeService.createByName(formDto.getMixTypeName());
+ if (!optionalMixType.isPresent()) return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
+
+ MixType mixType = optionalMixType.get();
+ if (recipeService.hasMixType(recipe, mixType))
+ return modelResponseBuilder.addResponseCode(ResponseCode.MIX_TYPE_ALREADY_USED, mixType.getTypeName());
+
+ // Crée le mélange en premier pour avoir accès à son ID pour les autres éléments
+ Mix mix = new Mix(recipe, mixType, null);
+
+ Optional savedMix = save(mix);
+ if (savedMix.isPresent()) {
+ mix = savedMix.get();
+
+ List mixQuantities = createMixQuantities(savedMix.get(), materials, formDto.getQuantities());
+ mix.setMixQuantities(mixQuantities);
+
+ // Retourne aucune erreur s'il la mise à jour à lieu
+ if (update(mix).isPresent()) return null;
+
+ deleteMix(mix);
+ }
+
+ return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
+ }
+
+ @Transactional
+ public ModelResponseBuilder edit(Mix mix, MixCreationFormDto formDto) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
+
+ List materials = new ArrayList<>();
+ for (String materialCode : formDto.getMaterials()) {
+ Optional found = materialService.getByMaterialCode(materialCode);
+ if (!found.isPresent()) {
+ return modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND_BY_NAME, materialCode);
+ }
+
+ materials.add(found.get());
+ }
+
+ List mixQuantities = createMixQuantities(mix, materials, formDto.getQuantities());
+
+ // Supprime les anciens MixQuantity pour éviter les doublons et les entrées inutiles dans la base de données
+ if (!mixQuantityService.deleteAll(mix.getMixQuantities())) {
+ return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
+ }
+
+ mix.setMixQuantities(mixQuantities);
+ if (update(mix).isPresent()) return null;
+ else return modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
+ }
+
+ public boolean deleteMix(Mix mix) {
+ if (mixQuantityService.deleteAll(mix.getMixQuantities())) {
+ return super.delete(mix);
+ }
+
+ return false;
+ }
+
+ /**
+ * Crée une liste de MixQuantity, pour la création d'un mélange
+ *
+ * @param mix Le mélange associé aux MixQuantity
+ * @param materials Les matériaux
+ * @param quantities Les quantités
+ * @return La liste des MixQuantity créés.
+ */
+ public List createMixQuantities(Mix mix, List materials, List quantities) {
+ List mixQuantities = new ArrayList<>();
+
+ for (int i = 0; i < materials.size(); i++) {
+ Material material = materials.get(i);
+ float quantity = quantities.get(i);
+
+ MixQuantity mixQuantity = new MixQuantity(mix, material, quantity);
+ mixQuantities.add(mixQuantity);
+ }
+
+ return mixQuantities;
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixTypeService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixTypeService.java
new file mode 100644
index 0000000..dbd70c9
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/MixTypeService.java
@@ -0,0 +1,46 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
+import dev.fyloz.trial.colorrecipesexplorer.dao.MixTypeDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+@Service
+public class MixTypeService extends GenericService {
+
+ private MaterialTypeService materialTypeService;
+
+ @Autowired
+ public MixTypeService(MixTypeDao mixTypeDao, MaterialTypeService materialTypeService) {
+ super(mixTypeDao);
+ this.materialTypeService = materialTypeService;
+ }
+
+ public Optional getByName(String name) {
+ return dao.findByTypeName(name);
+ }
+
+ public Optional getByMaterial(Material material) {
+ return dao.findByMaterial(material);
+ }
+
+ public Optional createByName(String name) {
+ Optional defaultType = materialTypeService.getDefaultMaterialType();
+ if (!defaultType.isPresent()) return Optional.empty();
+
+ Optional mixTypeByName = getByName(name);
+ if (mixTypeByName.isPresent()) {
+ return mixTypeByName;
+ }
+
+ Material mixTypeMaterial = new Material(name, 0, true, defaultType.get());
+ MixType mixType = new MixType(name, mixTypeMaterial);
+
+ return save(mixType);
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/RecipeService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/RecipeService.java
new file mode 100644
index 0000000..37aaa80
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/RecipeService.java
@@ -0,0 +1,196 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.file.ImageHandler;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.*;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
+import dev.fyloz.trial.colorrecipesexplorer.dao.RecipeDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.MultiValueMap;
+
+import java.io.File;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class RecipeService extends GenericService {
+
+ private CompanyService companyService;
+ private StepService stepService;
+
+ @Autowired
+ public RecipeService(RecipeDao recipeDao, CompanyService companyService, StepService stepService) {
+ super(recipeDao);
+ this.companyService = companyService;
+ this.stepService = stepService;
+ }
+
+ /**
+ * Récupère la liste des recettes associées à une compagnie.
+ *
+ * @param company La compagnie.
+ * @return La liste des recettes associées à cette compagnie.
+ */
+ public List getByCompany(Company company) {
+ return dao.findAllByCompany(company);
+ }
+
+ /**
+ * Récupère une liste triée des mélanges pour une recette.
+ *
+ * @param recipe La recette dont on veut récupérer les mélanges
+ * @return Une liste triée des mélanges.
+ */
+ public List getSortedMixes(Recipe recipe) {
+ List mixes = recipe.getRecipeMixes();
+ mixes.sort(Comparator.comparing(Mix::getMixID));
+ return mixes;
+ }
+
+ /**
+ * Récupère toutes les recettes dans la base de données et les classes par compagnie.
+ *
+ * @return Un Map contenant les recettes classées par compagnie.
+ */
+ public Map> getRecipesByCompany() {
+ return mappedByCompany(getAll());
+ }
+
+ public Optional updateRecipe(Recipe newRecipe, Recipe storedRecipe, MultiValueMap form) {
+ storedRecipe.setRecipeCode(newRecipe.getRecipeCode());
+ storedRecipe.setCompany(newRecipe.getCompany());
+ storedRecipe.setRecipeDescription(newRecipe.getRecipeDescription());
+ storedRecipe.setSample(newRecipe.getSample());
+ storedRecipe.setApprobationDate(newRecipe.getApprobationDate());
+ storedRecipe.setRemark(newRecipe.getRemark());
+ storedRecipe.setNote(newRecipe.getNote());
+
+ Optional optionalRecipe = convertAndCreateSteps(storedRecipe, form);
+ if (!optionalRecipe.isPresent()) {
+ return Optional.empty();
+ }
+
+ return update(optionalRecipe.get());
+ }
+
+ @Transactional
+ public boolean deleteRecipe(Recipe recipe) {
+ if (!delete(recipe)) return false;
+ return removeAllFiles(recipe);
+ }
+
+ /**
+ * Récupère le nom des images liées à une recette.
+ *
+ * @param recipe La recette dont on veut récupérer les images
+ * @return Une liste contenant le nom des images liées à la recette.
+ */
+ public List getImageFiles(Recipe recipe) {
+ int recipeID = recipe.getRecipeID();
+ String recipeCode = recipe.getRecipeCode();
+ String fileName = String.format("%s_%s", recipeID, recipeCode);
+
+ File imageLocation = new File(ImageHandler.IMAGES_LOCATION);
+ File[] result = imageLocation.listFiles((d, n) -> n.startsWith(fileName) && n.endsWith("jpeg"));
+
+ if (result == null) return new ArrayList<>();
+
+ return Arrays.stream(result).map(File::getName).collect(Collectors.toList());
+ }
+
+ /**
+ * Récupère les types de mélanges associés à la recette.
+ *
+ * @param recipe La recette dont on veut récupérer les types de mélange
+ * @return Une liste contenant les types de mélanges.
+ */
+ public List getAssociatedMixesTypes(Recipe recipe) {
+ return recipe
+ .getRecipeMixes()
+ .stream()
+ .map(Mix::getMixType)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Vérifie si une recette contient un mélange ayant le type de mélange spécifié.
+ *
+ * @param recipe La recette
+ * @param mixType Le type de mélange
+ * @return Si la recette contient le type de mélange
+ */
+ public boolean hasMixType(Recipe recipe, MixType mixType) {
+ return getAssociatedMixesTypes(recipe)
+ .contains(mixType);
+ }
+
+ public Map> getRecipesForSearchString(String searchString) {
+ List recipes = dao.findAllByRecipeDescriptionContainsOrRecipeCodeContains(searchString.toUpperCase());
+
+ return mappedByCompany(recipes);
+ }
+
+ private Map> mappedByCompany(List recipes) {
+ List companies = companyService.getAll();
+ Map> mappedRecipes = new HashMap<>();
+
+ for (Company c : companies) {
+ List recipesForCompany = recipes.stream().filter(r -> r.getCompany().equals(c)).collect(Collectors.toList());
+
+ if (recipesForCompany.size() > 0) {
+ mappedRecipes.put(c, recipesForCompany);
+ }
+ }
+
+ return mappedRecipes;
+ }
+
+ /**
+ * Crée et assigne des étapes à une recette, en se basant sur l'entrée de utilisateur.
+ *
+ * @param recipe La recette à assigner les étapes
+ * @param input L'entrée de l'utilisateur, contenant les étapes (key = "step_*")
+ * @return La recette avec les étapes.
+ */
+ @Transactional
+ public Optional convertAndCreateSteps(Recipe recipe, MultiValueMap input) {
+ if (recipe == null || input == null) return Optional.empty();
+
+ // Convertit les étapes en RecipeSteps
+ List steps = new ArrayList<>();
+ if (input.containsKey("step")) {
+ Object field = input.get("step");
+
+ if (field instanceof LinkedList && ((LinkedList) field).getFirst() instanceof String) {
+ for (String step : (LinkedList) field) {
+ steps.add(new RecipeStep(recipe, step));
+ }
+ }
+ }
+
+ return setSteps(recipe, steps);
+ }
+
+ private Optional setSteps(Recipe recipe, List steps) {
+ if (!stepService.deleteAll(recipe.getRecipeSteps())) return Optional.empty();
+
+ recipe.setRecipeSteps(null);
+ update(recipe);
+
+ recipe.setRecipeSteps(steps);
+ return Optional.of(recipe);
+ }
+
+ private boolean removeAllFiles(Recipe recipe) {
+ FileHandler fileHandler;
+ for (String image : getImageFiles(recipe)) {
+ fileHandler = new FileHandler(image.replace(".jpeg", ""), FileHandler.FileContext.IMAGE, FileHandler.FileExtension.JPEG);
+
+ if (!fileHandler.deleteFile()) return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/StepService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/StepService.java
new file mode 100644
index 0000000..8063109
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/services/model/StepService.java
@@ -0,0 +1,16 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.services.model;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.GenericService;
+import dev.fyloz.trial.colorrecipesexplorer.dao.StepDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class StepService extends GenericService {
+
+ @Autowired
+ public StepService(StepDao stepDao) {
+ super(stepDao);
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/ControllerUtils.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/ControllerUtils.java
new file mode 100644
index 0000000..8685fd7
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/ControllerUtils.java
@@ -0,0 +1,26 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.utils;
+
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class ControllerUtils {
+
+ public static String redirect(String viewName) {
+ return String.format("redirect:/%s", viewName);
+ }
+
+ public static String getCurrentBaseUrl() {
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ if (attributes == null) {
+ return null;
+ }
+
+ HttpServletRequest request = attributes.getRequest();
+
+ String port = ":" + (ColorRecipesExplorerApplication.USE_PORT ? request.getServerPort() : "");
+ return String.format("%s://%s%s%s", request.getScheme(), request.getServerName(), port, request.getContextPath());
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/FileUtils.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/FileUtils.java
new file mode 100644
index 0000000..be7277a
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/core/utils/FileUtils.java
@@ -0,0 +1,22 @@
+package dev.fyloz.trial.colorrecipesexplorer.core.utils;
+
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+public class FileUtils {
+
+ public static String readClasspathFile(ResourceLoader loader, String path) {
+ try (InputStream stream = loader.getResource(path).getInputStream()) {
+ byte[] data = FileCopyUtils.copyToByteArray(stream);
+ return new String(data, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/CompanyDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/CompanyDao.java
similarity index 50%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/dao/CompanyDao.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/CompanyDao.java
index 003e036..2785ed3 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/CompanyDao.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/CompanyDao.java
@@ -1,13 +1,11 @@
-package fyloz.trial.ColorRecipesExplorer.dao;
+package dev.fyloz.trial.colorrecipesexplorer.dao;
-import fyloz.trial.ColorRecipesExplorer.model.Company;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CompanyDao extends JpaRepository {
- void deleteByCompanyID(int companyID);
-
- Company findByCompanyName(String companyName);
+ boolean existsByCompanyName(String companyName);
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialDao.java
new file mode 100644
index 0000000..8014e54
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialDao.java
@@ -0,0 +1,20 @@
+package dev.fyloz.trial.colorrecipesexplorer.dao;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface MaterialDao extends JpaRepository {
+ Optional findByMaterialCode(String materialCode);
+
+ List findAllByMaterialType(MaterialType materialType);
+
+ List findAllByMaterialCodeContainingIgnoreCase(String stringSearch);
+
+ boolean existsByMaterialCode(String materialCode);
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialTypeDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialTypeDao.java
new file mode 100644
index 0000000..96ba4dc
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MaterialTypeDao.java
@@ -0,0 +1,14 @@
+package dev.fyloz.trial.colorrecipesexplorer.dao;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface MaterialTypeDao extends JpaRepository {
+
+ Optional findByMaterialTypeName(String name);
+
+ Optional findByPrefix(String prefix);
+
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixDao.java
similarity index 62%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixDao.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixDao.java
index 729df1b..46a2b3c 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixDao.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixDao.java
@@ -1,7 +1,7 @@
-package fyloz.trial.ColorRecipesExplorer.dao;
+package dev.fyloz.trial.colorrecipesexplorer.dao;
-import fyloz.trial.ColorRecipesExplorer.model.Mix;
-import fyloz.trial.ColorRecipesExplorer.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixQuantityDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixQuantityDao.java
similarity index 55%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixQuantityDao.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixQuantityDao.java
index 463a157..1a41d6a 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixQuantityDao.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixQuantityDao.java
@@ -1,7 +1,7 @@
-package fyloz.trial.ColorRecipesExplorer.dao;
+package dev.fyloz.trial.colorrecipesexplorer.dao;
-import fyloz.trial.ColorRecipesExplorer.model.Material;
-import fyloz.trial.ColorRecipesExplorer.model.MixQuantity;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@@ -9,7 +9,7 @@ import java.util.List;
@Repository
public interface MixQuantityDao extends JpaRepository {
- MixQuantity findByMixQuantityID(int mixQuantityID);
-
List findAllByMaterial(Material material);
+
+ boolean existsByMaterial(Material material);
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixTypeDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixTypeDao.java
new file mode 100644
index 0000000..5ae466d
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/MixTypeDao.java
@@ -0,0 +1,15 @@
+package dev.fyloz.trial.colorrecipesexplorer.dao;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface MixTypeDao extends JpaRepository {
+ Optional findByTypeName(String typeName);
+
+ Optional findByMaterial(Material material);
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/RecipeDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/RecipeDao.java
new file mode 100644
index 0000000..7ed35d4
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/RecipeDao.java
@@ -0,0 +1,22 @@
+package dev.fyloz.trial.colorrecipesexplorer.dao;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface RecipeDao extends JpaRepository {
+
+ List findAllByCompany(Company company);
+
+ Recipe findByRecipeCode(String recipeCode);
+
+ Recipe findByRecipeID(int recipeID);
+
+ @Query("select r from Recipe r where upper(r.recipeCode) like %?1% or upper(r.recipeDescription) like %?1%")
+ List findAllByRecipeDescriptionContainsOrRecipeCodeContains(String searchWordUpperCase);
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/StepDao.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/StepDao.java
similarity index 58%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/dao/StepDao.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/StepDao.java
index 9d04a0a..5b998a7 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/StepDao.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/dao/StepDao.java
@@ -1,7 +1,7 @@
-package fyloz.trial.ColorRecipesExplorer.dao;
+package dev.fyloz.trial.colorrecipesexplorer.dao;
-import fyloz.trial.ColorRecipesExplorer.model.Recipe;
-import fyloz.trial.ColorRecipesExplorer.model.RecipeStep;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/PagesPaths.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/PagesPaths.java
similarity index 69%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/PagesPaths.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/PagesPaths.java
index cf1dbbd..6000b93 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/PagesPaths.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/PagesPaths.java
@@ -1,17 +1,25 @@
-package fyloz.trial.ColorRecipesExplorer.web;
+package dev.fyloz.trial.colorrecipesexplorer.web;
public class PagesPaths {
// Autres
public static final String INDEX = "index";
+ public static final String SEARCH = "search";
+ public static final String SEARCH_INVENTORY = "inventory/search";
public static final String SIMDUT_FILES = "simdut/{materialID}";
public static final String PASSWORD_VALIDATION = "password/valid";
public static final String TOUCHUP = "touchup";
+ public static final String RECIPE_XLS = "recipe/xls/{recipeID}";
+ public static final String ALL_RECIPES_XLS = "recipe/xls";
+ public static final String ERROR = "error";
+ public static final String CLOSE_TAB = "closeTab";
+ public static final String UPDATES = "updates";
+ public static final String UPDATES_GET = "updates/get";
// Images
public static final String IMAGES_FILES = "images/{image}";
public static final String ADD_IMAGE = "images/add";
public static final String ADD_IMAGE_SPECIFIC = "images/add/{recipeID}";
- public static final String DELETE_IMAGE = "images/deleteIfNotLinked";
+ public static final String DELETE_IMAGE = "images/delete";
// Inventaire
public static final String INVENTORY = "inventory";
@@ -47,6 +55,11 @@ public class PagesPaths {
// Types de matériaux
public static final String CREATOR_MATERIAL_TYPE = "materialType/creator";
+ public static final String REMOVER_MATERIAL_TYPE = "materialType/remover";
+ public static final String REMOVER_MATERIAL_TYPE_SPECIFIC = "materialType/remover/{materialTypeID}";
+ public static final String EDITOR_MATERIAL_TYPE = "materialType/editor";
+ public static final String EDITOR_MATERIAL_TYPE_SPECIFIC = "materialType/editor/{materialTypeID}";
+ public static final String EDITOR_MATERIAL_TYPE_EDITOR = "materialType/edit";
// Mélanges
public static final String CREATOR_MIX = "mix/creator";
@@ -54,4 +67,6 @@ public class PagesPaths {
public static final String EDITOR_MIX = "mix/editor";
public static final String EDITOR_MIX_SPECIFIC = "mix/editor/{mixID}";
public static final String REMOVER_MIX_SPECIFIC = "mix/remover/{mixID}";
+ public static final String MATERIAL_SELECTOR_MIX = "mix/selector/{recipeID}/{mixID}";
+ public static final String MATERIAL_SELECTOR_FRAGMENT = "mix/selector.html :: materialSelector";
}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/StringBank.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/StringBank.java
similarity index 92%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/StringBank.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/StringBank.java
index ba3c1a6..598497d 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/StringBank.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/StringBank.java
@@ -1,4 +1,4 @@
-package fyloz.trial.ColorRecipesExplorer.web;
+package dev.fyloz.trial.colorrecipesexplorer.web;
public class StringBank {
@@ -48,8 +48,4 @@ public class StringBank {
public static final String COMPANY = "company";
public static final String COMPANY_ID = "companyID";
- public static final String UPLOAD_LOCATION = System.getProperty("upload.location");
- public static final String IMAGES_LOCATION = UPLOAD_LOCATION + "/images";
- public static final String SIMDUTS_LOCATION = UPLOAD_LOCATION + "/simdut/";
-
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/CREErrorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/CREErrorController.java
new file mode 100644
index 0000000..51716fb
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/CREErrorController.java
@@ -0,0 +1,51 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import org.springframework.boot.web.servlet.error.ErrorController;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.http.HttpServletRequest;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.ERROR;
+
+@Controller
+public class CREErrorController implements ErrorController {
+
+ @RequestMapping("/error")
+ public ModelAndView handleError(HttpServletRequest request) {
+ ModelResponseBuilder responseBuilder = new ModelResponseBuilder("error");
+ responseBuilder.addAttribute("referer", request.getHeader("referer"));
+
+ Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
+
+ ResponseCode responseCode = ResponseCode._500;
+ if (status != null) {
+ int statusCode = Integer.parseInt(status.toString());
+
+ switch (statusCode) {
+ case 401:
+ responseCode = ResponseCode._401;
+ break;
+ case 404:
+ responseCode = ResponseCode._404;
+ break;
+ default:
+ responseCode = ResponseCode._500;
+ break;
+ }
+ }
+
+ responseBuilder.addResponseCode(responseCode);
+ return responseBuilder.build();
+ }
+
+ @Override
+ public String getErrorPath() {
+ return ERROR;
+ }
+
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/ImageFilesController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/ImageFilesController.java
similarity index 58%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/ImageFilesController.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/ImageFilesController.java
index 109e579..9cef050 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/ImageFilesController.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/ImageFilesController.java
@@ -1,12 +1,14 @@
-package fyloz.trial.ColorRecipesExplorer.web.controller;
+package dev.fyloz.trial.colorrecipesexplorer.web.controller;
-import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication;
-import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
-import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
-import fyloz.trial.ColorRecipesExplorer.core.ResponseCode;
-import fyloz.trial.ColorRecipesExplorer.core.io.ImageHandler;
-import fyloz.trial.ColorRecipesExplorer.model.Recipe;
-import fyloz.trial.ColorRecipesExplorer.services.RecipeService;
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.file.ImageHandler;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -17,15 +19,13 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
+import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
-import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
-import static fyloz.trial.ColorRecipesExplorer.core.utils.ControllerUtils.redirect;
-import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.*;
-import static fyloz.trial.ColorRecipesExplorer.web.StringBank.ERROR_SAVING_IMAGE;
-import static fyloz.trial.ColorRecipesExplorer.web.StringBank.RESPONSE_ERROR;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
@Controller
public class ImageFilesController {
@@ -68,9 +68,9 @@ public class ImageFilesController {
*/
@GetMapping(ADD_IMAGE_SPECIFIC)
public ModelAndView showPage(ModelAndView model, @PathVariable int recipeID) {
- return new ModelBuilder(model)
- .setView(ADD_IMAGE)
- .addData(ModelDataType.RECIPE_ID, recipeID)
+ return new ModelResponseBuilder(model)
+ .withView(ADD_IMAGE)
+ .addResponseData(ResponseDataType.RECIPE_ID, recipeID)
.build();
}
@@ -95,37 +95,45 @@ public class ImageFilesController {
* @return La page à afficher.
*/
@PostMapping(ADD_IMAGE)
- public ModelAndView addImage(int recipeID, MultipartFile image) {
- ModelBuilder modelBuilder = new ModelBuilder(redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(recipeID))));
- Recipe recipe = recipeService.getByID(recipeID);
+ public ModelAndView addImage(int recipeID, MultipartFile image) throws IOException {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(recipeID))));
- if (recipe == null) {
- modelBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, String.valueOf(recipeID));
-
- return showPage(modelBuilder.build(), recipeID);
+ // Vérifie que le fichier est bien une image
+ if (ImageIO.read(image.getInputStream()) == null) {
+ return showPage(modelResponseBuilder
+ .addResponseCode(ResponseCode.FILE_NOT_IMAGE)
+ .build(), recipeID);
}
+ Optional optionalRecipe = recipeService.getByID(recipeID);
+ if (!optionalRecipe.isPresent()) {
+ return showPage(modelResponseBuilder
+ .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
+ .build(), recipeID);
+ }
+
+ Recipe recipe = optionalRecipe.get();
ImageHandler imageHandler = new ImageHandler(recipe, recipeService);
if (!imageHandler.createFile()) {
- modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE);
-
- return showPage(modelBuilder.build(), recipeID);
+ return showPage(modelResponseBuilder
+ .addResponseCode(ResponseCode.ERROR_SAVING_IMAGE)
+ .build(), recipeID);
}
- modelBuilder
- .addData(ModelDataType.RECIPE_CODE, recipe.getRecipeCode())
- .addData(ModelDataType.RECIPE_ID, recipe.getRecipeID());
+ modelResponseBuilder
+ .addResponseData(ResponseDataType.RECIPE_CODE, recipe.getRecipeCode())
+ .addResponseData(ResponseDataType.RECIPE_ID, recipe.getRecipeID());
try {
// Si je n'utilise pas le path, il cherche un fichier dans les tmp ?
image.transferTo(new File(imageHandler.getFile().getAbsolutePath()));
- return modelBuilder.build();
+ return modelResponseBuilder.build();
} catch (IOException e) {
- ColorRecipesExplorerApplication.logger.error("Erreur inconnue lors de la création d'une image", e);
- modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE);
+ ColorRecipesExplorerApplication.LOGGER.error("Erreur inconnue lors de la création d'une image", e);
+ modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE);
- return showPage(modelBuilder.build(), recipeID);
+ return showPage(modelResponseBuilder.build(), recipeID);
}
}
@@ -142,18 +150,18 @@ public class ImageFilesController {
* REQUIERT UNE AUTORISATION
*
* @param form Le formulaire contenant les informations sur l'opération
- * @return La réponse sous forme de Map (-> Json)
+ * @return La réponse sous forme de Map (pour y accéder en Json)
*/
@PostMapping(value = DELETE_IMAGE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
- public Map deleteImage(@RequestBody Map form) {
- Map response = new HashMap<>();
+ public Map deleteImage(@RequestBody Map form) {
+ JSONResponseBuilder responseBuilder = new JSONResponseBuilder();
ImageHandler imageHandler = new ImageHandler(form.get("image"), recipeService);
if (!imageHandler.deleteFile()) {
- response.put(RESPONSE_ERROR, ERROR_SAVING_IMAGE);
+ responseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_IMAGE);
}
- return response;
+ return responseBuilder.build();
}
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/IndexController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/IndexController.java
new file mode 100644
index 0000000..cc51792
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/IndexController.java
@@ -0,0 +1,81 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.PasswordService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
+
+@Controller
+public class IndexController {
+
+ private CompanyService companyService;
+ private RecipeService recipeService;
+
+ @Autowired
+ public IndexController(CompanyService companyService, RecipeService recipeService) {
+ this.companyService = companyService;
+ this.recipeService = recipeService;
+ }
+
+ /**
+ * Affiche la page d'acceuil.
+ *
+ * @return La page à afficher.
+ */
+ @GetMapping({INDEX, "/"})
+ public ModelAndView showPage() {
+ List companies = companyService.getAll();
+ Map> recipes = new HashMap<>();
+
+ for (Company company : companies) {
+ recipes.put(company, recipeService.getByCompany(company));
+ }
+
+ return new ModelResponseBuilder(INDEX)
+ .addResponseData(ResponseDataType.RECIPE_MAP, recipes)
+ .build();
+ }
+
+ @GetMapping(value = SEARCH, produces = MediaType.APPLICATION_JSON_VALUE)
+ @ResponseBody
+ public Map searchWord(@RequestParam String searchString) {
+ Map> searchResult = recipeService.getRecipesForSearchString(searchString);
+ Map> outputResult = new HashMap<>();
+
+ for (Company c : searchResult.keySet()) {
+ outputResult.put(c.getCompanyID(), searchResult.get(c).stream().map(Recipe::getRecipeID).collect(Collectors.toList()));
+ }
+
+ return new JSONResponseBuilder()
+ .addAttribute("result", outputResult)
+ .build();
+ }
+
+ /**
+ * Valide un mot de passe reçu dans une requête HTTP POST, dans le champ "password".
+ *
+ * @param data Corps de la requête HTTP
+ * @return Si le mot de passe est valide.
+ */
+ @PostMapping(value = PASSWORD_VALIDATION, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ @ResponseBody
+ public boolean validatePassword(@RequestBody Map data) {
+ return PasswordService.isValid((String) data.get("password"));
+ }
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/InventoryController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/InventoryController.java
similarity index 51%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/InventoryController.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/InventoryController.java
index bd9ea27..ed2ed89 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/InventoryController.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/InventoryController.java
@@ -1,33 +1,28 @@
-package fyloz.trial.ColorRecipesExplorer.web.controller;
+package dev.fyloz.trial.colorrecipesexplorer.web.controller;
-import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
-import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
-import fyloz.trial.ColorRecipesExplorer.model.Material;
-import fyloz.trial.ColorRecipesExplorer.model.Mix;
-import fyloz.trial.ColorRecipesExplorer.model.MixQuantity;
-import fyloz.trial.ColorRecipesExplorer.services.InventoryService;
-import fyloz.trial.ColorRecipesExplorer.services.MaterialService;
-import fyloz.trial.ColorRecipesExplorer.services.MaterialTypeService;
-import fyloz.trial.ColorRecipesExplorer.services.MixService;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.InventoryService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
-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.ResponseBody;
+import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.stream.Collectors;
-import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.INVENTORY;
-import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.USE_INVENTORY;
-import static fyloz.trial.ColorRecipesExplorer.web.StringBank.*;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
+import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.RESPONSE_REASON;
@Controller
public class InventoryController {
@@ -45,19 +40,12 @@ public class InventoryController {
this.materialTypeService = materialTypeService;
}
- /**
- * Affiche la page de l'inventaire.
- *
- * Modèle de la page:
- * - materials: Contient la liste de tous les matériaux
- *
- * @return La page à afficher.
- */
@GetMapping(INVENTORY)
public ModelAndView getInventory(ModelAndView model) {
- return new ModelBuilder(INVENTORY)
- .addData(ModelDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
- .addData(ModelDataType.MATERIAL_TYPES, materialTypeService.getAll())
+ return new ModelResponseBuilder(model)
+ .withView(INVENTORY)
+ .addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
+ .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
.build();
}
@@ -83,14 +71,14 @@ public class InventoryController {
* - success: Contient le message à affiche lors du succès de la méthode
*
* @param form Le JSON contenant les quantités à utiliser.
- * @return Une réponse sous forme de Map (-> Json).
+ * @return Une réponse sous forme de Map (vers Json).
*/
@PostMapping(value = USE_INVENTORY, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@Transactional
- // TODO traduits les méthodes JSON
- public Map consumeMaterials(@RequestBody Map form) {
- Map response = new HashMap<>();
+ // TODO traduit les méthodes JSON
+ public Map consumeMaterials(@RequestBody Map form) {
+ JSONResponseBuilder responseBuilder = new JSONResponseBuilder();
List mixes = new ArrayList<>();
Map> quantities = new HashMap<>();
@@ -98,12 +86,14 @@ public class InventoryController {
for (String mixIDStr : form.keySet()) {
int mixID = Integer.parseInt(mixIDStr);
- Mix mix = mixService.getByID(mixID);
- if (mix == null) {
- response.put(RESPONSE_ERROR, String.format(MIX_NOT_FOUND, mixID));
- return response;
+ Optional optionalMix = mixService.getByID(mixID);
+ if (!optionalMix.isPresent()) {
+ return responseBuilder
+ .addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID)
+ .build();
}
+ Mix mix = optionalMix.get();
mixes.add(mix);
Map formMaterials = (Map) form.get(mixIDStr);
@@ -123,20 +113,36 @@ public class InventoryController {
for (Mix mix : mixes) {
String errorCode = inventoryService.checkQuantities(mix, quantities.get(mix));
if (errorCode != null) {
- response.put(RESPONSE_ERROR, String.format(NOT_ENOUGH_MATERIAL, materialService.getByID(Integer.parseInt(errorCode.split("-")[1])).getMaterialCode()));
- response.put(RESPONSE_REASON, errorCode);
- return response;
+ String materialCode = materialService.getByID(Integer.parseInt(errorCode.split("-")[1])).orElse(new Material()).getMaterialCode();
+
+ return responseBuilder
+ .addResponseCode(ResponseCode.NOT_ENOUGH_MATERIAL, materialCode)
+ .addAttribute(RESPONSE_REASON, errorCode)
+ .build();
}
}
for (Mix mix : mixes) {
if (!inventoryService.useMix(mix, quantities.get(mix))) {
- response.put(RESPONSE_ERROR, ERROR_SAVING);
- return response;
+ return responseBuilder
+ .addResponseCode(ResponseCode.ERROR_SAVING)
+ .build();
}
}
- response.put(RESPONSE_SUCCESS, SUCCESS_USING_MATERIALS);
- return response;
+ return responseBuilder
+ .addResponseCode(ResponseCode.SUCCESS_USING_MATERIALS)
+ .build();
+ }
+
+ @GetMapping(value = SEARCH_INVENTORY, produces = MediaType.APPLICATION_JSON_VALUE)
+ @ResponseBody
+ public Map searchWordInventory(@RequestParam String searchString) {
+ List searchResult = materialService.getAllBySearchString(searchString);
+ List outputResult = searchResult.stream().map(Material::getMaterialID).collect(Collectors.toList());
+
+ return new JSONResponseBuilder()
+ .addAttribute("result", outputResult)
+ .build();
}
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/OthersController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/OthersController.java
new file mode 100644
index 0000000..e675c88
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/OthersController.java
@@ -0,0 +1,169 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller;
+
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.utils.FileUtils;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.XlsxExporter;
+import org.commonmark.node.Node;
+import org.commonmark.parser.Parser;
+import org.commonmark.renderer.html.HtmlRenderer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
+import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.MATERIALS;
+
+@Controller
+public class OthersController {
+
+ private RecipeService recipeService;
+ private MaterialService materialService;
+ private MixTypeService mixTypeService;
+ private MixService mixService;
+ private ResourceLoader resourceLoader;
+
+ @Autowired
+ public OthersController(RecipeService recipeService, MaterialService materialService, MixTypeService mixTypeService, MixService mixService, ResourceLoader resourceLoader) {
+ this.recipeService = recipeService;
+ this.materialService = materialService;
+ this.mixTypeService = mixTypeService;
+ this.mixService = mixService;
+ this.resourceLoader = resourceLoader;
+ }
+
+ @GetMapping(CLOSE_TAB)
+ public ModelAndView closeTab() {
+ return new ModelResponseBuilder(CLOSE_TAB).build();
+ }
+
+ @GetMapping(MATERIAL_SELECTOR_MIX)
+ public ModelAndView getMaterialSelectorFragment(@PathVariable int recipeID, @PathVariable int mixID) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(MATERIAL_SELECTOR_FRAGMENT);
+
+ Optional optionalRecipe = recipeService.getByID(recipeID);
+ if (!optionalRecipe.isPresent()) {
+ return modelResponseBuilder
+ .withView("")
+ .build();
+ }
+
+ Optional optionalMix = mixService.getByID(mixID);
+ boolean mixExist = optionalMix.isPresent();
+
+ List associatedMixTypes = recipeService.getAssociatedMixesTypes(optionalRecipe.get());
+ // Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette
+ List materials = materialService
+ .getAll()
+ .stream()
+ .filter(m -> !m.isMixType() || (!mixExist || !m.equals(optionalMix.get().getMixType().getMaterial())) && associatedMixTypes.contains(mixTypeService.getByMaterial(m).get()))
+ .sorted(Comparator.comparing(Material::getMaterialCode))
+ .sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName()))
+ .collect(Collectors.toList());
+
+ return modelResponseBuilder
+ .addAttribute(MATERIALS, materials)
+ .build();
+ }
+
+ @GetMapping(TOUCHUP)
+ public ModelAndView getTouchUpPdf() {
+ return new ModelResponseBuilder().withRedirect("pdf/touchup.pdf").build();
+ }
+
+ @GetMapping(RECIPE_XLS)
+ public ResponseEntity getXlsForRecipe(HttpServletRequest request, @PathVariable int recipeID) {
+ HttpHeaders headers = new HttpHeaders();
+
+ Optional optionalRecipe = recipeService.getByID(recipeID);
+ if (!optionalRecipe.isPresent()) {
+ headers.add(HttpHeaders.LOCATION, request.getHeader("referer"));
+ return new ResponseEntity<>(headers, HttpStatus.FOUND);
+ }
+
+ byte[] recipeXLS = new XlsxExporter().generate(optionalRecipe.get());
+ if (recipeXLS.length <= 0) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
+
+ return ResponseEntity.ok()
+ .headers(headers)
+ .contentLength(recipeXLS.length)
+ .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
+ .body(recipeXLS);
+ }
+
+ @GetMapping(value = ALL_RECIPES_XLS, produces = "application/zip")
+ public ResponseEntity getAllXls() throws IOException {
+ HttpHeaders headers = new HttpHeaders();
+
+ ColorRecipesExplorerApplication.LOGGER.info("Exportation de toutes les couleurs en XLS");
+
+ ByteArrayOutputStream byteOS = new ByteArrayOutputStream();
+ ZipOutputStream out = new ZipOutputStream(byteOS);
+
+ Collection recipes = recipeService.getAll();
+ for (Recipe recipe : recipes) {
+ byte[] recipeXLS = new XlsxExporter().generate(recipe);
+ if (recipeXLS.length <= 0) return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
+
+ out.putNextEntry(new ZipEntry(String.format("%s_%s.xlsx", recipe.getCompany().getCompanyName(), recipe.getRecipeCode())));
+ out.write(recipeXLS, 0, recipeXLS.length);
+ out.closeEntry();
+ }
+
+ out.close();
+
+ byte[] zipContent = byteOS.toByteArray();
+ byteOS.close();
+
+ return ResponseEntity.ok()
+ .headers(headers)
+ .contentLength(zipContent.length)
+ .contentType(MediaType.parseMediaType("application/zip"))
+ .body(zipContent);
+ }
+
+ @GetMapping(value = UPDATES)
+ public ModelAndView showUpdates() {
+ return new ModelResponseBuilder(UPDATES).build();
+ }
+
+ @GetMapping(value = UPDATES_GET, produces = MediaType.TEXT_HTML_VALUE)
+ @ResponseBody
+ public ResponseEntity getUpdates() throws IOException {
+ String fileContent = FileUtils.readClasspathFile(resourceLoader, "classpath:updates.md");
+ if (fileContent == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
+
+ Parser parser = Parser.builder().build();
+ Node document = parser.parse(fileContent);
+ HtmlRenderer renderer = HtmlRenderer.builder().build();
+
+ return new ResponseEntity<>(renderer.render(document), HttpStatus.OK);
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/RecipeExplorerController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/RecipeExplorerController.java
new file mode 100644
index 0000000..1e41a3b
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/RecipeExplorerController.java
@@ -0,0 +1,112 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.JSONResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.*;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
+
+@Controller
+public class RecipeExplorerController {
+
+ private RecipeService recipeService;
+ private MixService mixService;
+
+ @Autowired
+ public RecipeExplorerController(RecipeService recipeService, MixService mixService) {
+ this.recipeService = recipeService;
+ this.mixService = mixService;
+ }
+
+ /**
+ * Affiche la recette.
+ * Cette méthode requiert l'identifiant de la recette à affiche dans l'URL.
+ *
+ * Modèle de la page:
+ * - error: Contient le message d'erreur, s'il y a lieu
+ * - recipe: Contient la recette
+ * - mixes: Contient les mélanges associées à la recette
+ * - images: Contient la liste des noms des images associées à la recette
+ *
+ * @param recipeID L'identifiant de la recette
+ * @return La page à afficher.
+ */
+ @GetMapping(EXPLORER_RECIPE_SPECIFIC)
+ public ModelAndView showRecipe(@PathVariable int recipeID) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(EXPLORER_RECIPE);
+
+ Optional optionalRecipe = recipeService.getByID(recipeID);
+ if (!optionalRecipe.isPresent()) {
+ return modelResponseBuilder
+ .withView(INDEX)
+ .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
+ .build();
+ }
+
+ Recipe recipe = optionalRecipe.get();
+ List mixes = new ArrayList<>(recipe.getRecipeMixes()); // Convertit le PersistentBag en ArrayList
+ mixes.sort(Comparator.comparing(Mix::getMixID));
+
+ return modelResponseBuilder
+ .addResponseData(ResponseDataType.RECIPE, recipe)
+ .addResponseData(ResponseDataType.MIXES, mixes)
+ .addResponseData(ResponseDataType.IMAGES, recipeService.getImageFiles(recipe))
+ .build();
+ }
+
+ @PostMapping(value = EXPLORER_RECIPE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+ @ResponseBody
+ public Map saveRecipeInformations(@RequestBody Map form) {
+ JSONResponseBuilder responseBuilder = new JSONResponseBuilder();
+
+ int recipeID = Integer.parseInt(form.get("recipeID").toString());
+ Map location = (Map) form.get("locations");
+ String note = form.get("note").toString();
+
+ Optional optionalRecipe = recipeService.getByID(recipeID);
+ if (!optionalRecipe.isPresent()) {
+ responseBuilder.addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID);
+ } else {
+ Recipe recipe = optionalRecipe.get();
+
+ recipe.setNote(note);
+ recipeService.save(recipe);
+ }
+
+ for (String mixIDStr : location.keySet()) {
+ int mixID = Integer.parseInt(mixIDStr);
+
+ Optional optionalMix = mixService.getByID(mixID);
+ if (!optionalMix.isPresent()) {
+ responseBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID);
+ } else {
+ Mix mix = optionalMix.get();
+
+ if (mix.getRecipe().getRecipeID() != recipeID) {
+ responseBuilder.addResponseCode(ResponseCode.MIX_NOT_ASSOCIATED_WITH_RECIPE, mixID, recipeID);
+ } else {
+ mix.setLocation(location.get(mixIDStr));
+ mixService.update(mix);
+ }
+ }
+ }
+
+ if (!responseBuilder.containsErrors()) {
+ responseBuilder.addResponseCode(ResponseCode.SUCCESS_SAVING_RECIPE_INFORMATIONS);
+ }
+
+ return responseBuilder.build();
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/SIMDUTFilesController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/SIMDUTFilesController.java
new file mode 100644
index 0000000..0c2f046
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/SIMDUTFilesController.java
@@ -0,0 +1,62 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.file.FileHandler;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Optional;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CLOSE_TAB;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.SIMDUT_FILES;
+
+@Controller
+public class SIMDUTFilesController {
+
+ private MaterialService materialService;
+
+ @Autowired
+ public SIMDUTFilesController(MaterialService materialService) {
+ this.materialService = materialService;
+ }
+
+ @GetMapping(SIMDUT_FILES)
+ public ResponseEntity getFile(HttpServletRequest request, @PathVariable int materialID) {
+ Optional optionalMaterial = materialService.getByID(materialID);
+ HttpHeaders headers = new HttpHeaders();
+
+ if (!optionalMaterial.isPresent()) {
+ headers.add("Location", request.getHeader("referer"));
+ return new ResponseEntity<>(headers, HttpStatus.FOUND);
+ }
+
+ FileHandler fileHandler = new FileHandler(String.format("%s_%s", materialID, optionalMaterial.get().getMaterialCode()), FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF);
+ if (!fileHandler.isValid()) {
+ headers.add("Location", "/" + CLOSE_TAB);
+ return new ResponseEntity<>(headers, HttpStatus.FOUND);
+ }
+
+ byte[] fileContent = fileHandler.readFile();
+ headers.setContentType(MediaType.APPLICATION_PDF);
+ return new ResponseEntity<>(fileContent, headers, HttpStatus.OK);
+ }
+
+ @PostMapping(SIMDUT_FILES)
+ public ResponseEntity getFile(@PathVariable int materialID) {
+ Optional optionalMaterial = materialService.getByID(materialID);
+ if (!optionalMaterial.isPresent()) return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
+
+ FileHandler fileHandler = new FileHandler(String.format("%s_%s", materialID, optionalMaterial.get().getMaterialCode()), FileHandler.FileContext.SIMDUT, FileHandler.FileExtension.PDF);
+ if (!fileHandler.isValid()) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
+ return ResponseEntity.status(HttpStatus.FOUND).build();
+ }
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/CompanyCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/CompanyCreatorController.java
similarity index 54%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/CompanyCreatorController.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/CompanyCreatorController.java
index 7fc6e19..69c5328 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/creators/CompanyCreatorController.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/CompanyCreatorController.java
@@ -1,10 +1,10 @@
-package fyloz.trial.ColorRecipesExplorer.web.controller.creators;
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
-import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
-import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
-import fyloz.trial.ColorRecipesExplorer.core.ResponseCode;
-import fyloz.trial.ColorRecipesExplorer.model.Company;
-import fyloz.trial.ColorRecipesExplorer.services.CompanyService;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
@@ -14,9 +14,10 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid;
+import java.util.Optional;
-import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_COMPANY;
-import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.CREATOR_COMPANY_SUCCESS;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_COMPANY;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_COMPANY_SUCCESS;
@Controller
public class CompanyCreatorController {
@@ -28,16 +29,11 @@ public class CompanyCreatorController {
this.companyService = companyService;
}
- /**
- * Affiche la page de création d'une bannière.
- *
- * @return La page à afficher.
- */
@GetMapping(CREATOR_COMPANY)
public ModelAndView showCreationPage(ModelAndView model, Company company) {
- return new ModelBuilder(model)
- .setView(CREATOR_COMPANY)
- .addData(ModelDataType.COMPANY, company)
+ return new ModelResponseBuilder(model)
+ .withView(CREATOR_COMPANY)
+ .addResponseData(ResponseDataType.COMPANY, company)
.build();
}
@@ -60,20 +56,22 @@ public class CompanyCreatorController {
*/
@PostMapping(value = CREATOR_COMPANY, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ModelAndView createCompany(@ModelAttribute @Valid Company company) {
- ModelBuilder modelBuilder = new ModelBuilder(CREATOR_COMPANY_SUCCESS);
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(CREATOR_COMPANY_SUCCESS);
if (companyService.isValidForCreation(company)) {
- if ((company = companyService.save(company)) != null) {
- return modelBuilder
- .addData(ModelDataType.COMPANY_NAME, company.getCompanyName())
+ Optional savedCompany = companyService.save(company);
+
+ if (savedCompany.isPresent()) {
+ return modelResponseBuilder
+ .addResponseData(ResponseDataType.COMPANY_NAME, savedCompany.get().getCompanyName())
.build();
} else {
- modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
+ modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
}
} else {
- modelBuilder.addResponseCode(ResponseCode.MIX_NOT_ASSOCIATED_WITH_RECIPE, company.getCompanyName(), null);
+ modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_ALREADY_EXIST, company.getCompanyName());
}
- return showCreationPage(modelBuilder.build(), company);
+ return showCreationPage(modelResponseBuilder.build(), company);
}
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialCreatorController.java
new file mode 100644
index 0000000..556ed6d
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialCreatorController.java
@@ -0,0 +1,89 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.validation.Valid;
+import java.util.Optional;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_MATERIAL;
+
+@Controller
+public class MaterialCreatorController {
+
+ private MaterialService materialService;
+ private MaterialTypeService materialTypeService;
+
+ @Autowired
+ public MaterialCreatorController(MaterialService materialService, MaterialTypeService materialTypeService) {
+ this.materialService = materialService;
+ this.materialTypeService = materialTypeService;
+ }
+
+ @GetMapping(CREATOR_MATERIAL)
+ public ModelAndView showCreationPage(ModelAndView model, Material material) {
+ return new ModelResponseBuilder(model)
+ .withView(CREATOR_MATERIAL)
+ .addResponseData(ResponseDataType.MATERIAL, material != null ? material : new Material())
+ .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
+ .build();
+ }
+
+ /**
+ * Permet à l'utilisateur de créer un produit.
+ *
+ * La création échouera si:
+ * - L'utilisateur n'est pas autorisé à effectuer cette action
+ * - Le produit existe déjà
+ * - Une erreur est survenue lors de la sauvegarde dans la base de données
+ *
+ * Modèle de la page:
+ * - error: Contient le message d'erreur, s'il y a lieu
+ * - materialCode: Contient le code de produit du produit créé
+ *
+ * REQUIERT UNE AUTORISATION
+ *
+ * @param material Le produit à créer
+ * @param simdut Le fichier SIMDUT du produit (optionnel)
+ * @return La page à afficher.
+ */
+ @PostMapping(value = CREATOR_MATERIAL, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public ModelAndView create(@Valid Material material, MultipartFile simdut) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
+
+ if (!materialService.exists(material)) {
+ Optional savedMaterial = materialService.save(material);
+
+ if (savedMaterial.isPresent()) {
+ material = savedMaterial.get();
+
+ modelResponseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode());
+
+ if (simdut.getSize() > 0 && !materialService.addSimdut(simdut, material)) {
+ modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
+ }
+
+ return showCreationPage(modelResponseBuilder
+ .addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode())
+ .build(), null);
+ } else {
+ modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
+ }
+ } else {
+ modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode());
+ }
+
+ return showCreationPage(modelResponseBuilder.build(), material);
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialTypeCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialTypeCreatorController.java
new file mode 100644
index 0000000..3ffa255
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MaterialTypeCreatorController.java
@@ -0,0 +1,54 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.validation.Valid;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_MATERIAL_TYPE;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.INDEX;
+
+@Controller
+public class MaterialTypeCreatorController {
+
+ private MaterialTypeService materialTypeService;
+
+ @Autowired
+ public MaterialTypeCreatorController(MaterialTypeService materialTypeService) {
+ this.materialTypeService = materialTypeService;
+ }
+
+ @GetMapping(CREATOR_MATERIAL_TYPE)
+ public ModelAndView showPage(ModelAndView model, MaterialType materialType) {
+ return new ModelResponseBuilder(model)
+ .withView(CREATOR_MATERIAL_TYPE)
+ .addResponseData(ResponseDataType.MATERIAL_TYPE, materialType == null ? new MaterialType() : materialType)
+ .build();
+ }
+
+ @PostMapping(CREATOR_MATERIAL_TYPE)
+ public ModelAndView create(@Valid MaterialType materialType) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect(INDEX));
+
+ if (materialTypeService.isValidForCreation(materialType)) {
+ if (materialTypeService.save(materialType) != null) {
+ return modelResponseBuilder.build();
+ } else {
+ modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
+ }
+ } else {
+ modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST, materialType.getMaterialTypeName());
+ }
+
+ return showPage(modelResponseBuilder.build(), materialType);
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MixCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MixCreatorController.java
new file mode 100644
index 0000000..edfbee0
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/MixCreatorController.java
@@ -0,0 +1,128 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.dto.MixCreationFormDto;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.validation.Valid;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
+
+@Controller
+public class MixCreatorController {
+
+ private MixService mixService;
+ private RecipeService recipeService;
+ private MaterialService materialService;
+ private MixTypeService mixTypeService;
+
+ @Autowired
+ public MixCreatorController(MixService mixService, RecipeService recipeService, MaterialService materialService, MixTypeService mixTypeService) {
+ this.mixService = mixService;
+ this.recipeService = recipeService;
+ this.materialService = materialService;
+ this.mixTypeService = mixTypeService;
+ }
+
+ /**
+ * Affiche la page de création d'un mélange.
+ * Cette méthode requiert l'identifiant d'une recette dans l'URL.
+ *
+ * @param model Le Model injecté par Thymeleaf
+ * @param recipeID L'identifiant de la recette
+ * @return La page à afficher.
+ */
+ @GetMapping(CREATOR_MIX_SPECIFIC)
+ public ModelAndView showCreationPage(ModelAndView model, @PathVariable int recipeID) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(model)
+ .withView(CREATOR_MIX);
+
+ Optional optionalRecipe = recipeService.getByID(recipeID);
+ if (!optionalRecipe.isPresent()) {
+ return modelResponseBuilder
+ .withView(ControllerUtils.redirect(EDITOR_RECIPE))
+ .build();
+ }
+
+ Recipe recipe = optionalRecipe.get();
+
+ List associatedMixTypes = recipeService.getAssociatedMixesTypes(recipe);
+ // Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette
+ List materials = materialService
+ .getAll()
+ .stream()
+ .filter(m -> !m.isMixType() || associatedMixTypes.contains(mixTypeService.getByMaterial(m).get()))
+ .sorted(Comparator.comparing(Material::getMaterialCode))
+ .sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName()))
+ .collect(Collectors.toList());
+
+ ModelResponseBuilder responseBuilder = modelResponseBuilder
+ .addResponseData(ResponseDataType.RECIPE, recipe)
+ .addAttribute("materialsJson", materialService.asJson(materials));
+
+ if (materialService.getAll().isEmpty()) {
+ responseBuilder.addResponseCode(ResponseCode.NO_MATERIAL)
+ .addResponseData(ResponseDataType.BLOCK_BUTTON, true);
+ }
+
+ return responseBuilder.build();
+ }
+
+ /**
+ * Permet à l'utilisateur de créer un mélange.
+ *
+ * La création échouera si:
+ * - L'utilisateur n'est pas autorisé à exécuter cette action
+ * - La recette n'existe pas
+ * - Un des produits n'existe pas
+ * - Une erreur est survenue lors de la sauvegarde du type de mélange
+ * - Une erreur est survenue lors de la sauvegarde du mélange
+ *
+ * Modèle de la page:
+ * - error: Contient le message d'erreur, s'il y a lieu
+ *
+ * REQUIERT UNE AUTORISATION
+ *
+ * @param form La formulaire du mélange entré par l'utilisateur
+ * @return La page à afficher.
+ */
+ @PostMapping(value = CREATOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ public ModelAndView createMix(@ModelAttribute @Valid MixCreationFormDto formDto) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
+
+ Recipe recipe = formDto.getRecipe();
+ if (recipe == null) return modelResponseBuilder
+ .withRedirect(EDITOR_RECIPE)
+ .addResponseCode(ResponseCode.RECIPE_NOT_FOUND_NO_PARAMS)
+ .build();
+
+ ModelResponseBuilder mixCreationResponse = mixService.create(formDto, recipe);
+ if (mixCreationResponse != null)
+ return showCreationPage(mixCreationResponse.build(), formDto.getRecipe().getRecipeID());
+
+ return modelResponseBuilder
+ .withRedirect(EDITOR_RECIPE_SPECIFIC, recipe.getRecipeID())
+ .build();
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/RecipeCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/RecipeCreatorController.java
new file mode 100644
index 0000000..750a237
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/creators/RecipeCreatorController.java
@@ -0,0 +1,77 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.creators;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.validation.Valid;
+import java.util.Optional;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_RECIPE;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.CREATOR_RECIPE_SUCCESS;
+
+@Controller
+public class RecipeCreatorController {
+
+ private RecipeService recipeService;
+ private CompanyService companyService;
+
+ @Autowired
+ public RecipeCreatorController(RecipeService recipeService, CompanyService companyService) {
+ this.recipeService = recipeService;
+ this.companyService = companyService;
+ }
+
+ @GetMapping(CREATOR_RECIPE)
+ public ModelAndView showCreationPage(ModelAndView model, Recipe recipe) {
+ ModelResponseBuilder responseBuilder = new ModelResponseBuilder(model)
+ .withView(CREATOR_RECIPE)
+ .addResponseData(ResponseDataType.COMPANIES, companyService.getAll())
+ .addResponseData(ResponseDataType.RECIPE, recipe == null ? new Recipe() : recipe);
+
+ if (companyService.getAll().isEmpty()) {
+ responseBuilder.addResponseCode(ResponseCode.NO_COMPANY)
+ .addResponseData(ResponseDataType.BLOCK_BUTTON, true);
+ }
+
+ return responseBuilder.build();
+ }
+
+ /**
+ * Permet à l'utilisateur de créer une nouvelle recette.
+ *
+ * La création échouera si:
+ * - L'utilisateur n'est pas autorisé à exécuter cette action
+ * - Une erreur est survenue lors de la sauvegarde dans la base de données
+ *
+ * Modèle de la page:
+ * - error: Contient le message d'erreur, s'il y a lieu
+ *
+ * REQUIERT UNE AUTORISATION
+ *
+ * @param recipe La recette à créer
+ * @return La page à afficher.
+ */
+ @PostMapping(value = CREATOR_RECIPE)
+ public ModelAndView createRecipe(@Valid Recipe recipe) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(CREATOR_RECIPE_SUCCESS);
+
+ Optional savedRecipe = recipeService.save(recipe);
+ if (savedRecipe.isPresent()) {
+ return modelResponseBuilder
+ .addResponseData(ResponseDataType.RECIPE, savedRecipe.get())
+ .build();
+ }
+ modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
+
+ return showCreationPage(modelResponseBuilder.build(), recipe);
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialEditorController.java
new file mode 100644
index 0000000..17ca51f
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialEditorController.java
@@ -0,0 +1,178 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+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.multipart.MultipartFile;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
+
+@Controller
+public class MaterialEditorController {
+
+ private MaterialService materialService;
+ private MaterialTypeService materialTypeService;
+
+ @Autowired
+ public MaterialEditorController(MaterialService materialService, MaterialTypeService materialTypeService) {
+ this.materialService = materialService;
+ this.materialTypeService = materialTypeService;
+ }
+
+ /**
+ * Affiche la page de tous les produits.
+ *
+ * Modèle de la page:
+ * - materials: La liste de tous les produits
+ *
+ * @param model Le Model injecté par Thymeleaf
+ * @return La page à afficher.
+ */
+ @GetMapping(EDITOR_MATERIAL)
+ public ModelAndView listMaterials(ModelAndView model) {
+ return new ModelResponseBuilder(model)
+ .withView(EDITOR_MATERIAL)
+ .addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
+ .build();
+ }
+
+ @GetMapping(EDITOR_MATERIAL_SPECIFIC)
+ public ModelAndView showEditPage(ModelAndView model, @PathVariable int materialID, Material material) {
+ ModelResponseBuilder responseBuilder = new ModelResponseBuilder(model)
+ .withView(EDITOR_MATERIAL_EDITOR);
+
+ if (material.getMaterialCode() == null) {
+ Optional optionalMaterial = materialService.getByID(materialID);
+
+ if (!optionalMaterial.isPresent()) {
+ return listMaterials(
+ responseBuilder
+ .addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID)
+ .build()
+ );
+ }
+
+ material = optionalMaterial.get();
+ }
+
+ return responseBuilder
+ .addResponseData(ResponseDataType.MATERIAL, material)
+ .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
+ .build();
+ }
+
+ /**
+ * Permet à l'utilisateur de modifier un produit.
+ *
+ * La modification échouera si:
+ * - L'utilisateur n'est pas autorisé à exécuter cette action
+ * - Il n'y a aucun produit avec l'identifiant passé en paramètre
+ * - Une erreur est survenue lors de la mise à jour dans la base de données
+ *
+ * Modèle de la page:
+ * - error: Contient le message d'erreur, s'il y a lieu
+ * - materialCode: Contient le code du produit mit à jour
+ *
+ * REQUIERT UNE AUTORISATION
+ *
+ * @param material Le produit à mettre à jour
+ * @return La page à afficher.
+ */
+ @PostMapping(value = EDITOR_MATERIAL, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ public ModelAndView saveEditedMaterial(Material material) {
+ ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
+ int materialID = material.getMaterialID();
+
+ if (!materialService.existsById(materialID)) {
+ responseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID);
+ } else if (!materialService.isValidForUpdate(material)) {
+ responseBuilder.addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode());
+
+ return showEditPage(
+ responseBuilder
+ .addResponseCode(ResponseCode.MATERIAL_ALREADY_EXIST, material.getMaterialCode())
+ .build(),
+ materialID, material);
+ } else {
+ Optional updatedMaterial = materialService.update(material);
+ if (updatedMaterial.isPresent()) {
+ responseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, updatedMaterial.get().getMaterialCode());
+ } else {
+ return showEditPage(
+ responseBuilder
+ .addResponseCode(ResponseCode.ERROR_SAVING)
+ .build(),
+ materialID, null);
+ }
+ }
+
+ return listMaterials(responseBuilder.build());
+ }
+
+ /**
+ * Affiche la page d'upload d'un fichier SIMDUT pour un produit
+ * Cette méthode requiert l'identifiant du produit dans l'URL
+ *
+ * Modèle de la page:
+ * - materialID: Contient l'identifiant du produit
+ *
+ * @param model Le Model injecté par Thymeleaf
+ * @param materialID L'identifiant du produit à modifier le SIMDUT
+ * @return La page à afficher.
+ */
+ @GetMapping(value = EDIT_MATERIAL_SIMDUT_SPECIFIC)
+ public ModelAndView chooseSIMDUTFile(ModelAndView model, @PathVariable int materialID) {
+ return new ModelResponseBuilder(model)
+ .withView(EDIT_MATERIAL_SIMDUT)
+ .addResponseData(ResponseDataType.MATERIAL_ID, materialID)
+ .build();
+ }
+
+ /**
+ * Sauvegarde le fichier SIMDUT d'un produit.
+ *
+ * Modèle de la page:
+ * - error: Contient le message d'erreur, s'il y a lieu
+ *
+ * REQUIERT UNE AUTORISATION
+ *
+ * @param materialID L'identifiant du produit
+ * @param simdut Le fichier SIMDUT uploadé
+ * @return La page à afficher.
+ */
+ @PostMapping(value = EDIT_MATERIAL_SIMDUT, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public ModelAndView saveSIMDUT(int materialID, MultipartFile simdut) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(ControllerUtils.redirect("material/editor/" + materialID));
+
+ Optional optionalMaterial = materialService.getByID(materialID);
+ if (!optionalMaterial.isPresent()) {
+ return chooseSIMDUTFile(modelResponseBuilder
+ .addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID)
+ .build(),
+ materialID);
+ }
+
+ Material material = optionalMaterial.get();
+ if (!materialService.removeSimdut(material) || !materialService.addSimdut(simdut, material)) {
+ modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
+
+ return chooseSIMDUTFile(modelResponseBuilder.build(), materialID);
+ }
+
+ return modelResponseBuilder.build();
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialTypeEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialTypeEditorController.java
new file mode 100644
index 0000000..60e572d
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MaterialTypeEditorController.java
@@ -0,0 +1,96 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+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.servlet.ModelAndView;
+
+import java.util.Optional;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
+
+@Controller
+public class MaterialTypeEditorController {
+
+ private MaterialTypeService materialTypeService;
+
+ @Autowired
+ public MaterialTypeEditorController(MaterialTypeService materialTypeService) {
+ this.materialTypeService = materialTypeService;
+ }
+
+ @GetMapping(EDITOR_MATERIAL_TYPE)
+ public ModelAndView listMaterialTypes(ModelAndView model) {
+ return new ModelResponseBuilder(model)
+ .withView(EDITOR_MATERIAL_TYPE)
+ .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
+ .build();
+ }
+
+ @GetMapping(EDITOR_MATERIAL_TYPE_SPECIFIC)
+ public ModelAndView showEditPage(ModelAndView model, @PathVariable int materialTypeID, MaterialType materialType) {
+ ModelResponseBuilder responseBuilder = new ModelResponseBuilder(model)
+ .withView(EDITOR_MATERIAL_TYPE_EDITOR);
+
+ if (materialType.getMaterialTypeName() == null) {
+ Optional optionalMaterialType = materialTypeService.getByID(materialTypeID);
+
+ if (!optionalMaterialType.isPresent()) {
+ return listMaterialTypes(
+ responseBuilder
+ .addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID)
+ .build()
+ );
+ }
+
+ materialType = optionalMaterialType.get();
+ }
+
+ return responseBuilder
+ .addResponseData(ResponseDataType.MATERIAL_TYPE, materialType)
+ .build();
+ }
+
+ @PostMapping(value = EDITOR_MATERIAL_TYPE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ public ModelAndView saveEditedMaterialType(MaterialType materialType) {
+ ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
+ int materialTypeID = materialType.getMaterialTypeID();
+
+ if (!materialTypeService.getByID(materialTypeID).isPresent()) {
+ responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID);
+ } else if (!materialTypeService.isValidForUpdateName(materialType)) {
+ return showEditPage(
+ responseBuilder
+ .addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST, materialType.getMaterialTypeName())
+ .build(),
+ materialTypeID, materialType);
+ } else if (!materialTypeService.isValidForUpdatePrefix(materialType)) {
+ return showEditPage(
+ responseBuilder
+ .addResponseCode(ResponseCode.MATERIAL_TYPE_ALREADY_EXIST_PREFIX, materialType.getPrefix())
+ .build(),
+ materialTypeID, materialType);
+ } else {
+ Optional updatedMaterialType = materialTypeService.update(materialType);
+ if (updatedMaterialType.isPresent()) {
+ responseBuilder.addResponseData(ResponseDataType.MATERIAL_TYPE_NAME, updatedMaterialType.get().getMaterialTypeName());
+ } else {
+ return showEditPage(
+ responseBuilder
+ .addResponseCode(ResponseCode.ERROR_SAVING)
+ .build(),
+ materialTypeID, null);
+ }
+ }
+
+ return listMaterialTypes(responseBuilder.build());
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MixEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MixEditorController.java
new file mode 100644
index 0000000..387f16f
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/MixEditorController.java
@@ -0,0 +1,154 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.dto.MixCreationFormDto;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MixTypeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
+import dev.fyloz.trial.colorrecipesexplorer.core.utils.ControllerUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.validation.Valid;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
+import static dev.fyloz.trial.colorrecipesexplorer.web.StringBank.MIX_ID;
+
+@Controller
+public class MixEditorController {
+
+ private MixService mixService;
+ private MaterialService materialService;
+ private RecipeService recipeService;
+ private MixTypeService mixTypeService;
+
+ @Autowired
+ public MixEditorController(MixService mixService, MaterialService materialService, RecipeService recipeService, MixTypeService mixTypeService) {
+ this.mixService = mixService;
+ this.materialService = materialService;
+ this.recipeService = recipeService;
+ this.mixTypeService = mixTypeService;
+ }
+
+ /**
+ * Affiche la page d'édition d'un mélange.
+ * Cette méthode requiert l'identifiant du mélange à modifier dans l'URL.
+ *
+ * @param model Le Model injecté par Thymeleaf
+ * @param mixID L'identifiant du mélange à modifier
+ * @return La page à afficher.
+ */
+ @GetMapping(EDITOR_MIX_SPECIFIC)
+ public ModelAndView showPage(ModelAndView model, @PathVariable int mixID) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(model)
+ .withView(EDITOR_MIX_SPECIFIC.replaceAll("/\\{" + MIX_ID + "}", ""));
+
+ Optional optionalMix = mixService.getByID(mixID);
+ if (!optionalMix.isPresent()) {
+ return modelResponseBuilder
+ .withView(ControllerUtils.redirect(EDITOR_RECIPE))
+ .build();
+ }
+
+ Mix mix = optionalMix.get();
+ List associatedMixTypes = recipeService.getAssociatedMixesTypes(mix.getRecipe());
+ // Récupère seulement les produits qui ne sont pas des types de mélange OU que ce type existe dans la recette
+ List materials = materialService
+ .getAll()
+ .stream()
+ .filter(m -> !m.isMixType() || (!m.equals(mix.getMixType().getMaterial()) && associatedMixTypes.contains(mixTypeService.getByMaterial(m).get())))
+ .sorted(Comparator.comparing(Material::getMaterialCode))
+ .sorted(Comparator.comparing(m -> m.getMaterialType().getMaterialTypeName()))
+ .collect(Collectors.toList());
+
+ return modelResponseBuilder
+ .addResponseData(ResponseDataType.MIX, mix)
+ .addResponseData(ResponseDataType.RECIPE_CODE, mix.getRecipe().getRecipeCode())
+ .addAttribute("mixJson", materialService.asJson(mix))
+ .addAttribute("materialsJson", materialService.asJson(materials))
+ .build();
+ }
+
+ /**
+ * Permet à l'utilisateur de modifier un mélange.
+ *
+ * La mise à jour échouera si:
+ * - L'utilisateur n'est pas autorisé à exécuter cette action
+ * - Le mélange n'existe pas
+ * - Un des produits n'existe pas
+ * - Une erreur est survenue lors de la mise à jour dans la base de données
+ *
+ * Modèle de la page:
+ * - error: Contient le message d'erreur, s'il y a lieu
+ *
+ * REQUIERT UNE AUTORISATION
+ *
+ * @param form Le formulaire du mélange entré par l'utilisateur
+ * @return La page à afficher.
+ */
+ @PostMapping(value = EDITOR_MIX, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ public ModelAndView saveMix(@ModelAttribute @Valid MixCreationFormDto formDto, int mixID) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder();
+
+ Optional optionalMix = mixService.getByID(mixID);
+ if (!optionalMix.isPresent()) {
+ modelResponseBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID);
+
+ return showPage(modelResponseBuilder.build(), mixID);
+ }
+
+ Mix mix = optionalMix.get();
+ modelResponseBuilder.withRedirect(EDITOR_RECIPE_SPECIFIC, mix.getRecipe().getRecipeID());
+
+ ModelResponseBuilder editResult = mixService.edit(mix, formDto);
+ if (editResult != null) {
+ return showPage(
+ modelResponseBuilder
+ .addResponseCode(ResponseCode.ERROR_SAVING)
+ .build(),
+ mixID);
+ }
+
+ return modelResponseBuilder.build();
+ }
+
+ @GetMapping(REMOVER_MIX_SPECIFIC)
+ public ModelAndView deleteMix(@PathVariable int mixID) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
+
+ Optional optionalMix = mixService.getByID(mixID);
+ if (!optionalMix.isPresent()) {
+ return showPage(modelResponseBuilder
+ .addResponseCode(ResponseCode.MIX_NOT_FOUND, mixID)
+ .build(),
+ mixID);
+ }
+
+ Mix mix = optionalMix.get();
+ modelResponseBuilder.withView(ControllerUtils.redirect(EDITOR_RECIPE_SPECIFIC.replace("{recipeID}", String.valueOf(mix.getRecipe().getRecipeID()))));
+
+ if (!mixService.deleteMix(mix)) {
+ modelResponseBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
+
+ return showPage(modelResponseBuilder.build(), mixID);
+ }
+
+ return modelResponseBuilder.build();
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/RecipeEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/RecipeEditorController.java
new file mode 100644
index 0000000..d26afc9
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/editors/RecipeEditorController.java
@@ -0,0 +1,125 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.editors;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.MultiValueMap;
+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.servlet.ModelAndView;
+
+import java.util.ArrayList;
+import java.util.Optional;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.*;
+
+@Controller
+public class RecipeEditorController {
+
+ private RecipeService recipeService;
+ private CompanyService companyService;
+
+ @Autowired
+ public RecipeEditorController(RecipeService recipeService, CompanyService companyService) {
+ this.recipeService = recipeService;
+ this.companyService = companyService;
+ }
+
+ /**
+ * Affiche la page listant toutes les recettes.
+ *
+ * Modèle de la page:
+ * - recipes: Contient un Map de toutes les recettes triées par compagnie
+ *
+ * @param model Le Model injecté par Thymeleaf
+ * @return La page à afficher.
+ */
+ @GetMapping(EDITOR_RECIPE)
+ public ModelAndView listRecipes(ModelAndView model) {
+ return new ModelResponseBuilder(model)
+ .withView(EDITOR_RECIPE)
+ .addResponseData(ResponseDataType.RECIPE_MAP, recipeService.getRecipesByCompany())
+ .build();
+ }
+
+ @GetMapping(EDITOR_RECIPE_SPECIFIC)
+ public ModelAndView showEditPage(ModelAndView model, @PathVariable int recipeID, Recipe recipe) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder(model)
+ .withView(EDITOR_RECIPE_EDITOR);
+
+ if (recipe.getRecipeCode() == null || recipe.getCompany() == null) {
+ Optional optionalRecipe = recipeService.getByID(recipeID);
+
+ if (!optionalRecipe.isPresent()) {
+ return listRecipes(
+ modelResponseBuilder
+ .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
+ .build()
+ );
+ }
+
+ recipe = optionalRecipe.get();
+ }
+
+ return modelResponseBuilder
+ .addResponseData(ResponseDataType.RECIPE, recipe)
+ .addResponseData(ResponseDataType.COMPANIES, companyService.getAll())
+ .addResponseData(ResponseDataType.MIXES, new ArrayList<>(recipeService.getSortedMixes(recipe))) // Convertit le PersistentBag en ArrayList
+ .addResponseData(ResponseDataType.IMAGES, recipeService.getImageFiles(recipe))
+ .addAttribute("recipeJSON", recipeService.asJson(recipe))
+ .build();
+ }
+
+ /**
+ * Permet à l'utilisateur de modifier une recette.
+ *
+ * La mise à jour échouera si:
+ * - L'utilisateur n'est pas autorisé à exécuter cette action
+ * - La recette n'existe pas
+ * - Une erreur est survenue lors de la mise à jour dans la base de données
+ *
+ * Modèle de la page:
+ * - error: Contient le message d'erreur, s'il y a lieu
+ * - recipeCode: Contient la couleur d'une recette
+ *
+ * REQUIERT UNE AUTORISATION
+ *
+ * @param recipe La recette à modifier
+ * @param form Le formulaire entré par l'utilisateur
+ * @return La page à afficher.
+ */
+ @PostMapping(value = EDITOR_RECIPE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ @Transactional
+ public ModelAndView saveRecipe(Recipe recipe, @RequestBody MultiValueMap form) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
+ int recipeID = recipe.getRecipeID();
+
+ Optional optionalStoredRecipe = recipeService.getByID(recipeID);
+ if (!optionalStoredRecipe.isPresent()) {
+ return listRecipes(
+ modelResponseBuilder
+ .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
+ .build());
+ }
+
+ Optional optionalRecipe = recipeService.updateRecipe(recipe, optionalStoredRecipe.get(), form);
+ if (optionalRecipe.isPresent()) {
+ modelResponseBuilder.addResponseData(ResponseDataType.RECIPE_CODE, optionalRecipe.get().getRecipeCode());
+ return listRecipes(modelResponseBuilder.build());
+ }
+
+ return listRecipes(
+ modelResponseBuilder
+ .addResponseCode(ResponseCode.ERROR_SAVING)
+ .build());
+ }
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/CompanyRemoverController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/CompanyRemoverController.java
similarity index 56%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/CompanyRemoverController.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/CompanyRemoverController.java
index 30d9ae2..2d3212a 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/CompanyRemoverController.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/CompanyRemoverController.java
@@ -1,10 +1,10 @@
-package fyloz.trial.ColorRecipesExplorer.web.controller.removers;
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers;
-import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
-import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
-import fyloz.trial.ColorRecipesExplorer.core.ResponseCode;
-import fyloz.trial.ColorRecipesExplorer.model.Company;
-import fyloz.trial.ColorRecipesExplorer.services.CompanyService;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Company;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.CompanyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@@ -12,8 +12,10 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
-import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_COMPANY;
-import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_COMPANY_SPECIFIC;
+import java.util.Optional;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_COMPANY;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_COMPANY_SPECIFIC;
@Controller
public class CompanyRemoverController {
@@ -36,9 +38,9 @@ public class CompanyRemoverController {
*/
@GetMapping(REMOVER_COMPANY)
public ModelAndView showPage(ModelAndView model) {
- return new ModelBuilder(model)
- .setView(REMOVER_COMPANY)
- .addData(ModelDataType.COMPANIES, companyService.getAll())
+ return new ModelResponseBuilder(model)
+ .withView(REMOVER_COMPANY)
+ .addResponseData(ResponseDataType.COMPANIES, companyService.getAll())
.build();
}
@@ -63,19 +65,21 @@ public class CompanyRemoverController {
@PostMapping(REMOVER_COMPANY_SPECIFIC)
public ModelAndView removeCompany(@PathVariable int companyID) {
- ModelBuilder modelBuilder = new ModelBuilder("");
- Company company = companyService.getByID(companyID);
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
+
+ Optional optionalCompany = companyService.getByID(companyID);
+ if (optionalCompany.isPresent()) {
+ Company company = optionalCompany.get();
- if (companyService.exists(company)) {
if (companyService.deleteIfNotLinked(company)) {
- modelBuilder.addData(ModelDataType.COMPANY_NAME, company.getCompanyName());
+ modelResponseBuilder.addResponseData(ResponseDataType.COMPANY_NAME, company.getCompanyName());
} else {
- modelBuilder.addResponseCode(ResponseCode.COMPANY_LINKED, company.getCompanyName());
+ modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_LINKED, company.getCompanyName());
}
} else {
- modelBuilder.addResponseCode(ResponseCode.COMPANY_NOT_FOUND, String.valueOf(companyID));
+ modelResponseBuilder.addResponseCode(ResponseCode.COMPANY_NOT_FOUND, companyID);
}
- return showPage(modelBuilder.build());
+ return showPage(modelResponseBuilder.build());
}
}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/MaterialRemoverController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialRemoverController.java
similarity index 54%
rename from src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/MaterialRemoverController.java
rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialRemoverController.java
index 599a3c8..8e8f581 100644
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/web/controller/removers/MaterialRemoverController.java
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialRemoverController.java
@@ -1,10 +1,10 @@
-package fyloz.trial.ColorRecipesExplorer.web.controller.removers;
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers;
-import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
-import fyloz.trial.ColorRecipesExplorer.core.ModelDataType;
-import fyloz.trial.ColorRecipesExplorer.core.ResponseCode;
-import fyloz.trial.ColorRecipesExplorer.model.Material;
-import fyloz.trial.ColorRecipesExplorer.services.MaterialService;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Material;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@@ -12,10 +12,11 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
+import java.util.Optional;
import java.util.stream.Collectors;
-import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_MATERIAL;
-import static fyloz.trial.ColorRecipesExplorer.web.PagesPaths.REMOVER_MATERIAL_SPECIFIC;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_SPECIFIC;
@Controller
public class MaterialRemoverController {
@@ -35,9 +36,9 @@ public class MaterialRemoverController {
*/
@GetMapping(REMOVER_MATERIAL)
public ModelAndView showPage(ModelAndView model) {
- return new ModelBuilder(model)
- .setView(REMOVER_MATERIAL)
- .addData(ModelDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
+ return new ModelResponseBuilder(model)
+ .withView(REMOVER_MATERIAL)
+ .addResponseData(ResponseDataType.MATERIALS, materialService.getAll().stream().filter(m -> !m.isMixType()).collect(Collectors.toList()))
.build();
}
@@ -61,23 +62,25 @@ public class MaterialRemoverController {
*/
@PostMapping(REMOVER_MATERIAL_SPECIFIC)
public ModelAndView removeMaterial(@PathVariable int materialID) {
- ModelBuilder modelBuilder = new ModelBuilder("");
- Material material = materialService.getByID(materialID);
+ ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
- if (material == null) {
- modelBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, String.valueOf(materialID));
+ Optional optionalMaterial = materialService.getByID(materialID);
+ if (!optionalMaterial.isPresent()) {
+ responseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, materialID);
} else {
+ Material material = optionalMaterial.get();
+
if (materialService.deleteIfNotLinked(material)) {
- modelBuilder.addData(ModelDataType.MATERIAL_CODE, material.getMaterialCode());
+ responseBuilder.addResponseData(ResponseDataType.MATERIAL_CODE, material.getMaterialCode());
if (!materialService.removeSimdut(material)) {
- modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
+ responseBuilder.addResponseCode(ResponseCode.ERROR_SAVING_SIMDUT);
}
} else {
- modelBuilder.addResponseCode(ResponseCode.MATERIAL_LINKED, material.getMaterialCode());
+ responseBuilder.addResponseCode(ResponseCode.MATERIAL_LINKED, material.getMaterialCode());
}
}
- return showPage(modelBuilder.build());
+ return showPage(responseBuilder.build());
}
}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialTypeRemoverController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialTypeRemoverController.java
new file mode 100644
index 0000000..facf9eb
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/MaterialTypeRemoverController.java
@@ -0,0 +1,58 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MaterialType;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.MaterialTypeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+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.servlet.ModelAndView;
+
+import java.util.Optional;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_TYPE;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_MATERIAL_TYPE_SPECIFIC;
+
+@Controller
+public class MaterialTypeRemoverController {
+
+ private MaterialTypeService materialTypeService;
+
+ @Autowired
+
+ public MaterialTypeRemoverController(MaterialTypeService materialTypeService) {
+ this.materialTypeService = materialTypeService;
+ }
+
+ @GetMapping(REMOVER_MATERIAL_TYPE)
+ public ModelAndView showPage(ModelAndView model) {
+ return new ModelResponseBuilder(model)
+ .withView(REMOVER_MATERIAL_TYPE)
+ .addResponseData(ResponseDataType.MATERIAL_TYPES, materialTypeService.getAll())
+ .build();
+ }
+
+ @PostMapping(REMOVER_MATERIAL_TYPE_SPECIFIC)
+ public ModelAndView removeMaterialType(@PathVariable int materialTypeID) {
+ ModelResponseBuilder responseBuilder = new ModelResponseBuilder("");
+
+ Optional optionalMaterialType = materialTypeService.getByID(materialTypeID);
+ if (!optionalMaterialType.isPresent()) {
+ responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_NOT_FOUND, materialTypeID);
+ } else {
+ MaterialType materialType = optionalMaterialType.get();
+
+ if (materialTypeService.deleteIfNotLinked(materialType)) {
+ responseBuilder.addResponseData(ResponseDataType.MATERIAL_TYPE_NAME, materialType.getMaterialTypeName());
+ } else {
+ responseBuilder.addResponseCode(ResponseCode.MATERIAL_TYPE_LINKED, materialType.getMaterialTypeName());
+ }
+ }
+
+ return showPage(responseBuilder.build());
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/RecipeRemoverController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/RecipeRemoverController.java
new file mode 100644
index 0000000..2bbc64c
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/removers/RecipeRemoverController.java
@@ -0,0 +1,83 @@
+package dev.fyloz.trial.colorrecipesexplorer.web.controller.removers;
+
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ModelResponseBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseCode;
+import dev.fyloz.trial.colorrecipesexplorer.core.io.response.ResponseDataType;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.services.model.RecipeService;
+import org.springframework.stereotype.Controller;
+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.servlet.ModelAndView;
+
+import java.util.Optional;
+
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_RECIPE;
+import static dev.fyloz.trial.colorrecipesexplorer.web.PagesPaths.REMOVER_RECIPE_SPECIFIC;
+
+@Controller
+public class RecipeRemoverController {
+
+ private RecipeService recipeService;
+
+ public RecipeRemoverController(RecipeService recipeService) {
+ this.recipeService = recipeService;
+ }
+
+ /**
+ * Affiche la liste de toutes les recettes.
+ *
+ * @param model Le Model injecté par Thymeleaf
+ * @return La page à afficher.
+ */
+ @GetMapping(REMOVER_RECIPE)
+ public ModelAndView listRecipes(ModelAndView model) {
+ return new ModelResponseBuilder(model)
+ .withView(REMOVER_RECIPE)
+ .addResponseData(ResponseDataType.RECIPE_MAP, recipeService.getRecipesByCompany())
+ .build();
+ }
+
+ /**
+ * Permet à l'utilisateur de supprimer une recette.
+ * Cette méthode requiert l'identifiant de la recette dans l'URL.
+ *
+ * La suppression échouera si:
+ * - L'utilisateur n'est pas autorisé à exécuter cette action
+ * - La recette n'existe pas
+ * - Une erreur est survenue lors de la suppression dans la base de données
+ *
+ * Modèle de la page:
+ * - error: Contient le message d'erreur, s'il y a lieu
+ * - recipeCode: Contient la couleur de la recette
+ *
+ * REQUIERT UNE AUTORISATION
+ *
+ * @param recipeID L'identifiant de la recette
+ * @return La page à afficher.
+ */
+ @PostMapping(REMOVER_RECIPE_SPECIFIC)
+ public ModelAndView removeRecipe(@PathVariable int recipeID) {
+ ModelResponseBuilder modelResponseBuilder = new ModelResponseBuilder("");
+
+ Optional optionalRecipe = recipeService.getByID(recipeID);
+ if (!optionalRecipe.isPresent()) {
+ return listRecipes(
+ modelResponseBuilder
+ .addResponseCode(ResponseCode.RECIPE_NOT_FOUND, recipeID)
+ .build());
+ }
+
+ Recipe recipe = optionalRecipe.get();
+ if (!recipeService.deleteRecipe(recipe)) {
+ return listRecipes(
+ modelResponseBuilder
+ .addResponseCode(ResponseCode.ERROR_SAVING)
+ .build());
+ }
+
+ modelResponseBuilder.addResponseData(ResponseDataType.RECIPE_CODE, recipe.getRecipeCode());
+ return listRecipes(modelResponseBuilder.build());
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/XlsxExporter.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/XlsxExporter.java
new file mode 100644
index 0000000..3743cd0
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/XlsxExporter.java
@@ -0,0 +1,101 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx;
+
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Mix;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.MixQuantity;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.Recipe;
+import dev.fyloz.trial.colorrecipesexplorer.core.model.RecipeStep;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Catalog;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Sheet;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Table;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.DescriptionCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.NoteCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.SectionTitleCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.TitleCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.util.Position;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Collection;
+
+public class XlsxExporter {
+
+ public byte[] generate(Recipe recipe) {
+ ColorRecipesExplorerApplication.LOGGER.info(String.format("Génération du XLS de la couleur %s (%s)", recipe.getRecipeCode(), recipe.getRecipeID()));
+
+ Document document = new Document(recipe.getRecipeCode());
+ Sheet sheet = document.getSheet();
+ registerCells(recipe, sheet);
+
+ document.buildSheet();
+
+ byte[] output;
+ try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+ document.write(outputStream);
+ output = outputStream.toByteArray();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return new byte[0];
+ }
+
+ return output;
+ }
+
+ private void registerCells(Recipe recipe, Sheet sheet) {
+ // Header
+ sheet.registerCell(new TitleCell(recipe.getRecipeCode()));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Bannière"));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getCompany().getCompanyName()));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Description"));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getRecipeDescription()));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Échantillon"));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_NUM, recipe.getSample()));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Date d'approbation"));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getApprobationDate()));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.NAME, "Remarque"));
+ sheet.registerCell(new DescriptionCell(DescriptionCell.DescriptionCellType.VALUE_STR, recipe.getRemark()));
+
+ // Mélanges
+ Collection recipeMixes = recipe.getRecipeMixes();
+ if (recipeMixes.size() > 0) {
+ sheet.registerCell(new SectionTitleCell("Recette"));
+
+ for (Mix mix : recipeMixes) {
+ Table mixTable = new Table(4, mix.getMixQuantities().size() + 1, mix.getMixType().getTypeName());
+ mixTable.setColumnName(0, "Quantité");
+ mixTable.setColumnName(2, "Unités");
+
+ int row = 0;
+ for (MixQuantity mixQuantity : mix.getMixQuantities()) {
+ mixTable.setRowName(row, mixQuantity.getMaterial().getMaterialCode());
+ mixTable.setContent(new Position(1, row + 1), mixQuantity.getQuantity());
+ mixTable.setContent(new Position(3, row + 1), mixQuantity.getMaterial().getMaterialType().getUsePercentages() ? "%" : "mL");
+
+ row++;
+ }
+
+ sheet.registerAllCells(mixTable.getCells());
+ }
+ }
+
+ // Étapes
+ Collection steps = recipe.getRecipeSteps();
+ if (steps.size() > 0) {
+ sheet.registerCell(new SectionTitleCell("Étapes"));
+ Catalog stepsCatalog = new Catalog();
+
+ for (RecipeStep step : recipe.getRecipeSteps()) stepsCatalog.addContent(step.getStepMessage());
+
+ sheet.registerAllCells(stepsCatalog.getCells());
+ }
+
+ // Note
+ String note = recipe.getNote();
+ if (note != null) {
+ sheet.registerCell(new SectionTitleCell("Note"));
+ sheet.registerCell(new NoteCell(recipe.getNote()));
+ }
+ }
+
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/CellBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/CellBuilder.java
new file mode 100644
index 0000000..43d2f21
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/CellBuilder.java
@@ -0,0 +1,69 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.builder;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+
+public class CellBuilder {
+
+ private Document document;
+ private Cell cell;
+ private XSSFCell xcell;
+
+ public CellBuilder(Document document, Cell cell, int x, int y) {
+ this.document = document;
+ this.cell = cell;
+
+ xcell = document.getSheet().getCell(cell, x, y, true);
+ }
+
+ private void applyColor(IColoredCell cell, XSSFCellStyle style) {
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+ style.setFillForegroundColor(cell.getBackgroundColor().getIndex());
+ }
+
+ private void applyFont(IFontCell cell, XSSFCellStyle style) {
+ XSSFFont font = document.createFont();
+ font.setBold(cell.isBold());
+ font.setColor(cell.getFontColor().getIndex());
+ font.setFontHeightInPoints(cell.getFontHeight());
+
+ style.setFont(font);
+ if (cell.isCentered()) style.setAlignment(HorizontalAlignment.CENTER);
+ }
+
+ private void applyStyle() {
+ XSSFCellStyle style = document.createCellStyle();
+ style.setWrapText(true);
+
+ if (cell instanceof IColoredCell) applyColor((IColoredCell) cell, style);
+ if (cell instanceof IFontCell) applyFont((IFontCell) cell, style);
+
+ xcell.setCellStyle(style);
+ }
+
+ private void applyContent() throws InvalidCellTypeException {
+ switch (cell.getType()) {
+ case STRING:
+ xcell.setCellValue(cell.getContentText());
+ break;
+ case NUMERIC:
+ xcell.setCellValue(cell.getContentNum());
+ break;
+ default:
+ throw new InvalidCellTypeException(cell.getType());
+ }
+ }
+
+ public void build() throws InvalidCellTypeException {
+ applyStyle();
+ applyContent();
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/SheetBuilder.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/SheetBuilder.java
new file mode 100644
index 0000000..3269f39
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/builder/SheetBuilder.java
@@ -0,0 +1,60 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.builder;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Sheet;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.util.CellUtils;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+public class SheetBuilder {
+
+ private Sheet sheet;
+ private Iterable cells;
+
+ public SheetBuilder(Sheet sheet) {
+ this.sheet = sheet;
+
+ cells = sheet.getRegisteredCells();
+ }
+
+ private void applyCellMerge(IBiggerCell cell, int x, int y) {
+ int width = cell.getWidth() - 1;
+ int height = cell.getHeight() - 1;
+
+ sheet.getXSheet().addMergedRegion(new CellRangeAddress(y, y + height, x, x + width));
+ }
+
+ public void build() throws InvalidCellTypeException {
+ int x = 0;
+ int y = 0;
+
+ for (Cell cell : cells) {
+ while (!CellUtils.isCellEmpty(sheet, x, y) || CellUtils.isCellInMergedCell(sheet, x, y)) {
+ x++;
+
+ if (x >= Document.WIDTH) {
+ x = 0;
+ y++;
+ }
+ }
+
+ new CellBuilder(sheet.getDocument(), cell, x, y).build();
+ if (cell instanceof IBiggerCell) {
+ IBiggerCell biggerCell = (IBiggerCell) cell;
+
+ applyCellMerge(biggerCell, x, y);
+
+ x += biggerCell.getWidth() - 1;
+ } else {
+ x++;
+ }
+
+ if (x >= Document.WIDTH) {
+ x = 0;
+ y++;
+ }
+ }
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Catalog.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Catalog.java
new file mode 100644
index 0000000..6a135bf
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Catalog.java
@@ -0,0 +1,73 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
+import org.apache.poi.ss.usermodel.CellType;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class Catalog {
+
+ private List content;
+
+ public Catalog() {
+ content = new ArrayList<>();
+ }
+
+ public void addContent(String value) {
+ content.add(value);
+ }
+
+ public Collection getCells() {
+ Collection cells = new ArrayList<>();
+
+ int index = 1;
+ for (String value : content) {
+ cells.add(new CatalogValueCell(String.format("%s. %s", index, value)));
+
+ index++;
+ }
+
+ return cells;
+ }
+
+ private class CatalogValueCell extends Cell implements IBiggerCell, IFontCell {
+
+ private String value;
+
+ public CatalogValueCell(String value) {
+ super(CellType.STRING);
+
+ this.value = value;
+ }
+
+ @Override
+ public int getWidth() {
+ return Document.WIDTH;
+ }
+
+ @Override
+ public int getHeight() {
+ return 1;
+ }
+
+ @Override
+ public String getContentText() {
+ return value;
+ }
+
+ @Override
+ public boolean isCentered() {
+ return false;
+ }
+
+ @Override
+ public boolean isBold() {
+ return false;
+ }
+ }
+
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Document.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Document.java
new file mode 100644
index 0000000..93a9f65
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Document.java
@@ -0,0 +1,33 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component;
+
+import dev.fyloz.trial.colorrecipesexplorer.ColorRecipesExplorerApplication;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.builder.SheetBuilder;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbookType;
+
+public class Document extends XSSFWorkbook {
+
+ public static final int WIDTH = 8;
+ private static final XSSFWorkbookType WORKBOOK_TYPE = XSSFWorkbookType.XLSX;
+
+ private Sheet sheet;
+
+ public Document(String name) {
+ super(WORKBOOK_TYPE);
+
+ sheet = new Sheet(this, createSheet(name));
+ }
+
+ public void buildSheet() {
+ try {
+ new SheetBuilder(sheet).build();
+ } catch (InvalidCellTypeException e) {
+ ColorRecipesExplorerApplication.LOGGER.error("Une erreur est survenue lors de la génération du document: " + e.getLocalizedMessage());
+ }
+ }
+
+ public Sheet getSheet() {
+ return sheet;
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Sheet.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Sheet.java
new file mode 100644
index 0000000..c006464
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Sheet.java
@@ -0,0 +1,84 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+
+import java.util.*;
+
+public class Sheet {
+
+ private Document document;
+ private XSSFSheet xsheet;
+
+ private Map rows;
+ private List registeredCells;
+
+ Sheet(Document document, XSSFSheet xsheet) {
+ this.document = document;
+ this.xsheet = xsheet;
+ xsheet.setDefaultColumnWidth(xsheet.getDefaultColumnWidth() * 2);
+
+ rows = new HashMap<>();
+ registeredCells = new ArrayList<>();
+ }
+
+ public void registerCell(Cell cell) {
+ registeredCells.add(cell);
+ }
+
+ public void registerAllCells(Collection cells) {
+ registeredCells.addAll(cells);
+ }
+
+ public List getRegisteredCells() {
+ return registeredCells;
+ }
+
+ public XSSFRow getRow(int rownum, boolean create) {
+ int rowSize = rows.keySet().size();
+
+ if (rowSize <= rownum) {
+ if (!create) return null;
+
+ for (int i = rowSize; i <= rownum; i++) {
+ rows.put(i, xsheet.createRow(i));
+ }
+ }
+
+ return rows.get(rownum);
+ }
+
+ public XSSFCell getCell(int rownum, int columnnum, CellType type, boolean create) {
+ XSSFRow row = getRow(rownum, create);
+// List columns = rows.get(row);
+ int columnsSize = row.getLastCellNum();
+
+ if (columnsSize == -1) columnsSize = 0;
+
+ if (columnsSize <= columnnum) {
+ if (!create) return null;
+
+ for (int i = columnsSize; i <= columnnum; i++) {
+ row.createCell(i, type);
+ }
+ }
+
+ return row.getCell(columnnum);
+ }
+
+ public XSSFCell getCell(Cell cell, int x, int y, boolean create) {
+ return getCell(y, x, cell.getType(), create);
+ }
+
+ public XSSFSheet getXSheet() {
+ return xsheet;
+ }
+
+ public Document getDocument() {
+ return document;
+ }
+
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Table.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Table.java
new file mode 100644
index 0000000..01d84da
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/Table.java
@@ -0,0 +1,276 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.Cell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.exception.IndexOutOfTableBoundsException;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.util.Position;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import java.text.DecimalFormat;
+import java.util.*;
+
+public class Table {
+
+ private static DecimalFormat format = new DecimalFormat("#.###");
+
+ private int width;
+ private int height;
+ private int cellWidth;
+
+ private Map content;
+
+ private List columns;
+ private List rows;
+
+ public Table(int width, int height, String name) {
+ this.width = width;
+ this.height = height;
+
+ cellWidth = Document.WIDTH / width;
+
+ content = new HashMap<>();
+ columns = new ArrayList<>();
+ rows = new ArrayList<>();
+
+ for (int row = 0; row < this.height; row++) {
+ for (int col = 0; col < this.width; col++) {
+ Position pos = new Position(col, row);
+ Cell cell;
+
+ if (col == 0 && row == 0) { // Titre
+ cell = new TableNameCell(name, cellWidth);
+ } else if (col == 0 || row == 0) { // Colonnes/Rangée
+ cell = new TableSubNameCell("", cellWidth);
+
+ if (col > 0) columns.add((TableSubNameCell) cell);
+ else rows.add((TableSubNameCell) cell);
+ } else {
+ cell = new TableStringValueCell("", cellWidth);
+ }
+
+ content.put(pos, cell);
+ }
+ }
+ }
+
+ public void setColumnName(int index, String name) {
+ int columnnum = columns.size() - 1;
+ if (columnnum < index) throw new IndexOutOfTableBoundsException(index, columnnum);
+
+ columns.get(index).setName(name);
+ }
+
+ /**
+ * @param index Index de la rangée (à partir de 0)
+ * @param name Nouveau nom de la rangée
+ * @throws IndexOutOfTableBoundsException La rangée à l'index défini est en dehors de la portée du tableau.
+ * @author
+ */
+ public void setRowName(int index, String name) {
+ int rownum = rows.size() - 1;
+ if (rownum < index) throw new IndexOutOfTableBoundsException(index, rownum);
+
+ rows.get(index).setName(name);
+ }
+
+ public void setContent(Position position, String value) {
+ if (isInTableRange(position, this)) {
+ content.put(position, new TableStringValueCell(value, cellWidth));
+ }
+ }
+
+ public void setContent(Position position, double value) {
+ if (isInTableRange(position, this)) {
+ value = Double.parseDouble(format.format(value).replace(',', '.'));
+ content.put(position, new TableNumValueCell(value, cellWidth));
+ }
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public Collection getCells() {
+ int col = 0;
+ int row = 0;
+
+ Collection cells = new ArrayList<>();
+ while (row < height) {
+
+ while (col < width) {
+ Position pos = new Position(col, row);
+
+ cells.add(content.get(pos));
+
+ col++;
+ }
+
+ col = 0;
+ row++;
+ }
+
+ return cells;
+ }
+
+ public static boolean isInTableRange(Position position, Table table) {
+ int col = position.getColumn();
+ int columnnum = table.getWidth() - 1;
+ if (col > columnnum) throw new IndexOutOfTableBoundsException(col, columnnum);
+
+ int row = position.getRow();
+ int rownum = table.getHeight() - 1;
+ if (row > rownum) throw new IndexOutOfTableBoundsException(row, rownum);
+
+ return true;
+ }
+
+ private class TableNameCell extends Cell implements IColoredCell, IFontCell, IBiggerCell {
+
+ private final IndexedColors COLOR = IndexedColors.GREY_40_PERCENT;
+
+ private String name;
+ private int width;
+ private int height = 2;
+
+ public TableNameCell(String name, int width) {
+ super(CellType.STRING);
+
+ this.name = name;
+ this.width = width;
+ }
+
+ @Override
+ public String getContentText() {
+ return name;
+ }
+
+ @Override
+ public IndexedColors getBackgroundColor() {
+ return COLOR;
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public int getHeight() {
+ return height;
+ }
+ }
+
+ private class TableSubNameCell extends Cell implements IFontCell, IBiggerCell, IColoredCell {
+
+ private String name;
+ private int width;
+ private int height = 2;
+
+ public TableSubNameCell(String name, int width) {
+ super(CellType.STRING);
+
+ this.name = name;
+ this.width = width;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getContentText() {
+ return name;
+ }
+
+ @Override
+ public IndexedColors getBackgroundColor() {
+ return IndexedColors.GREY_25_PERCENT;
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public int getHeight() {
+ return height;
+ }
+ }
+
+ private class TableStringValueCell extends Cell implements IFontCell, IBiggerCell {
+
+ private String value;
+ private int width;
+ private int height = 2;
+
+ public TableStringValueCell(String value, int width) {
+ super(CellType.STRING);
+
+ this.value = value;
+ this.width = width;
+ }
+
+ @Override
+ public String getContentText() {
+ return value;
+ }
+
+ @Override
+ public boolean isBold() {
+ return false;
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public int getHeight() {
+ return height;
+ }
+ }
+
+ private class TableNumValueCell extends Cell implements IFontCell, IBiggerCell {
+
+ private double value;
+ private int width;
+ private int height = 2;
+
+ public TableNumValueCell(double value, int width) {
+ super(CellType.NUMERIC);
+
+ this.value = value;
+ this.width = width;
+ }
+
+ @Override
+ public double getContentNum() {
+ return value;
+ }
+
+ @Override
+ public boolean isBold() {
+ return false;
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public int getHeight() {
+ return height;
+ }
+ }
+
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/Cell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/Cell.java
new file mode 100644
index 0000000..1b2ee7d
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/Cell.java
@@ -0,0 +1,24 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
+
+import org.apache.poi.ss.usermodel.CellType;
+
+public class Cell {
+
+ protected CellType type;
+
+ public Cell(CellType type) {
+ this.type = type;
+ }
+
+ public CellType getType() {
+ return type;
+ }
+
+ public String getContentText() {
+ return "";
+ }
+
+ public double getContentNum() {
+ return 0.0d;
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java
new file mode 100644
index 0000000..0a1192b
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java
@@ -0,0 +1,68 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+public class DescriptionCell extends Cell implements IColoredCell, IBiggerCell, IFontCell {
+
+ private static final int WIDTH_NAME = 2;
+ private static final int WIDTH_VALUE = 6;
+ private static final int HEIGHT = 2;
+ private static final IndexedColors BG_COLOR_NAME = IndexedColors.GREY_40_PERCENT;
+ private static final short FONT_HEIGHT = 18;
+
+ private DescriptionCellType type;
+ private String valueStr;
+ private double valueNbr;
+
+ public DescriptionCell(DescriptionCellType type, String value) {
+ super(CellType.STRING);
+
+ this.type = type;
+ this.valueStr = value;
+ }
+
+ public DescriptionCell(DescriptionCellType type, double value) {
+ super(CellType.NUMERIC);
+
+ this.type = type;
+ this.valueNbr = value;
+ }
+
+ @Override
+ public int getWidth() {
+ return type == DescriptionCellType.NAME ? WIDTH_NAME : WIDTH_VALUE;
+ }
+
+ @Override
+ public int getHeight() {
+ return HEIGHT;
+ }
+
+ @Override
+ public IndexedColors getBackgroundColor() {
+ return type == DescriptionCellType.NAME ? BG_COLOR_NAME : IndexedColors.WHITE1;
+ }
+
+ @Override
+ public short getFontHeight() {
+ return FONT_HEIGHT;
+ }
+
+ @Override
+ public String getContentText() {
+ return type != DescriptionCellType.VALUE_NUM ? valueStr : "";
+ }
+
+ @Override
+ public double getContentNum() {
+ return type == DescriptionCellType.VALUE_NUM ? valueNbr : 0.0d;
+ }
+
+ public enum DescriptionCellType {
+ NAME, VALUE_STR, VALUE_NUM
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/NoteCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/NoteCell.java
new file mode 100644
index 0000000..c62bb09
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/NoteCell.java
@@ -0,0 +1,37 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
+import org.apache.poi.ss.usermodel.CellType;
+
+public class NoteCell extends Cell implements IBiggerCell, IFontCell {
+
+ private String value;
+
+ public NoteCell(String value) {
+ super(CellType.STRING);
+
+ this.value = value;
+ }
+
+ @Override
+ public int getWidth() {
+ return Document.WIDTH;
+ }
+
+ @Override
+ public int getHeight() {
+ return Math.max(Math.abs(value.length() / 100), 1);
+ }
+
+ @Override
+ public boolean isBold() {
+ return false;
+ }
+
+ @Override
+ public String getContentText() {
+ return value.replaceAll("(.{100})", "$1\n");
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java
new file mode 100644
index 0000000..34e99ad
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java
@@ -0,0 +1,56 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+
+public class SectionTitleCell extends Cell implements IColoredCell, IBiggerCell, IFontCell {
+
+ private static final int WIDTH = Document.WIDTH;
+ private static final int HEIGHT = 2;
+ private static final IndexedColors BG_COLOR = IndexedColors.BLACK;
+ private static final IndexedColors FONT_COLOR = IndexedColors.WHITE;
+ private static final int FONT_HEIGHT = 24;
+
+ private String title;
+
+ public SectionTitleCell(String title) {
+ super(CellType.STRING);
+
+ this.title = title.toUpperCase();
+ }
+
+ @Override
+ public int getWidth() {
+ return WIDTH;
+ }
+
+ @Override
+ public int getHeight() {
+ return HEIGHT;
+ }
+
+ @Override
+ public IndexedColors getBackgroundColor() {
+ return BG_COLOR;
+ }
+
+ @Override
+ public IndexedColors getFontColor() {
+ return FONT_COLOR;
+ }
+
+ @Override
+ public short getFontHeight() {
+ return FONT_HEIGHT;
+ }
+
+ @Override
+ public String getContentText() {
+ return title;
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/TitleCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/TitleCell.java
new file mode 100644
index 0000000..f215989
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/TitleCell.java
@@ -0,0 +1,60 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Document;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell;
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+public class TitleCell extends Cell implements IColoredCell, IBiggerCell, IFontCell {
+
+ private static final int WIDTH = Document.WIDTH;
+ private static final int HEIGHT = 3;
+ private static final CellType TYPE = CellType.STRING;
+ private static final IndexedColors FONT_COLOR = IndexedColors.WHITE;
+ private static IndexedColors BACKGROUND_COLOR = IndexedColors.BLACK;
+
+ private String title;
+
+ public TitleCell(String title) {
+ super(TYPE);
+
+ this.title = title;
+ }
+
+ @Override
+ public IndexedColors getBackgroundColor() {
+ return BACKGROUND_COLOR;
+ }
+
+ @Override
+ public IndexedColors getFontColor() {
+ return FONT_COLOR;
+ }
+
+ public Cell setColor(IndexedColors color) {
+ BACKGROUND_COLOR = color;
+ return this;
+ }
+
+ @Override
+ public short getFontHeight() {
+ return 36;
+ }
+
+ @Override
+ public int getWidth() {
+ return WIDTH;
+ }
+
+ @Override
+ public int getHeight() {
+ return HEIGHT;
+ }
+
+ @Override
+ public String getContentText() {
+ return title;
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IBiggerCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IBiggerCell.java
new file mode 100644
index 0000000..4548a5e
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IBiggerCell.java
@@ -0,0 +1,7 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles;
+
+public interface IBiggerCell {
+ int getWidth();
+
+ int getHeight();
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IColoredCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IColoredCell.java
new file mode 100644
index 0000000..5bb741a
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IColoredCell.java
@@ -0,0 +1,7 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles;
+
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+public interface IColoredCell {
+ IndexedColors getBackgroundColor();
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IFontCell.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IFontCell.java
new file mode 100644
index 0000000..68bb7ec
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/component/cells/styles/IFontCell.java
@@ -0,0 +1,23 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.component.cells.styles;
+
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+public interface IFontCell {
+
+ default IndexedColors getFontColor() {
+ return IndexedColors.BLACK;
+ }
+
+ default short getFontHeight() {
+ return 14;
+ }
+
+ default boolean isBold() {
+ return true;
+ }
+
+ default boolean isCentered() {
+ return true;
+ }
+
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/IndexOutOfTableBoundsException.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/IndexOutOfTableBoundsException.java
new file mode 100644
index 0000000..ddd984a
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/IndexOutOfTableBoundsException.java
@@ -0,0 +1,9 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.exception;
+
+public class IndexOutOfTableBoundsException extends RuntimeException {
+
+ public IndexOutOfTableBoundsException(int current, int max) {
+ super(String.format("L'index '%s' se trouve hors de portée du tableau (maximum: %s)", current, max));
+ }
+
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/InvalidCellTypeException.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/InvalidCellTypeException.java
new file mode 100644
index 0000000..57ed8d0
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/exception/InvalidCellTypeException.java
@@ -0,0 +1,11 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.exception;
+
+import org.apache.poi.ss.usermodel.CellType;
+
+public class InvalidCellTypeException extends Exception {
+
+ public InvalidCellTypeException(CellType type) {
+ super(String.format("Les recettes ne peuvent contenir que des cellules de type STRING et NUMERIC. Actuel: %s", type.name()));
+ }
+
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/CellUtils.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/CellUtils.java
new file mode 100644
index 0000000..ead3106
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/CellUtils.java
@@ -0,0 +1,52 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.util;
+
+import dev.fyloz.trial.colorrecipesexplorer.xlsx.component.Sheet;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.*;
+
+public class CellUtils {
+ public static XSSFColor getXSSFColor(int[] rgb) {
+ return new XSSFColor(new byte[]{(byte) rgb[0], (byte) rgb[1], (byte) rgb[2]}, new DefaultIndexedColorMap());
+ }
+
+ public static boolean isCellEmpty(Sheet sheet, int x, int y) {
+ XSSFRow row = sheet.getRow(y, false);
+
+ if (row == null) {
+ return true;
+ }
+
+ XSSFCell cell = row.getCell(x);
+
+ if (cell == null) { // use row.getCell(x, Row.CREATE_NULL_AS_BLANK) to avoid null cells
+ return true;
+ }
+
+ if (cell.getCellType() == CellType.BLANK) {
+ return true;
+ }
+
+ if (cell.getCellType() == CellType.STRING && cell.getStringCellValue().trim().isEmpty()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public static boolean isCellInMergedCell(Sheet sheet, int x, int y) {
+ XSSFSheet xsheet = sheet.getXSheet();
+
+ int numberOfMergedRegions = xsheet.getNumMergedRegions();
+
+ for (int i = 0; i < numberOfMergedRegions; i++) {
+ CellRangeAddress mergedCell = xsheet.getMergedRegion(i);
+
+ if (mergedCell.isInRange(y, x)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/Position.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/Position.java
new file mode 100644
index 0000000..5c4ba0c
--- /dev/null
+++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/xlsx/util/Position.java
@@ -0,0 +1,49 @@
+package dev.fyloz.trial.colorrecipesexplorer.xlsx.util;
+
+import java.util.Objects;
+
+public class Position {
+
+ private int column;
+ private int row;
+
+ public Position(int column, int row) {
+ this.column = column;
+ this.row = row;
+ }
+
+ public int getColumn() {
+ return column;
+ }
+
+ public void setColumn(int column) {
+ this.column = column;
+ }
+
+ public int getRow() {
+ return row;
+ }
+
+ public void setRow(int row) {
+ this.row = row;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Position position = (Position) o;
+ return column == position.column &&
+ row == position.row;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(column, row);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s, %s", column, row);
+ }
+}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelBuilder.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelBuilder.java
deleted file mode 100644
index deb400a..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/ModelBuilder.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.core;
-
-import org.springframework.web.servlet.ModelAndView;
-
-import javax.validation.constraints.NotNull;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class ModelBuilder {
-
- private static String RESPONSE_PREFIX = "response.";
- private static String ERROR_ATTRIBUTE_NAME = "error";
- private static String SUCCESS_ATTRIBUTE_NAME = "success";
-
- private ModelAndView model;
- private Map modelAttributes;
-
- public ModelBuilder(String view) {
- this(new ModelAndView(view));
- }
-
- public ModelBuilder(ModelAndView model) {
- this.model = model == null ? new ModelAndView() : model;
-
- modelAttributes = new HashMap<>();
- }
-
- public ModelBuilder setView(String view) {
- model.setViewName(view);
-
- return this;
- }
-
- public ModelBuilder addAttribute(String attributeName, Object content) {
- modelAttributes.put(attributeName, content);
-
- return this;
- }
-
- public ModelBuilder addResponseCode(ResponseCode responseCode, String... parameters) {
- int requiredParametersNumber = responseCode.getParametersNumber();
- int givenParametersNumber = parameters.length;
- StringBuilder builder = new StringBuilder();
-
- if (requiredParametersNumber != givenParametersNumber) {
- throw new IllegalArgumentException(String.format("Mauvais nombre de paramètre dans un réponse de modèle: %s requis, %s fournis", requiredParametersNumber, givenParametersNumber));
- }
-
- // Construit le code de réponse
- builder.append(RESPONSE_PREFIX);
- builder.append(responseCode.getCode());
-
- // Ajoute les paramètres, si nécessaire
- if (requiredParametersNumber > 0) {
- builder.append("('");
-
- for (int i = 0; i < givenParametersNumber; i++) {
- builder.append(parameters[i]);
-
- if (i < givenParametersNumber - 1) {
- builder.append("','");
- }
- }
-
- builder.append("')");
- }
-
- // Ajoute l'attribut dans le Map
- addAttribute(responseCode.getType() == ResponseCode.ResponseCodeType.ERROR ? ERROR_ATTRIBUTE_NAME : SUCCESS_ATTRIBUTE_NAME, builder.toString());
- addAttribute("arg1", "Bathia");
- addAttribute("arg2", "test");
-
- return this;
- }
-
- public ModelBuilder addData(ModelDataType modelDataType, @NotNull Object data) {
- Class modelDataTypeClass = modelDataType.getDataType();
- Class modelListDataTypeClass = modelDataType.getListDataType();
- Class givenDataTypeClass = data.getClass();
-
- // Vérifie le type de l'objet
- if (!modelDataTypeClass.equals(givenDataTypeClass)) {
- throw new IllegalArgumentException(String.format("L'objet passé en paramètre n'est pas du bon type. Requis: %s, fournis: %s", modelDataTypeClass.getName(), givenDataTypeClass.getName()));
- }
-
- // Si l'objet est une liste, vérifie qu'elle n'est pas vide et qu'elle est du bon type
- if (modelDataTypeClass.equals(List.class) && modelListDataTypeClass != null) {
- List listData = (List) data;
-
- if (listData.size() < 1) {
- throw new IllegalArgumentException("La liste passée en paramètre ne contient aucun élément");
- }
-
- Class givenListDataTypeClass = listData.get(0).getClass();
- if (givenDataTypeClass.equals(modelListDataTypeClass)) {
- throw new IllegalArgumentException(String.format("La liste passée en paramètre contient des éléments du mauvais type. Requis: %s, fournis: %s", modelListDataTypeClass.getName(), givenListDataTypeClass.getName()));
- }
- }
-
- // Ajoute l'attribut dans le Map
- addAttribute(modelDataType.getDataTypeName(), data);
-
- return this;
- }
-
- public ModelAndView build() {
- model.addAllObjects(modelAttributes);
-
- return model;
- }
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/utils/ControllerUtils.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/core/utils/ControllerUtils.java
deleted file mode 100644
index 1e098d7..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/core/utils/ControllerUtils.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.core.utils;
-
-public class ControllerUtils {
-
- public static String redirect(String viewName) {
- return String.format("redirect:/%s", viewName);
- }
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialDao.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialDao.java
deleted file mode 100644
index ce494dc..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialDao.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.dao;
-
-import fyloz.trial.ColorRecipesExplorer.model.Material;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-@Repository
-public interface MaterialDao extends JpaRepository {
- Material findByMaterialID(int materialID);
-
- Material findByMaterialCode(String materialCode);
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialTypeDao.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialTypeDao.java
deleted file mode 100644
index dedbc81..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MaterialTypeDao.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.dao;
-
-import fyloz.trial.ColorRecipesExplorer.model.MaterialType;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-public interface MaterialTypeDao extends JpaRepository {
-
- MaterialType findByMaterialTypeName(String name);
-
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixTypeDao.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixTypeDao.java
deleted file mode 100644
index fe7d839..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/MixTypeDao.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.dao;
-
-import fyloz.trial.ColorRecipesExplorer.model.Material;
-import fyloz.trial.ColorRecipesExplorer.model.MixType;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-@Repository
-public interface MixTypeDao extends JpaRepository {
- MixType findByTypeID(int id);
-
- MixType findByTypeName(String typeName);
-
- MixType findByMaterial(Material material);
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/RecipeDao.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/RecipeDao.java
deleted file mode 100644
index 4c87f35..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/dao/RecipeDao.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.dao;
-
-import fyloz.trial.ColorRecipesExplorer.model.Company;
-import fyloz.trial.ColorRecipesExplorer.model.Recipe;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
-
-import java.util.List;
-
-@Repository
-public interface RecipeDao extends JpaRepository {
-
- List findAllByCompany(Company company);
-
- Recipe findByRecipeCode(String recipeCode);
-
- Recipe findByRecipeID(int recipeID);
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/PdfFactory.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/PdfFactory.java
deleted file mode 100644
index 17a40bd..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/PdfFactory.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.factory.files;
-
-import com.itextpdf.text.Document;
-import com.itextpdf.text.DocumentException;
-import com.itextpdf.text.pdf.PdfWriter;
-import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-
-public class PdfFactory {
-
- protected Document document;
-
- private String fileName;
- private FileHandler fileHandler;
-
- public PdfFactory(String fileName) {
- this(fileName, FileHandler.FileContext.OTHERS);
- }
-
- public PdfFactory(String fileName, FileHandler.FileContext context) {
- this.fileName = fileName;
-
- fileHandler = new FileHandler(fileName, context, FileHandler.FileExtension.PDF);
- }
-
- public PdfFactory open() throws FileNotFoundException, DocumentException {
- document = new Document();
- PdfWriter.getInstance(document, new FileOutputStream(fileHandler.getPath().toString()));
-
- document.open();
-
- return this;
- }
-
- public void write() {
- document.close();
- }
-
- public FileHandler getFileHandler() {
- return fileHandler;
- }
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/TouchUpKitPdfFactory.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/TouchUpKitPdfFactory.java
deleted file mode 100644
index ba7bff0..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/factory/files/TouchUpKitPdfFactory.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.factory.files;
-
-import com.itextpdf.text.*;
-import com.itextpdf.text.pdf.PdfWriter;
-import fyloz.trial.ColorRecipesExplorer.ColorRecipesExplorerApplication;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-public class TouchUpKitPdfFactory {
-
- private String kitName;
- private ByteArrayOutputStream pdfContent;
- private Document document;
-
- public TouchUpKitPdfFactory(String kitName) {
- this.kitName = kitName.toUpperCase();
-
- pdfContent = new ByteArrayOutputStream();
- document = new Document();
- }
-
- public TouchUpKitPdfFactory build() throws DocumentException {
- ColorRecipesExplorerApplication.logger.info(String.format("Génération d'un PDF pour le kit de retouche '%s'", kitName));
-
- PdfWriter.getInstance(document, pdfContent);
-
- Font descFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 48, BaseColor.BLACK);
- Font kitNameFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, kitName.length() > 22 ? 32 : 38, BaseColor.BLACK);
-
- Paragraph descFr = new Paragraph("KIT DE RETOUCHE", descFont);
- Paragraph descEn = new Paragraph("TOUCH UP KIT", descFont);
- Paragraph touchUpKitName = new Paragraph(kitName, kitNameFont);
-
- descFr.setAlignment(Element.ALIGN_CENTER);
- descEn.setAlignment(Element.ALIGN_CENTER);
- touchUpKitName.setAlignment(Element.ALIGN_CENTER);
-
- document.open();
- document.add(descFr);
- document.add(descEn);
- document.add(touchUpKitName);
- document.close();
-
- return this;
- }
-
- public byte[] toByteArray() {
- byte[] content = pdfContent.toByteArray();
-
- try {
- pdfContent.close();
- } catch (IOException e) {
- ColorRecipesExplorerApplication.logger.error("Une erreur est survenue lors de la fermeture d'un ByteArrayOutputStream", e);
- }
-
- return content;
- }
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/form/MaterialForm.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/model/form/MaterialForm.java
deleted file mode 100644
index ed4ceb6..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/model/form/MaterialForm.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.model.form;
-
-import org.springframework.web.multipart.MultipartFile;
-
-public class MaterialForm {
-
- private String materialCode;
-
- private int inventoryQuantity;
-
- private MultipartFile file;
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/CompanyService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/CompanyService.java
deleted file mode 100644
index 2bb8fad..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/CompanyService.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.services;
-
-import fyloz.trial.ColorRecipesExplorer.dao.CompanyDao;
-import fyloz.trial.ColorRecipesExplorer.dao.RecipeDao;
-import fyloz.trial.ColorRecipesExplorer.model.Company;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-@Service
-public class CompanyService extends GenericService {
-
- private RecipeDao recipeDao; // Utilise le Dao pour éviter une erreur au démarrage, citant une récursion (CompanyService -> RecipeService -> CompanyService -> ...)
-
- @Autowired
- public CompanyService(CompanyDao companyDao, RecipeDao recipeDao) {
- super(companyDao);
- this.recipeDao = recipeDao;
- }
-
- @Override
- public boolean isValidForCreation(Company entity) {
- return super.isValidForCreation(entity) && getByName(entity.getCompanyName()) == null;
- }
-
- public Company getByName(String name) {
- return ((CompanyDao) dao).findByCompanyName(name);
- }
-
- /**
- * Vérifie si une bannière est liée à une ou plusieurs recettes en faisant une requête dans la base de données,
- * pour retourner s'il y a des résultats ou non.
- *
- * @return Si la bannière est liée à une ou plusieurs recettes.
- */
- public boolean isLinkedToRecipes(Company company) {
- return !recipeDao.findAllByCompany(company).isEmpty();
- }
-
- public boolean deleteIfNotLinked(Company company) {
- if (!isLinkedToRecipes(company)) {
- return super.delete(company);
- }
-
- return false;
- }
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialTypeService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialTypeService.java
deleted file mode 100644
index 30f0433..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MaterialTypeService.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.services;
-
-import fyloz.trial.ColorRecipesExplorer.dao.MaterialTypeDao;
-import fyloz.trial.ColorRecipesExplorer.model.MaterialType;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-@Service
-public class MaterialTypeService extends GenericService {
-
- private MaterialTypeDao materialTypeDao;
-
- @Autowired
- public MaterialTypeService(MaterialTypeDao materialTypeDao) {
- super(materialTypeDao);
- this.materialTypeDao = materialTypeDao;
- }
-
- @Override
- public boolean isValidForCreation(MaterialType entity) {
- return entity != null && !existsByName(entity);
- }
-
- public MaterialType getByName(String name) {
- return materialTypeDao.findByMaterialTypeName(name);
- }
-
- public MaterialType getDefaultMaterialType() {
- MaterialType defaultType = getByName("Aucun");
-
- if (defaultType == null) {
- defaultType = new MaterialType("Aucun", "", false);
- save(defaultType);
- }
-
- return defaultType;
- }
-
- public boolean existsByName(MaterialType entity) {
- return getByName(entity.getMaterialTypeName()) != null;
- }
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixQuantityService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixQuantityService.java
deleted file mode 100644
index ca69086..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixQuantityService.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.services;
-
-import fyloz.trial.ColorRecipesExplorer.dao.MixQuantityDao;
-import fyloz.trial.ColorRecipesExplorer.model.Material;
-import fyloz.trial.ColorRecipesExplorer.model.MixQuantity;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-@Service
-public class MixQuantityService extends GenericService {
-
- private MixQuantityDao mixQuantityDao;
-
- @Autowired
- public MixQuantityService(MixQuantityDao mixQuantityDao) {
- super(mixQuantityDao);
- this.mixQuantityDao = mixQuantityDao;
- }
-
- /**
- * Récupère la liste des MixQuantity liées à un produit.
- *
- * @param material Le produit
- * @return La page à afficher.
- */
- public List getByMaterial(Material material) {
- return mixQuantityDao.findAllByMaterial(material);
- }
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixService.java
deleted file mode 100644
index bd6d56b..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixService.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.services;
-
-import fyloz.trial.ColorRecipesExplorer.core.ModelBuilder;
-import fyloz.trial.ColorRecipesExplorer.core.ResponseCode;
-import fyloz.trial.ColorRecipesExplorer.dao.MixDao;
-import fyloz.trial.ColorRecipesExplorer.model.*;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Service
-public class MixService extends GenericService {
-
- private MaterialService materialService;
- private MixQuantityService mixQuantityService;
-
- @Autowired
- public MixService(MixDao mixDao, MaterialService materialService, MixQuantityService mixQuantityService) {
- super(mixDao);
- this.materialService = materialService;
- this.mixQuantityService = mixQuantityService;
- }
-
- /**
- * Crée un mélange, ainsi que tous ses sous-éléments.
- *
- * materials & quantities doivent avoir le même ordre.
- *
- * @param materials La liste des identifiants des matériaux
- * @param quantities La liste des quantités de matériaux
- * @param recipe La recette associée au mélange
- * @param mixType Le type du mélange
- * @return Le message d'erreur, s'il y a lieu
- */
- @Transactional
- public ModelBuilder create(ModelBuilder modelBuilder, List materials, List quantities, Recipe recipe, MixType mixType) {
- // Crée le mélange en premier pour avoir accès à son ID pour les autres éléments
- Mix mix = new Mix(recipe, mixType, null);
-
- if ((mix = save(mix)) != null) {
- List mixQuantities = createMixQuantities(mix, materials, quantities);
- if (mixQuantities == null) {
- return modelBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND);
- }
-
- if (mixQuantityService.saveAll(mixQuantities)) return null;
- }
-
- return modelBuilder.addResponseCode(ResponseCode.ERROR_SAVING);
- }
-
- /**
- * Modifie un mélange, ainsi que ses sous-éléments.
- *
- * materials & quantities doivent avoir le même ordre.
- *
- * @param mix Le mélange à modifier
- * @param materials La liste des identifiants des matériaux
- * @param quantities La liste des quantités de matériaux
- * @return Si le mélange a été modifier.
- */
- public boolean edit(Mix mix, List materials, List quantities) {
- List mixQuantities = createMixQuantities(mix, materials, quantities);
- if (mixQuantities == null) return false;
-
- // Supprime les anciens MixQuantity pour éviter les doublons et les entrées inutiles dans la base de données
- if (!mixQuantityService.deleteAll(mix.getMixQuantities())) {
- return false;
- }
-
- return mixQuantityService.saveAll(mixQuantities);
- }
-
- public boolean deleteMix(Mix mix) {
- if (mixQuantityService.deleteAll(mix.getMixQuantities())) {
- return super.delete(mix);
- }
-
- return false;
- }
-
- /**
- * Crée une liste de MixQuantity, pour la création d'un mélange
- *
- * @param mix Le mélange associé aux MixQuantity
- * @param materials Les matériaux
- * @param quantities Les quantités
- * @return La liste des MixQuantity créés.
- */
- private List createMixQuantities(Mix mix, List materials, List quantities) {
- List mixQuantities = new ArrayList<>();
-
- int i = 0;
- for (int materialID : materials) {
- Material material = materialService.getByID(materialID);
-
- if (material == null) {
- return null;
- }
-
- float associatedQuantity = quantities.get(i);
-
- MixQuantity quantity = new MixQuantity(mix, material, associatedQuantity);
- mixQuantities.add(quantity);
-
- i++;
- }
-
- return mixQuantities;
- }
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixTypeService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixTypeService.java
deleted file mode 100644
index 4eaf2c3..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/MixTypeService.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.services;
-
-import fyloz.trial.ColorRecipesExplorer.dao.MixTypeDao;
-import fyloz.trial.ColorRecipesExplorer.model.Material;
-import fyloz.trial.ColorRecipesExplorer.model.MixType;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-@Service
-public class MixTypeService extends GenericService {
-
- private MixTypeDao mixTypeDao;
- private MaterialTypeService materialTypeService;
-
- @Autowired
- public MixTypeService(MixTypeDao mixTypeDao, MaterialTypeService materialTypeService) {
- super(mixTypeDao);
- this.mixTypeDao = mixTypeDao;
- this.materialTypeService = materialTypeService;
- }
-
- public MixType getByName(String name) {
- return mixTypeDao.findByTypeName(name);
- }
-
- public MixType getByMaterial(Material material) {
- return mixTypeDao.findByMaterial(material);
- }
-
- public MixType createByName(String name) {
- Material mixTypeMaterial = new Material(name, 0, true, materialTypeService.getDefaultMaterialType());
- MixType mixType = new MixType(name, mixTypeMaterial);
-
- mixType = save(mixType);
- if (mixType == null) {
- return getByName(name);
- }
-
- return mixType;
- }
-}
diff --git a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/RecipeService.java b/src/main/java/fyloz/trial/ColorRecipesExplorer/services/RecipeService.java
deleted file mode 100644
index c2209a4..0000000
--- a/src/main/java/fyloz/trial/ColorRecipesExplorer/services/RecipeService.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package fyloz.trial.ColorRecipesExplorer.services;
-
-import fyloz.trial.ColorRecipesExplorer.core.io.FileHandler;
-import fyloz.trial.ColorRecipesExplorer.dao.RecipeDao;
-import fyloz.trial.ColorRecipesExplorer.model.*;
-import fyloz.trial.ColorRecipesExplorer.web.StringBank;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.util.MultiValueMap;
-
-import java.io.File;
-import java.util.*;
-import java.util.stream.Collectors;
-
-@Service
-public class RecipeService extends GenericService {
-
- private RecipeDao recipeDao;
- private CompanyService companyService;
- private StepService stepService;
- private MixService mixService;
-
- @Autowired
- public RecipeService(RecipeDao recipeDao, CompanyService companyService, StepService stepService, MixService mixService) {
- super(recipeDao);
- this.recipeDao = recipeDao;
- this.companyService = companyService;
- this.stepService = stepService;
- this.mixService = mixService;
- }
-
- /**
- * Récupère la liste des recettes associées à une compagnie.
- *
- * @param company La compagnie.
- * @return La liste des recettes associées à cette compagnie.
- */
- public List getByCompany(Company company) {
- return recipeDao.findAllByCompany(company);
- }
-
- /**
- * Crée et assigne des étapes à une recette, en se basant sur l'entrée de utilisateur.
- *
- * @param recipe La recette à assigner les étapes
- * @param input L'entrée de l'utilisateur, contenant les étapes (key = "step_*")
- * @return La recette avec les étapes.
- */
- public Recipe createAndSetSteps(Recipe recipe, MultiValueMap input) {
- List steps = new ArrayList<>();
- for (String key : input.keySet()) {
- Object field = input.get(key);
- if (key.startsWith("step_") && field instanceof LinkedList) {
- steps.add(new RecipeStep(recipe, ((LinkedList) field).get(0).toString()));
- }
- }
-
- List recipeSteps = recipe.getRecipeSteps();
- if (recipeSteps != null) {
- stepService.deleteAll(recipeSteps);
- }
- recipe.setRecipeSteps(steps);
- save(recipe);
-
- return recipe;
- }
-
- /**
- * Supprime complètement une recette ainsi que les éléments qui y sont attachés de la base de données.
- *
- * @param recipe La recette à supprimer
- */
- public void deleteRecipe(Recipe recipe) {
- List mixes = recipe.getRecipeMixes();
- mixService.deleteAll(mixes);
-
- stepService.deleteAll(recipe.getRecipeSteps());
- delete(recipe);
-
- FileHandler fileHandler;
- for (String image : getImageFiles(recipe)) {
- fileHandler = new FileHandler(image.replace(".jpeg", ""), FileHandler.FileContext.IMAGE, FileHandler.FileExtension.JPEG);
- fileHandler.deleteFile();
- }
- }
-
- /**
- * Récupère une liste triée des mélanges pour une recette.
- *
- * @param recipe La recette dont on veut récupérer les mélanges
- * @return Une liste triée des mélanges.
- */
- public List | | | | | | | |