From 8d176bf6d0ff6411dc6edc23ffdc76006eb5853f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Thu, 23 May 2024 10:34:18 +0200 Subject: [PATCH 01/30] =?UTF-8?q?Ajout=20du=20formulaire=20d'enqu=C3=AAte.?= =?UTF-8?q?=20fixes=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/drop.sql | 3 + sql/init_data.h2.sql | 6 + sql/init_data.postgresql.sql | 21 + sql/questions.csv | 4 + sql/responses.csv | 19 + sql/schema.tables.sql | 29 ++ .../java/fr/agrometinfo/www/client/App.java | 4 +- .../www/client/i18n/AppConstants.java | 28 +- .../www/client/presenter/LoginPresenter.java | 130 +++++++ .../www/client/view/AbstractBaseView.java | 41 +- .../www/client/view/LayoutView.java | 59 ++- .../www/client/view/LoginView.java | 179 +++++++++ .../client/i18n/AppConstants_fr.properties | 10 + .../agrometinfo/www/client/public/style.css | 18 + .../fr/agrometinfo/www/client/style.css | 208 ++++++++++ .../www/server/AgroMetInfoConfiguration.java | 1 - .../www/server/dao/DaoHibernate.java | 25 +- .../www/server/dao/QuestionsDao.java | 32 ++ .../www/server/dao/QuestionsDaoHibernate.java | 34 ++ .../www/server/dao/ResponsesDao.java | 34 ++ .../www/server/dao/ResponsesDaoHibernate.java | 36 ++ .../www/server/dao/UserResponsesDao.java | 48 +++ .../server/dao/UserResponsesDaoHibernate.java | 64 +++ .../www/server/model/LoginFormData.java | 50 +++ .../www/server/model/Question.java | 38 ++ .../www/server/model/Response.java | 45 +++ .../www/server/model/UserResponses.java | 56 +++ .../www/server/rs/ApplicationConfig.java | 4 +- .../www/server/rs/LoginFormResource.java | 240 ++++++++++++ .../www/server/service/MailService.java | 320 +-------------- .../www/server/service/MailServiceImpl.java | 361 +++++++++++++++++ www-server/src/main/webapp/index.html | 2 +- .../www/server/LoginFormHibernateTest.java | 192 +++++++++ .../www/server/exception/ErrorTypeTest.java | 4 +- .../www/server/rs/LoginFormResourceTest.java | 368 ++++++++++++++++++ .../test/resources/META-INF/persistence.xml | 3 + .../www/shared/dto/LoginFormDataDTO.java | 84 ++++ .../www/shared/dto/QuestionDTO.java | 85 ++++ .../www/shared/dto/ResponseDTO.java | 64 +++ .../www/shared/service/LoginFormService.java | 92 +++++ 40 files changed, 2708 insertions(+), 333 deletions(-) create mode 100644 sql/questions.csv create mode 100644 sql/responses.csv create mode 100644 www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java create mode 100644 www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java create mode 100644 www-client/src/main/resources/fr/agrometinfo/www/client/style.css create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/model/LoginFormData.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java create mode 100644 www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java create mode 100644 www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java create mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java create mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java create mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java create mode 100644 www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java diff --git a/sql/drop.sql b/sql/drop.sql index ee674b8..324c3c5 100644 --- a/sql/drop.sql +++ b/sql/drop.sql @@ -10,3 +10,6 @@ DROP TABLE period; DROP TABLE i18n; DROP TABLE i18nkey; DROP TABLE locale; +DROP TABLE user2responses; +DROP TABLE responses; +DROP TABLE questions; diff --git a/sql/init_data.h2.sql b/sql/init_data.h2.sql index c898645..6095f2c 100644 --- a/sql/init_data.h2.sql +++ b/sql/init_data.h2.sql @@ -127,3 +127,9 @@ INSERT INTO simulation (date, simulationid, started, ended) VALUES -- REFRESH MATERIALIZED VIEW v_pra_dailyvalue; +INSERT INTO questions(question_ref, category, fullname) + SELECT * FROM CSVREAD('../sql/questions.csv'); + +INSERT INTO responses(question_ref, fullname) + SELECT * FROM CSVREAD('../sql/responses.csv', null, 'fieldSeparator=;'); + diff --git a/sql/init_data.postgresql.sql b/sql/init_data.postgresql.sql index 6648baa..056f7c5 100644 --- a/sql/init_data.postgresql.sql +++ b/sql/init_data.postgresql.sql @@ -1,6 +1,19 @@ -- Initialization script for PostgreSQL database with sample data -- also do update. +DELETE FROM normalvalue; +DELETE FROM dailyvalue; +DELETE FROM cell; +DELETE FROM department; +DELETE FROM region; +DELETE FROM indicator; +DELETE FROM period; +DELETE FROM i18n; +DELETE FROM i18nkey; +DELETE FROM locale; +DELETE FROM questions; +DELETE FROM responses; + -- translations CREATE TEMPORARY TABLE IF NOT EXISTS tmp_translation ( key VARCHAR, @@ -155,3 +168,11 @@ INSERT INTO normalvalue (indicator, cell, doy, medianvalue, q5, q95) JOIN period AS p ON p.id=i.period WHERE p.code=t.period ON CONFLICT ON CONSTRAINT "UK_normalvalue" DO NOTHING; + +-- questions +\COPY questions(question_ref, category, fullname) FROM questions.csv WITH DELIMITER ',' HEADER CSV; + +-- responses +-- WARNING : responses CSV file use semicolon (« ; ») as separator !! +\COPY responses(question_ref, fullname) FROM sql/responses.csv WITH DELIMITER ';' HEADER CSV; + diff --git a/sql/questions.csv b/sql/questions.csv new file mode 100644 index 0000000..faac491 --- /dev/null +++ b/sql/questions.csv @@ -0,0 +1,4 @@ +question_ref,category,fullname +1,profession,Quelle est votre profession ? +2,origin,Comment avez-vous connu AgroMetInfo ? +3,useCase,Dans quel but voulez-vous utiliser cette application ? diff --git a/sql/responses.csv b/sql/responses.csv new file mode 100644 index 0000000..a88a2c0 --- /dev/null +++ b/sql/responses.csv @@ -0,0 +1,19 @@ +question_ref;fullname +1;Agriculteur +1;Conseiller agricole (Chambre d'agriculture, Entreprise de service) +1;Scientifique +1;Journaliste +1;Administration +1;Enseignant +1;Citoyen curieux (c'est bien) +2;Internet +2;Via le site internet d'AgroClim +2;Via le site internet INRAE +2;Média (TV, journaux, radio) +2;Réseaux sociaux (Linkedin, Facebook, X, ...) +2;Bouche à oreilles +3;S'informer +3;Enseigner +3;Conseiller +3;Publier un article dans les médias +3;Faire une présentation diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql index 77eff33..a469a08 100644 --- a/sql/schema.tables.sql +++ b/sql/schema.tables.sql @@ -214,6 +214,35 @@ CREATE TABLE IF NOT EXISTS dailyvisit( ); COMMENT ON TABLE dailyvisit IS 'Number of visits per day.'; +-- Tables pour le formulaire d'enquête +CREATE TABLE IF NOT EXISTS questions ( + question_ref serial NOT NULL, + category varchar(20) NOT NULL, + fullname varchar(255) NULL, + CONSTRAINT questions_pk PRIMARY KEY (question_ref) +); +COMMENT ON TABLE questions IS 'Questions pour le formulaire d''enquête'; + +CREATE TABLE IF NOT EXISTS responses ( + response_ref serial NOT NULL, + question_ref int4 NOT NULL, + fullname varchar NULL, + CONSTRAINT responses_pk PRIMARY KEY (response_ref), + CONSTRAINT responses_questions_fk FOREIGN KEY (question_ref) REFERENCES questions(question_ref) +); +CREATE TABLE IF NOT EXISTS user2responses ( + user_response_ref serial NOT NULL, + datetime timestamp NOT NULL, + question_ref int4 NOT NULL, + response_ref int4 NULL, + other_text varchar NULL, + CONSTRAINT user2responses_pk PRIMARY KEY (user_response_ref), + CONSTRAINT user2responses_questions_fk FOREIGN KEY (question_ref) REFERENCES questions(question_ref), + CONSTRAINT user2responses_responses_fk FOREIGN KEY (response_ref) REFERENCES responses(response_ref) +); +COMMENT ON TABLE user2responses IS 'Réponses des utilisateurs'; + + CREATE OR REPLACE VIEW v_i18n AS SELECT l.languagetag, i.i18nkey, diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/App.java b/www-client/src/main/java/fr/agrometinfo/www/client/App.java index 920e623..d1895a5 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/App.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/App.java @@ -98,7 +98,9 @@ public class App implements EntryPoint { // enabling Charba Charba.enable(); - new LayoutPresenter().start(); + + // formulaire d'enquête + new LoginPresenter().start(); } } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java index ec07adb..b45c154 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java @@ -1,5 +1,7 @@ package fr.agrometinfo.www.client.i18n; +import java.util.Map; + /** * Interface to represent the constants contained in resource bundle: * 'fr/agrometinfo/www/client/i18n/AppConstants.properties'. @@ -338,5 +340,29 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo */ @DefaultStringValue("Yes") String yes(); - + + // Formulaire d'enquête - #5 + @DefaultStringValue("Valider") + String validate(); + + @DefaultStringValue("Ignorer") + String ignore(); + + @DefaultStringValue("Formulaire d'enquête") + String loginFormTitle(); + + @DefaultStringValue("Please complete this survey form to continue on AgroMetInfo.") + String loginFormDescription(); + + @DefaultStringValue("Other") + String loginFormOtherTextCheckbox(); + + @DefaultStringValue("You must click on checkbox above for activate this input field.") + String loginFormOtherTextTooltip(); + + @DefaultStringValue("Your responses have been recorded.") + String loginFormSuccess(); + + @DefaultStringValue("Your responses cannot been recorded, but you can use AgroMetInfo application.") + String loginFormFail(); } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java new file mode 100644 index 0000000..1c7d2f9 --- /dev/null +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java @@ -0,0 +1,130 @@ +package fr.agrometinfo.www.client.presenter; + +import java.util.ArrayList; +import java.util.List; + +import org.dominokit.rest.shared.request.FailedResponseBean; + +import com.google.gwt.core.client.GWT; + +import fr.agrometinfo.www.client.view.BaseView; +import fr.agrometinfo.www.client.view.LoginView; +import fr.agrometinfo.www.shared.dto.QuestionDTO; +import fr.agrometinfo.www.shared.dto.ResponseDTO; +import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; +import fr.agrometinfo.www.shared.service.LoginFormServiceFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * Presenter to login the user with survey form. + * + * @author Olivier Maury + * @author Jérémie Décome + */ +public final class LoginPresenter implements Presenter { + + /** + * Interface for the related view. + */ + public interface View extends BaseView<LoginPresenter> { + /** + * Display notification on failure. + * + * @param failedResponse failure response + */ + void failureNotification(FailedResponseBean failedResponse); + /** + * Close modal. + */ + void close(); + /** + * @param list list of availables responses. + */ + void setResponses(Map<QuestionDTO, List<ResponseDTO>> map); + /** + * Showing success login. + * @param msg returned message from webservice + */ + void displaySuccessLogin(final String msg); + } + + /** + * Related view. + */ + private final LoginView view = new LoginView(); + /** List of responses from webservice. */ + private List<ResponseDTO> responses; + /** List of questions, extracted from responses list. */ + private List<QuestionDTO> questions; + /** + * Set responses and extract questions from responses list. + * @param list list of responses + */ + private void setResponses(final List<ResponseDTO> list) { + GWT.log("setResponses(" + list.size() +") start"); + this.responses = list; + final Map<QuestionDTO, List<ResponseDTO>> responsesMap = new HashMap<>(); + + // extraction des questions, à partir des réponses retournées par le webservice + for (final ResponseDTO dto : list) { + if (!responsesMap.containsKey(dto.getQuestion())) { // la map ne contient pas la question + // on crée l'entrée, avec une liste vide + responsesMap.put(dto.getQuestion(), new ArrayList<ResponseDTO>()); + } + responsesMap.get(dto.getQuestion()).add(dto); + } + this.questions = new ArrayList<>(responsesMap.keySet()); + view.setResponses(responsesMap); + GWT.log("setResponses() end"); + + view.init(); + } + @Override + public void start() { + view.setPresenter(this); + + LoginFormServiceFactory.INSTANCE.getResponses() + .onSuccess(this::setResponses) + .onFailed(view::failureNotification) + .send(); + } + public void insertUserResponses(final List<Long> responsesRef, final HashMap<Long, String> otherTextMap) { + GWT.log("Insère les réponses de l'utilisateur"); + + // traitement des réponses prédéfinies + final List<QuestionDTO> questionsDto = new ArrayList<>(); + final List<ResponseDTO> responsesDto = new ArrayList<>(); + + for (final Long ref : responsesRef) { + // on récupère la réponse correspondante à la référence + final ResponseDTO rDto = this.responses.stream().filter(r -> r.getResponseRef() == ref).findFirst().get(); + if (rDto != null) { + if (!responsesDto.contains(rDto)) { + responsesDto.add(rDto); + } + + // on récupère la question correspondantes à la réponse + if (!questionsDto.contains(rDto.getQuestion())) { + questionsDto.add(rDto.getQuestion()); + } + } + } + // ajout de la question, si celle çi n'a qu'une réponse libre + this.questions.forEach((q) -> { + if (!questionsDto.contains(q) && otherTextMap.containsKey(q.getQuestionRef())) { + questionsDto.add(q); + } + }); + + final LoginFormDataDTO data = new LoginFormDataDTO(questionsDto, responsesDto, otherTextMap); + + // envoi au webservice + LoginFormServiceFactory.INSTANCE.insertAllResponses(data) + .onSuccess(view::displaySuccessLogin) + .onFailed(view::failureNotification) + .send(); + } + +} diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/AbstractBaseView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/AbstractBaseView.java index 789fd1c..52236ee 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/AbstractBaseView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/AbstractBaseView.java @@ -1,5 +1,16 @@ package fr.agrometinfo.www.client.view; +import java.util.StringJoiner; + +import org.dominokit.domino.ui.notifications.Notification; +import org.dominokit.rest.shared.request.FailedResponseBean; + +import com.google.gwt.core.client.GWT; + +import elemental2.dom.DomGlobal; +import fr.agrometinfo.www.client.i18n.AppConstants; +import fr.agrometinfo.www.client.i18n.AppMessages; + /** * Abstract class for all view implementations. * @@ -12,6 +23,30 @@ public abstract class AbstractBaseView<T> implements BaseView<T> { * Related presenter. */ private T presenter; + /** + * I18N constants. + */ + private static final AppConstants CSTS = GWT.create(AppConstants.class); + /** + * I18N messages. + */ + private static final AppMessages MSGS = GWT.create(AppMessages.class); + /** + * + * @param failure + * @return + */ + protected static String getDetails(final FailedResponseBean failure) { + final StringJoiner sj = new StringJoiner("<br/>"); + sj.add(CSTS.failureBody()); + sj.add(failure.getBody()); + sj.add(CSTS.failureHeaders()); + sj.add(failure.getHeaders().toString()); + sj.add(MSGS.failureStatusCode(failure.getStatusCode())); + sj.add(CSTS.failureStatusText()); + sj.add(failure.getStatusText()); + return sj.toString(); + } /** * @return related presenter @@ -24,5 +59,9 @@ public abstract class AbstractBaseView<T> implements BaseView<T> { public final void setPresenter(final T value) { this.presenter = value; } - + + protected Notification notification(final String msg) { + DomGlobal.console.info("Notification!"); + return Notification.create(msg).setPosition(Notification.TOP_LEFT).show(); + } } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java index 5f7e8ba..6006d8a 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java @@ -89,17 +89,6 @@ implements LayoutPresenter.View, LoadingHandler { addMenuItem(menu, text, icon, runnable); } - private static String getDetails(final FailedResponseBean failure) { - final StringJoiner sj = new StringJoiner("<br/>"); - sj.add(CSTS.failureBody()); - sj.add(failure.getBody()); - sj.add(CSTS.failureHeaders()); - sj.add(failure.getHeaders().toString()); - sj.add(MSGS.failureStatusCode(failure.getStatusCode())); - sj.add(CSTS.failureStatusText()); - sj.add(failure.getStatusText()); - return sj.toString(); - } /** * @param relativePath documentation path relative to documentation root @@ -389,11 +378,21 @@ implements LayoutPresenter.View, LoadingHandler { return layout.isRightPanelVisible(); } - private Notification notification(final String msg) { - DomGlobal.console.info("Notification! " + msg); - return Notification.create(msg).setPosition(Notification.TOP_LEFT).show(); + private void onChoiceChange() { + if (choice.isValid()) { + getPresenter().onChoiceChange(choice); + } + } + + private void onComparisonChange(final boolean newValue) { + choice.setComparison(newValue); + onChoiceChange(); } + private void onIndicatorChange(final String newValue) { + choice.setIndicator(newValue); + onChoiceChange(); + } @Override public void onLoading(final LoadingEvent event) { GWT.log("LayoutView.onLoading() " + event); @@ -417,7 +416,37 @@ implements LayoutPresenter.View, LoadingHandler { } GWT.log("LayoutView.onLoading() done"); } - + private void onPeriodChange(final String newValue) { + choice.setPeriod(newValue); + choice.setIndicator(null); + + // fill indicators + List<IndicatorDTO> list = null; + for (final PeriodDTO p : this.periods) { + if (p.getCode().equals(newValue)) { + list = p.getIndicators(); + break; + } + } + if (list == null) { + return; + } + DomGlobal.console.info("Indicators : " + list); + new HTMLSelectElementBuilder<IndicatorDTO>() // + .setSelect(indicatorSelect) // + .setTextFunction(IndicatorDTO::getDescription) // + .setValueFunction(IndicatorDTO::getCode) // + .removeOptions() // + .addOptions(list) // + .build(); + // select "meant" + if (list.stream().map(IndicatorDTO::getCode).anyMatch(DEFAULT_INDICATOR::equals)) { + indicatorSelect.element().value = DEFAULT_INDICATOR; + onIndicatorChange(DEFAULT_INDICATOR); + } else { + onChoiceChange(); + } + } /** * To display an OpenLayers map, a container with a fixed height CSS property is * needed. diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java new file mode 100644 index 0000000..b1f3164 --- /dev/null +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java @@ -0,0 +1,179 @@ +package fr.agrometinfo.www.client.view; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.ArrayList; +import java.util.HashMap; + +import org.dominokit.domino.ui.button.Button; +import org.dominokit.domino.ui.forms.CheckBox; +import org.dominokit.domino.ui.forms.TextArea; +import org.dominokit.domino.ui.modals.ModalDialog; +import org.dominokit.rest.shared.request.FailedResponseBean; +import org.jboss.elemento.Elements; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.storage.client.Storage; + +import fr.agrometinfo.www.client.i18n.AppConstants; +import fr.agrometinfo.www.client.i18n.AppMessages; +import fr.agrometinfo.www.client.presenter.LoginPresenter; +import fr.agrometinfo.www.shared.dto.QuestionDTO; +import fr.agrometinfo.www.shared.dto.ResponseDTO; + +/** + * View for survey form. + * + * @author Olivier Maury + * @author Jérémie Décome + * + */ +public final class LoginView extends AbstractBaseView<LoginPresenter> implements LoginPresenter.View { + /** + * I18N constants. + */ + private static final AppConstants CSTS = GWT.create(AppConstants.class); + /** + * I18N messages. + */ + private static final AppMessages MSGS = GWT.create(AppMessages.class); + /** + * Is survey was already validated by user ? + */ + private static final String IS_VALIDATED_KEY = "isValidated"; + /** + * List of available responses. + */ + private Map<QuestionDTO, List<ResponseDTO>> availableResponses; + /** + * The modal used to display the login form. + */ + private ModalDialog modal; + /** Validate button of modal. */ + private Button validate; + /** List of all checkbox on modal. */ + private List<CheckBox> checkBoxList = new ArrayList<>(); + + @Override + public void close() { + modal.close(); + } + + @Override + public void init() { + GWT.log("LoginView.init()"); + // on vérifie que le formulaire n'a pas déjà été rempli par l'utilisateur, via le LocalStorage du navigateur + final Storage ls = Storage.getLocalStorageIfSupported(); + if (ls != null) { + if (ls.getItem(IS_VALIDATED_KEY) != null && ls.getItem(IS_VALIDATED_KEY).equals("true")) { + GWT.log("Survey was already validated for this user, don't showing again"); + return; + } + } + + final Map<Long, TextArea> otherTextArea = new HashMap<>(); + + this.modal = ModalDialog.create(CSTS.loginFormTitle()).large().setAutoClose(true); + this.modal + .appendChild(Elements.p().textContent(CSTS.loginFormDescription()).css("login-paragraph")); + + for (Map.Entry<QuestionDTO, List<ResponseDTO>> entry : this.availableResponses.entrySet()) { + final QuestionDTO k = entry.getKey(); // Pour chaque question + + // on affiche le libellé + this.modal.appendChild(Elements.h(5, "• " + k.getFullName())); + + // on affiche les réponses possibles + entry.getValue().forEach((r) -> { + final CheckBox cb = CheckBox.create(r.getFullname()).id(Long.toString(r.getResponseRef())) + .css("login-checkbox"); + this.modal.appendChild(cb); + this.checkBoxList.add(cb); + }); + + // on affiche le champ pour la réponse libre + final CheckBox otherCb = CheckBox.create(CSTS.loginFormOtherTextCheckbox()).id(k.getCategory() + "_other").css("login-checkbox"); + final TextArea otherText = TextArea.create().setId(k.getCategory() + "_other_text") + .setDisabled(true) + .setTooltip(CSTS.loginFormOtherTextTooltip()) + .setRows(2) + .css("login-textarea"); + + otherCb.addChangeHandler((v) -> { + otherText.setDisabled(!otherCb.getValue()); + if (!otherText.isDisabled()) { + otherText.removeTooltip(); + } else { + otherText.setTooltip(CSTS.loginFormOtherTextTooltip()); + } + }); + this.checkBoxList.add(otherCb); + this.modal.appendChild(otherCb).appendChild(otherText); + otherTextArea.put(k.getQuestionRef(), otherText); + } + // active le bouton Valider si au moins une case a été cochée + this.checkBoxList.forEach((c) -> { + c.addChangeHandler((v) -> this.activateValidateButton()); + }); + + // E-mail de l'utilisateur + + this.validate = Button.create(CSTS.validate()).linkify(); + this.validate.addClickListener((evt) -> { + final HashMap<Long, String> otherTextMap = new HashMap<>(); + + // on traite les réponses prédéfinies (récupération des références des réponses), en excluant les cases à cocher pour les réponses libre + final List<Long> selectedResponsesRef = this.checkBoxList.stream() + .filter((v) -> v.getValue() && v.getId().matches("[0-9]+")) + .map(v -> Long.parseLong(v.getId())).collect(Collectors.toList()); + + // traitement des réponses libre de la question + otherTextArea.forEach((k, v) -> { + // si le champ est actif, c'est qu'il y a (potentiellement) une réponse et si le champ n'est pas vide + if (!v.isDisabled() && !v.getValue().equals("")) { + otherTextMap.put(k, v.getValue()); + } + }); + + this.getPresenter().insertUserResponses(selectedResponsesRef, otherTextMap); + + ls.setItem(IS_VALIDATED_KEY, "true"); + this.modal.close(); + }); + this.validate.setDisabled(true); // le bouton Valider est désactivé par défaut + this.modal.appendFooterChild(validate); + + final Button ignore = Button.create(CSTS.ignore()).linkify(); + ignore.addClickListener((evt) -> { + this.modal.close(); + }); + this.modal.appendFooterChild(ignore); + + this.modal.open(); + GWT.log("LoginView.init() end"); + } + + @Override + public void failureNotification(FailedResponseBean failedResponse) { + this.notification(CSTS.loginFormFail()); + } + + @Override + public void setResponses(Map<QuestionDTO, List<ResponseDTO>> map) { + GWT.log("LoginView.setResponses(" + map.size() + ")"); + this.availableResponses = map; + GWT.log("LoginView.setResponses() end"); + } + + @Override + public void displaySuccessLogin(String msg) { + this.notification(CSTS.loginFormSuccess()); + } + /** + * Enable or disable validate button depending of checkbox status. + */ + private void activateValidateButton() { + this.validate.setDisabled(!this.checkBoxList.stream().anyMatch((c) -> c.getValue() == true)); + } +} diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties index 3436fb9..685c04a 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties @@ -49,3 +49,13 @@ Pour rester au courant des évolutions, vous pouvez nous envoyer un message à \ <a href="mailto:support-agrometinfo@inrae.fr?subject=AgroMetInfo:%20contact">support-agrometinfo@inrae.fr</a> ou utiliser le formulaire de contact. welcomeTitle = Bienvenue sur AgroMetInfo yes = Oui +userProfile = Compte et paramètres +whyConnectionIsRequired = Vous devez vous identifier pour accéder à AgroMetInfo en raison des accords avec Météo-France relatifs aux échanges de données SAFRAN avec AgroClim. +validate = Valider +ignore = Ignorer +loginFormTitle = Formulaire d'enquête +loginFormDescription = Merci de compléter ce formulaire d'enquête afin de continuer sur AgroMetInfo +loginFormOtherTextCheckbox = Autre, à préciser +loginFormOtherTextTooltip = Vous devez cliquer sur la case à cocher ci-dessus pour activer ce champ de saisie. +loginFormSuccess = Vos réponses au formulaire d'enquête ont bien été enregistrées. +loginFormFail = Vos réponses au formulaire n'ont pas pu être, mais vous pouvez tout de même utiliser AgroMetInfo. \ No newline at end of file diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css index bdbff67..1cf0b4c 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css @@ -348,3 +348,21 @@ body > .modal-backdrop { --rightsidebar-width: 600px; } } + +/* Formulaire d'enquête */ +.login-paragraph { + font-size: 18px; +} +.login-checkbox { + margin: 0 0 2px 5px; +} +.login-checkbox .field-cntr { + padding: 0 10px !important; +} +.login-checkbox label { + top: 0px !important; + margin-bottom: 0px !important; +} +.login-textarea .field-cntr { + padding-top: 5px; +} \ No newline at end of file diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/style.css new file mode 100644 index 0000000..bdd54e8 --- /dev/null +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/style.css @@ -0,0 +1,208 @@ +footer { + background-color: #353854; +} +footer.footer { + max-height: 2em; + min-height: 2em; + text-align: center; + margin-left: auto; + margin-right: auto; +} +footer, footer a { + color: #b5b5c8; + font-weight: bold; + margin-right: 1em; + padding: 0.3em; +} +footer a:hover { + color: #ffffff; +} +select { + width: 100%; + height: 2.5em; + font-size: 1.1em; +} +/** + * Font awesome icons. + */ +/*! + * Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@font-face { + font-family:"Font Awesome 5 Free"; + font-style:normal; + font-weight:900; + src:url(vendors/fa/fa-solid-900.eot); + src:url(vendors/fa/fa-solid-900.eot?#iefix) format("embedded-opentype"), + url(vendors/fa/fa-solid-900.woff2) format("woff2"), + url(vendors/fa/fa-solid-900.woff) format("woff"), + url(vendors/fa/fa-solid-900.ttf) format("truetype"), + url(vendors/fa/fa-solid-900.svg#fontawesome) format("svg") +} +.fa, .fab, .fal, .far, .fas { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; +} +.fa, .fas { + font-family: "Font Awesome 5 Free"; + font-weight: 900; +} +.fa-cloud-showers-heavy::before { + content: "\f740"; +} +.fa-snowflake::before { + content: "\f2dc"; +} +.fa-thermometer-half::before { + content: "\f2c9"; +} +.fa-thermometer-quarter::before { + content: "\f2ca"; +} +.fa-thermometer-three-quarters::before { + content: "\f2c8"; +} +.agroclim-apps img { + height: 60px; + width: 60px; +} +.agroclim-apps ul { + box-sizing: content-box; + width: 200px; +} +.agroclim-apps.dom-ui.menu .simple-menu-item { + display: inline-block; + padding-bottom: 15px; + text-align: center; + width: 100px; +} +.agrometinfo-navbar .navbar-header { + min-height: var(--logo-height); + padding-top: 0px; +} +.agrometinfo-navbar .navbar-header .menu-toggle .bars { + line-height: 15px; +} +.agrometinfo-leftsidebar.sidebar, +.agrometinfo-rightsidebar.right-sidebar { + height: calc(100vh - var(--logo-height)); + top: var(--logo-height); +} +.agrometinfo-rightsidebar.right-sidebar { + width: var(--rightsidebar-width); +} +.agrometinfo-rightsidebar.right-sidebar.slide-out-right { + right: calc(-1 * var(--rightsidebar-width)); +} +.agrometinfo-topbar.navbar { + border: 0px; +} +.agrometinfo-topbar.navbar-nav > li > a { + padding-bottom: 6px; + padding-top: 6px; +} +.float-right { + float: right; +} +div.idp { + padding: 0.5em; +} +.idp img { + padding-right: 1em; +} +.idp span { + font-weight: bold; +} +.indicator-categories > i { + font-size: 40px; + padding-left: 5px; +} +.javascript-disabled { + width: 22em; + position: absolute; + left: 50%; + margin-left: -11em; + color: red; + background-color: white; + border: 1px solid red; + padding: 4px; + font-family: sans-serif +} +.logo-in img { + background-color: white; + height: var(--logo-height); +} +#mapContainer .ol-attribution.ol-uncollapsible { + top: auto; + right: auto; + bottom: 0.2em; + right: .5em; +} +#mapContainer .ol-control button { + /* same as layer switcher */ + height: 38px; + width: 38px; +} +#mapContainer .ol-full-screen { + top: .5em; + right: .5em; + bottom: auto; + left: auto; +} +#mapContainer .layer-switcher { + top: 3.5em; + right: .5em; + bottom: auto; + left: auto; +} +#mapContainer .ol-zoom-extent { + top: auto; + bottom: 8em; + right: .5em; + left: auto; +} +#mapContainer .ol-zoom { + top: auto; + bottom: 2em; + right: .5em; + left: auto; +} +:root { + --logo-height: 50px; +} +@media screen and (max-width: 450px) { + .navbar-brand { + display: none; + } +} +@media screen and (max-width: 700px) { + :root { + --rightsidebar-width: 90%; + } +} +@media screen and (min-width: 700px) { + :root { + --rightsidebar-width: 400px; + } +} + +/* Formulaire d'enquête */ +.login-paragraph { + font-size: 18px; +} +.login-checkbox { + margin: 0 0 2px 5px; +} +.login-checkbox .field-cntr { + padding: 0 10px !important; +} +.login-checkbox label { + top: 0px !important; + margin-bottom: 0px !important; +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/AgroMetInfoConfiguration.java b/www-server/src/main/java/fr/agrometinfo/www/server/AgroMetInfoConfiguration.java index 9e95b3a..5eb7981 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/AgroMetInfoConfiguration.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/AgroMetInfoConfiguration.java @@ -67,7 +67,6 @@ public class AgroMetInfoConfiguration { * E-mail address for support. */ SUPPORT_EMAIL("support.email"); - /** * Key in config.properties. */ diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java index b9b9c20..f6232d1 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java @@ -86,7 +86,18 @@ public abstract class DaoHibernate<T> { return 0L; } } - + /** + * Delete all row in table. + */ + public void deleteAll() { + LOGGER.traceEntry(); + final ScopedEntityManager em = getScopedEntityManager(); + final Query q = em.createQuery("DELETE FROM " + clazz.getName() + " t"); + em.getTransaction().begin(); + q.executeUpdate(); + em.getTransaction().commit(); + LOGGER.traceExit(); + }; /** * Use a consumer to execute JPA operations in a transaction. * @@ -304,4 +315,16 @@ public abstract class DaoHibernate<T> { protected final ScopedEntityManager getScopedEntityManager() { return PersistenceManager.getInstance().createScopedEntityManager(); } + /** + * Save a new entity in database. + * @param object + * new entity to save + */ + protected final void save(final Object object) { + try (ScopedEntityManager em = getScopedEntityManager()) { + em.executeTransaction(() -> em.persist(object)); + } catch (final Exception e) { + LOGGER.catching(e); + } + } } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java new file mode 100644 index 0000000..e68aaf0 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java @@ -0,0 +1,32 @@ +/** + * + */ +package fr.agrometinfo.www.server.dao; + +import java.util.List; + +import fr.agrometinfo.www.server.model.Question; + +/** + * DAO for {@link Question}. + * @author jdecome + * + */ +public interface QuestionsDao { + /** + * @return all of Questions + */ + List<Question> findAll(); + /** + * Find question object by reference. + * @param questionRef question_ref + * @return Question object + */ + Question findByRef(long questionRef); + /** + * Find question object by category. + * @param category of question + * @return Question object + */ + Question findByCategory(final String category); +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java new file mode 100644 index 0000000..9369e17 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java @@ -0,0 +1,34 @@ +/** + * + */ +package fr.agrometinfo.www.server.dao; + +import java.util.List; +import java.util.Map; + +import fr.agrometinfo.www.server.model.Question; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * @author jdecome + * + */ +@ApplicationScoped +public class QuestionsDaoHibernate extends DaoHibernate<Question> implements QuestionsDao { + + public QuestionsDaoHibernate() { + super(Question.class); + } + + @Override + public Question findByRef(long ref) { + return super.find(ref); + } + + @Override + public Question findByCategory(String category) { + final String jpql = "SELECT q FROM Question q WHERE q.category = :cat"; + return super.findOneByJPQL(jpql, Map.of("cat", category), Question.class); + } + +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java new file mode 100644 index 0000000..9715217 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java @@ -0,0 +1,34 @@ +/** + * + */ +package fr.agrometinfo.www.server.dao; + +import fr.agrometinfo.www.server.model.Response; + +import java.util.List; + +/** + * DAO for {@link Response}. + * + * @author jdecome + * + */ +public interface ResponsesDao { + /** + * Find all responses in database. + * @return all responses + */ + List<Response> findAll(); + /** + * Find all responses by question. + * @param questionRef + * @return list of responses + */ + List<Response> findAllByQuestion(final long questionRef); + /** + * Get response with reference. + * @param responseRef + * @return response + */ + Response findByRef(final long responseRef); +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java new file mode 100644 index 0000000..5577d8e --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java @@ -0,0 +1,36 @@ +/** + * + */ +package fr.agrometinfo.www.server.dao; + +import java.util.List; +import java.util.Map; + +import fr.agrometinfo.www.server.model.Response; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * @author jdecome + * + */ +@ApplicationScoped +public class ResponsesDaoHibernate extends DaoHibernate<Response> implements ResponsesDao { + /** + * Constructor. + */ + public ResponsesDaoHibernate() { + super(Response.class); + } + + @Override + public List<Response> findAllByQuestion(final long questionRef) { + final String jpql = "SELECT r FROM Response r WHERE r.question.questionRef = :ref"; + return super.findAllByJPQL(jpql, Map.of("ref", questionRef), Response.class); + } + + @Override + public Response findByRef(final long responseRef) { + return super.find(responseRef); + } + +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java new file mode 100644 index 0000000..32c8a9d --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java @@ -0,0 +1,48 @@ +package fr.agrometinfo.www.server.dao; + +import java.util.List; + +import fr.agrometinfo.www.server.model.Question; +import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.UserResponses; +/** + * DAO for {@link UserResponsesDao}. + * + * @author jdecome + * + */ +public interface UserResponsesDao { + /** + * Get all user responses by question. + * @param questionRef + * @return list of user's responses + */ + List<UserResponses> findAllByQuestion(final long questionRef); + /** + * Insert response or text for specified question.<br> + * If r is provided, {@code otherText} must be null.<br> + * If otherText is provided, {@code r} must be null. + * @param q question to answer + * @param r response + * @param otherText text if response is other + */ + void insertResponse(final Question q, final Response r, final String otherText); + /** + * Insert response or text for specified question, identified by reference.<br> + * If responseRef is provided, {@code otherText} must be null.<br> + * If otherText is provided, {@code responseRef} must be null. + * @param questionRef reference of question to answer + * @param responseRef reference of response + * @param otherText text if response is other + */ + void insertResponse(final Long questionRef, final Long responseRef, final String otherText); + /** + * Get all user responses. + * @return number of responses + */ + int getNbUserResponses(); + /** + * + */ + void deleteAll(); +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java new file mode 100644 index 0000000..322dd2e --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java @@ -0,0 +1,64 @@ +/** + * + */ +package fr.agrometinfo.www.server.dao; + +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; + +import fr.agrometinfo.www.server.model.Question; +import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.UserResponses; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * @author jdecome + * + */ +@ApplicationScoped +public class UserResponsesDaoHibernate extends DaoHibernate<UserResponses> implements UserResponsesDao { + /** DAO for questions. */ + private QuestionsDao questionsDao = new QuestionsDaoHibernate(); + /** DAO for responses. */ + private ResponsesDao responsesDao = new ResponsesDaoHibernate(); + /** Default constructor. */ + public UserResponsesDaoHibernate() { + super(UserResponses.class); + } + @Override + public List<UserResponses> findAllByQuestion(final long questionRef) { + final String jpql = "SELECT u FROM UserResponses u WHERE u.question.questionRef = :ref"; + return super.findAllByJPQL(jpql, Map.of("ref", questionRef), UserResponses.class); + } + @Override + public void insertResponse(final Question q, final Response r, final String otherText) { + final UserResponses ur = new UserResponses(); + ur.setDateTime(Timestamp.valueOf(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()))); + ur.setQuestion(q); + ur.setResponse(r); + ur.setOtherText(otherText); + + this.save(ur); + + } + @Override + public void insertResponse(final Long questionRef, final Long responseRef, final String otherText) { + // recherche de la question + final Question q = questionsDao.findByRef(questionRef); + if (q != null) { + if (responseRef != null) { // insertion d'une réponse prédéfinie, on recherche de la réponse + final Response r = responsesDao.findByRef(responseRef); + this.insertResponse(q, r, null); + } else { // insertion d'une réponse libre + this.insertResponse(q, null, otherText); + } + } + } + @Override + public int getNbUserResponses() { + return super.findAll().size(); + } +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/LoginFormData.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/LoginFormData.java new file mode 100644 index 0000000..236fbe4 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/LoginFormData.java @@ -0,0 +1,50 @@ +/** + * + */ +package fr.agrometinfo.www.server.model; + +import java.util.HashMap; +import java.util.List; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +/** + * Class contains all data of login form. + * @author jdecome + * + */ +@Deprecated +public class LoginFormData { + /** + * List of login form questions.<br> + * This list questions contains available questions, obtained by {@link QuestionsDao} + */ + @Getter + @Setter + private List<Question> questions; + /** + * List of login form responses.<br> + * This list responses contains available responses, obtained by {@link ResponsesDao} + */ + @Getter + @Setter + private List<Response> responses; + /** + * Storage, for each response, the other text, if specified. + */ + @Getter + private HashMap<Long, String> otherTextMap = new HashMap<>(); + /** + * Constructor. + * @param qList questions list + * @param rList responses list + * @param otherText otherText map + */ + public LoginFormData(final List<Question> qList, final List<Response> rList, HashMap<Long, String> otherText) { + this.questions = qList; + this.responses = rList; + this.otherTextMap = otherText; + } +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java new file mode 100644 index 0000000..0d2537a --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java @@ -0,0 +1,38 @@ +/** + * + */ +package fr.agrometinfo.www.server.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; + +/** + * Questions for survey login modal. + * @author jdecome + * + */ +@Data +@Entity +@Table(name = "questions") +public class Question { + /** PK. */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "question_ref") + private long questionRef; + /** + * Catogory of question. + */ + @Column(name = "category") + private String category; + /** + * Label of question. + */ + @Column(name = "fullname") + private String fullName; +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java new file mode 100644 index 0000000..7f3c123 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java @@ -0,0 +1,45 @@ +/** + * + */ +package fr.agrometinfo.www.server.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import lombok.Data; + +/** + * Available response. + * @author jdecome + * + */ +@Data +@Entity +@Table(name = "responses") +public class Response { + /** + * Reference of response. + */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "response_ref") + private long responseRef; + /** + * Question related to response. + */ + @OneToOne + @JoinColumn(name = "question_ref") + private Question question; + /** + * Label of the response. + */ + @Column(name = "fullname") + private String fullname; +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java new file mode 100644 index 0000000..e4d6e50 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java @@ -0,0 +1,56 @@ +/** + * + */ +package fr.agrometinfo.www.server.model; + +import java.sql.Timestamp; +import java.util.List; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import lombok.Data; + +/** + * User's responses values. + * @author jdecome + * + */ +@Data +@Entity +@Table(name = "user2responses") +public class UserResponses { + /** Primary key. */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_response_ref") + private long userResponseRef; + /** Date time of user responses. */ + @Column(name = "datetime") + private Timestamp dateTime; + /** Related question. */ + @OneToOne + @JoinColumn(name = "question_ref") + private Question question; + /** + * Related response.<br> + * Can be null if it's a other response. + */ + @OneToOne + @JoinColumn(name = "response_ref") + private Response response; + /** + * Other text response.<br> + * Can be null if it's a related response. + */ + @Column(name = "other_text") + private String otherText; +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java index 26fef07..60623c8 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java @@ -39,11 +39,11 @@ public class ApplicationConfig extends Application { public final Set<Class<?>> getClasses() { return Set.of( // OpenAPI / Swagger - OpenApiResource.class, AcceptHeaderOpenApiResource.class, + AcceptHeaderOpenApiResource.class, OpenApiResource.class, // Jackson configuration JacksonConfig.class, // JAX-RS resources - ApplicationResource.class, GeometryResource.class, IndicatorResource.class, UserResource.class, + ApplicationResource.class, GeometryResource.class, IndicatorResource.class, LoginFormResource.class, UserResource.class, // POJO // Dependencies of resources LogFilter.class diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java new file mode 100644 index 0000000..432c54c --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java @@ -0,0 +1,240 @@ +/** + * + */ +package fr.agrometinfo.www.server.rs; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import fr.agrometinfo.www.server.dao.QuestionsDao; +import fr.agrometinfo.www.server.dao.ResponsesDao; +import fr.agrometinfo.www.server.dao.UserResponsesDao; +import fr.agrometinfo.www.server.model.Question; +import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.service.MailService; +import fr.agrometinfo.www.server.service.MailServiceImpl; +import fr.agrometinfo.www.shared.dto.ErrorResponseDTO; +import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; +import fr.agrometinfo.www.shared.dto.QuestionDTO; +import fr.agrometinfo.www.shared.dto.ResponseDTO; +import fr.agrometinfo.www.shared.service.LoginFormService; +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import lombok.extern.log4j.Log4j2; + +/** + * @author jdecome + * + */ +@Log4j2 +@Path(LoginFormService.PATH) +@RequestScoped +public class LoginFormResource implements LoginFormService { + /** + * Convert {@link Question} entity to dto. + * @param question entity + * @return dto + */ + public static QuestionDTO toDto(final Question question) { + final QuestionDTO dto = new QuestionDTO(); + dto.setQuestionRef(question.getQuestionRef()); + dto.setCategory(question.getCategory()); + dto.setFullName(question.getFullName()); + return dto; + } + /** + * Convert {@link Response} entity to dto. + * @param response entity + * @return dto + */ + public static ResponseDTO toDto(final Response response) { + final ResponseDTO dto = new ResponseDTO(); + dto.setResponseRef(response.getResponseRef()); + dto.setQuestion(toDto(response.getQuestion())); + dto.setFullname(response.getFullname()); + return dto; + } + /** + * Convert {@link QuestionDTO} dto to entity. + * @param dto question + * @return entity + */ + private static Question toEntity(final QuestionDTO dto) { + final Question question = new Question(); + question.setQuestionRef(dto.getQuestionRef()); + question.setCategory(dto.getCategory()); + question.setFullName(dto.getFullName()); + return question; + } + /** + * Convert {@link ResponseDTO} dto to entity. + * @param dto response + * @return entity + */ + private static Response toEntity(final ResponseDTO dto) { + final Response response = new Response(); + response.setResponseRef(dto.getResponseRef()); + response.setQuestion(toEntity(dto.getQuestion())); + response.setFullname(dto.getFullname()); + return response; + } + /** + * DAO for questions ({@link QuestionsDao}). + */ + @Inject + private QuestionsDao questionsDao; + /** + * DAO for responses ({@link ResponsesDao}). + */ + @Inject + private ResponsesDao responsesDao; + /** + * DAO for user responses ({@link UserResponsesDao} + */ + @Inject + private UserResponsesDao userResponsesDao; + /** + * Mail service. + */ + @Inject + private MailService mailService; + /** + * Ensure the value of query parameter is not null and not blanck. + * @param value value of query parameter to check + * @param queryParamName name of query parameter + * @throws WebApplicationException if validation failed + */ + private void checkRequired(final Object value, final String queryParamName) { + if (value instanceof final String str && str.isBlank() || value == null) { + final jakarta.ws.rs.core.Response.Status badRequest = jakarta.ws.rs.core.Response.Status.BAD_REQUEST; + throw new WebApplicationException( + jakarta.ws.rs.core.Response.status(badRequest).entity(ErrorResponseDTO.of( + badRequest.getStatusCode(), + badRequest.getReasonPhrase(), + queryParamName + " parameter is mandatory") + ).build()); + } + } + @GET + @Path(LoginFormService.PATH_QUESTIONS_LIST) + @Produces(MediaType.APPLICATION_JSON) + @Override + public List<QuestionDTO> getQuestions() { + final List<Question> list = questionsDao.findAll(); + final List<QuestionDTO> questions = new ArrayList<>(); + for (Question q : list) { + questions.add(toDto(q)); + } + return questions; + } + @GET + @Path(LoginFormService.PATH_QUESTION_BY_CATEGORY) + @Produces(MediaType.APPLICATION_JSON) + @Override + public QuestionDTO getQuestionByCategory(@QueryParam(value = "category") final String category) { + this.checkRequired(category, "category"); + final Question question = questionsDao.findByCategory(category); + return toDto(question); + } + @GET + @Path(LoginFormService.PATH_RESPONSES_BY_QUESTION_LIST) + @Produces(MediaType.APPLICATION_JSON) + @Override + public List<ResponseDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") final Long questionRef) { + this.checkRequired(questionRef, "questionRef"); + if (this.checkIfQuestionExist(questionRef)) { + final List<Response> list = responsesDao.findAllByQuestion(questionRef); + final List<ResponseDTO> responses = new ArrayList<>(); + for (final Response r : list) { + responses.add(toDto(r)); + } + return responses; + } + return null; + + } + @GET + @Path(LoginFormService.PATH_RESPONSES_LIST) + @Produces(MediaType.APPLICATION_JSON) + @Override + public List<ResponseDTO> getResponses() { + final List<Response> list = responsesDao.findAll(); + final List<ResponseDTO> responses = new ArrayList<>(); + for (final Response r : list) { + responses.add(toDto(r)); + } + return responses; + } + @POST + @Path(LoginFormService.PATH_INSERT_RESPONSE) + @Produces(MediaType.TEXT_PLAIN) + @Override + public void insertResponse( + @FormParam(value = "questionRef") final Long questionRef, + @FormParam(value = "responseRef") final String responseRef, + @FormParam(value = "otherText") final String otherText) { + this.checkRequired(questionRef, "questionRef"); + final boolean responseRefIsNull = responseRef == null || responseRef.equals("null"); + final boolean otherTextIsNull = otherText == null || otherText.equals("null"); + if (this.checkIfQuestionExist(questionRef)) { + if (!responseRefIsNull && otherTextIsNull) { // réponse prédéfinie + this.userResponsesDao.insertResponse(questionRef, Long.valueOf(responseRef), null); + } else if(responseRefIsNull && !otherTextIsNull) { // réponse libre + this.userResponsesDao.insertResponse(questionRef, null, otherText); + } else { + // Do nothing + } + } + } + + private boolean checkIfQuestionExist(final Long questionRef) { + if (questionRef != null) { + // on cherche dans le DAO + final Question q = questionsDao.findByRef(questionRef); + return (q != null); + } + return false; + } + @POST + @Path(LoginFormService.PATH_INSERT_RESPONSE_WITH_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Override + public String insertAllResponses(final LoginFormDataDTO data) { + // traitement des réponses prédéfinies + for (final QuestionDTO dto : data.getQuestions()) { // Pour chaque question répondue + // Insérer les réponses associés + final Question q = toEntity(dto); + final Long qRef = dto.getQuestionRef(); + List<ResponseDTO> associatedResponses = data.getResponses().stream().filter(f -> f.getQuestion().getQuestionRef() == qRef).collect(Collectors.toList()); + // On insère les réponses prédéfinies + for (final ResponseDTO rDto : associatedResponses) { + final Response r = toEntity(rDto); + this.userResponsesDao.insertResponse(q, r, null); + } + + // Si il existe une réponse libre, l'insérer + if (data.getOtherTextMap().containsKey(dto.getQuestionRef()) + && data.getOtherTextMap().get(dto.getQuestionRef()) != null) { + this.userResponsesDao.insertResponse(q, null, data.getOtherTextMap().get(q.getQuestionRef())); + } + } + + // une fois que tout est inséré, on envoi un mail au support + this.mailService.sendLoginFilled(data); + return "0"; + } +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java index f3f025a..c2524f0 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java @@ -1,319 +1,23 @@ package fr.agrometinfo.www.server.service; -import java.io.Serializable; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.StringJoiner; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Filter; -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.AbstractAppender; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.layout.PatternLayout; - -import fr.agrometinfo.www.server.AgroMetInfoConfiguration; -import fr.agrometinfo.www.server.AgroMetInfoConfiguration.ConfigurationKey; -import fr.agrometinfo.www.server.exception.AgroMetInfoErrorCategory; import fr.agrometinfo.www.server.exception.AgroMetInfoException; -import fr.agrometinfo.www.server.exception.ErrorCategory; -import fr.agrometinfo.www.server.exception.ErrorType; -import jakarta.annotation.PostConstruct; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.mail.Address; -import jakarta.mail.Authenticator; -import jakarta.mail.Message; -import jakarta.mail.MessagingException; -import jakarta.mail.PasswordAuthentication; -import jakarta.mail.SendFailedException; -import jakarta.mail.Session; -import jakarta.mail.Transport; -import jakarta.mail.internet.InternetAddress; -import jakarta.mail.internet.MimeMessage; -import lombok.Data; -import lombok.Getter; -import lombok.extern.log4j.Log4j2; - -/** - * Service to send e-mails. - * - * @author Olivier Maury - */ -@ApplicationScoped -@Log4j2 -public class MailService { - - /** - * Text message. - */ - @Data - public static class Mail { - /** - * Body. - */ - private String content; - /** - * Sender's e-mail address. - */ - private String fromAddress; - /** - * Subject. - */ - private String subject; - /** - * Recipients' e-mail addresses. - */ - private List<String> toAddresses; - } +import fr.agrometinfo.www.server.service.MailServiceImpl.Mail; +import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; +public interface MailService { /** - * Log4j2 appender to send error logs by e-mail. + * Sending e-mail. + * @param mail object to send + * @throws AgroMetInfoException */ - private class MailAppender extends AbstractAppender { - /** - * Logger name. - */ - private static final String NAME = "MailAppender"; - - /** - * Constructor. - * - * @param filter The Filter to associate with the Appender. - * @param layout The layout to use to format the event. - * @param ignoreExceptions If true, exceptions will be logged and suppressed. If - * false errors will be logged and then passed to the - * application. - */ - MailAppender(final Filter filter, final Layout<? extends Serializable> layout, final boolean ignoreExceptions) { - super(NAME, filter, layout, ignoreExceptions, null); - - } - - @Override - public void append(final LogEvent event) { - final Mail mail = new Mail(); - mail.setSubject("error log"); - mail.setContent(super.toSerializable(event).toString()); - mail.setToAddresses(List.of(configuration.get(ConfigurationKey.LOG_EMAIL))); - try { - send(mail); - } catch (final AgroMetInfoException e) { - // do nothing - LOGGER.info("Cannot send email: {}", e.getMessage()); - } - } - } - + void send(Mail mail) throws AgroMetInfoException; /** - * Keys from messages.properties used to warn about errors. + * Send mail when application started. */ - public enum MailErrorType implements ErrorType { - /** - * Cannot get message details. - */ - DETAILS("01"), - /** - * Generic exception. - */ - SEND_FAILED("02"), - /** - * Some e-mail addresses are not valid. - */ - SEND_FAILED_INVALID("03"), - /** - * Some messages failed to be sent to valid e-mail addresses. - */ - SEND_FAILED_VALID("04"); - - /** - * Subcode for the error. - */ - @Getter - private final String subCode; - - /** - * Constructor. - * - * @param c Subcode for the error. - */ - MailErrorType(final String c) { - this.subCode = c; - } - - @Override - public ErrorCategory getCategory() { - return AgroMetInfoErrorCategory.MAIL; - } - - @Override - public String getName() { - return name(); - } - - } - - /** - * Application configuration. - */ - @Inject - private AgroMetInfoConfiguration configuration; - - /** - * Session created from parameters in context.xml on Tomcat. - */ - private Session session; - - /** - * Initialization of session and log appender. - */ - @PostConstruct - public void init() { - final Properties props = new Properties(); - props.put("mail.smtp.auth", "true"); - props.put("mail.smtp.host", configuration.get(ConfigurationKey.SMTP_HOST)); - props.put("mail.smtp.port", configuration.get(ConfigurationKey.SMTP_PORT)); - final Authenticator authenticator = new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(configuration.get(ConfigurationKey.SMTP_USER), - configuration.get(ConfigurationKey.SMTP_PASSWORD)); - } - }; - session = Session.getInstance(props, authenticator); - // Send e-mails for ERROR level messages - final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); - final Configuration config = ctx.getConfiguration(); - final String pattern = """ - date : %d - level : %-5p - class : %c#%M() - line : %L - msg : %m - throwable : %throwable - """; - final PatternLayout layout = PatternLayout.newBuilder() // - .withConfiguration(config) // - .withPattern(pattern).build(); - final Appender appender = new MailAppender(null, layout, true); - appender.start(); - config.addAppender(appender); - final LoggerConfig loggerConfig = LoggerConfig.newBuilder() // - .withAdditivity(false) // - .withConfig(config) // - .withLevel(Level.ERROR) // - .withLoggerName(MailAppender.NAME) // - .build(); - loggerConfig.addAppender(appender, null, null); - config.addLogger("fr.agrometinfo", loggerConfig); - ctx.updateLoggers(); - } - - /** - * @param mail text message to send - * @throws AgroMetInfoException exception - */ - public void send(final Mail mail) throws AgroMetInfoException { - send(toMessage(mail)); - } - - /** - * @param message jakarta message to send - * @throws AgroMetInfoException exception - */ - private void send(final Message message) throws AgroMetInfoException { - final String subject; - final String recipients; - try { - subject = message.getSubject(); - recipients = toString(message.getAllRecipients()); - } catch (final MessagingException e) { - throw new AgroMetInfoException(MailErrorType.DETAILS, e.getMessage()); - } - try { - Transport.send(message); - } catch (final MessagingException e) { - if (e instanceof final SendFailedException sfe) { - final Address[] invalid = sfe.getInvalidAddresses(); - if (invalid != null) { - throw new AgroMetInfoException(MailErrorType.SEND_FAILED_INVALID, subject, toString(invalid)); - } - final Address[] validUnsent = sfe.getValidUnsentAddresses(); - if (validUnsent != null) { - throw new AgroMetInfoException(MailErrorType.SEND_FAILED_VALID, subject, toString(validUnsent)); - } - } - throw new AgroMetInfoException(MailErrorType.SEND_FAILED, subject, recipients, e.getMessage()); - } - } - - /** - * Send an e-mail to log e-mail address at application start. - */ - public void sendApplicationStarted() { - final Mail mail = new Mail(); - mail.setContent("Démarrage de AgroMetInfo-www : " + LocalDateTime.now()); - mail.setFromAddress(configuration.get(ConfigurationKey.APP_EMAIL)); - mail.setSubject("Démarrage"); - mail.setToAddresses(List.of(configuration.get(ConfigurationKey.LOG_EMAIL))); - try { - send(mail); - } catch (final AgroMetInfoException e) { - LOGGER.info("failed to send e-mail : {}", e); - } - } - - /** - * @param mail text message to convert - * @return jakarta converted message - * @throws AgroMetInfoException exception - */ - private Message toMessage(final Mail mail) throws AgroMetInfoException { - final String environment = configuration.get(ConfigurationKey.ENVIRONMENT); - try { - final Message message = new MimeMessage(session); - if (mail.getFromAddress() == null) { - mail.setFromAddress(configuration.get(ConfigurationKey.APP_EMAIL)); - } - message.setFrom(new InternetAddress(mail.getFromAddress())); - final List<InternetAddress> to = new ArrayList<>(); - if (mail.getToAddresses() == null || mail.getToAddresses().isEmpty()) { - mail.setToAddresses(List.of(configuration.get(ConfigurationKey.SUPPORT_EMAIL))); - } - for (final String addr : mail.getToAddresses()) { - to.add(new InternetAddress(addr)); - } - message.setRecipients(Message.RecipientType.TO, to.toArray(InternetAddress[]::new)); - if ("prod".equals(environment)) { - message.setSubject("AgroMetInfo : " + mail.getSubject()); - } else { - message.setSubject("AgroMetInfo " + environment + " : " + mail.getSubject()); - } - final String content = mail.getContent() + "\n-- \n" + configuration.get(ConfigurationKey.APP_URL); - message.setContent(content, "text/plain; charset=UTF-8"); - message.setHeader("X-Environment", environment); - return message; - } catch (final MessagingException e) { - throw new AgroMetInfoException(MailErrorType.DETAILS, e.getLocalizedMessage()); - } - } - + void sendApplicationStarted(); /** - * @param addresses e-mail addresses - * @return string representation of addresses + * Send mail when user fill login form, with questions and responses. + * @param data */ - private String toString(final Address[] addresses) { - final StringJoiner sj = new StringJoiner(", "); - for (final Address addr : addresses) { - sj.add(addr.toString()); - } - return sj.toString(); - } + void sendLoginFilled(LoginFormDataDTO data); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java new file mode 100644 index 0000000..e752839 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java @@ -0,0 +1,361 @@ +package fr.agrometinfo.www.server.service; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.StringJoiner; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.layout.PatternLayout; + +import fr.agrometinfo.www.server.AgroMetInfoConfiguration; +import fr.agrometinfo.www.server.AgroMetInfoConfiguration.ConfigurationKey; +import fr.agrometinfo.www.server.exception.AgroMetInfoErrorCategory; +import fr.agrometinfo.www.server.exception.AgroMetInfoException; +import fr.agrometinfo.www.server.exception.ErrorCategory; +import fr.agrometinfo.www.server.exception.ErrorType; +import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; +import jakarta.annotation.PostConstruct; +import jakarta.mail.Address; +import jakarta.mail.Authenticator; +import jakarta.mail.Message; +import jakarta.mail.MessagingException; +import jakarta.mail.PasswordAuthentication; +import jakarta.mail.SendFailedException; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; +import lombok.Data; +import lombok.Getter; +import lombok.extern.log4j.Log4j2; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +/** + * Service to send e-mails. + * + * @author Olivier Maury + */ +@ApplicationScoped +@Log4j2 +public class MailServiceImpl implements MailService { + + /** + * Text message. + */ + @Data + public static class Mail { + /** + * Body. + */ + private String content; + /** + * Sender's e-mail address. + */ + private String fromAddress; + /** + * Subject. + */ + private String subject; + /** + * Recipients' e-mail addresses. + */ + private List<String> toAddresses; + } + + /** + * Log4j2 appender to send error logs by e-mail. + */ + private class MailAppender extends AbstractAppender { + /** + * Logger name. + */ + private static final String NAME = "MailAppender"; + + /** + * Constructor. + * + * @param filter The Filter to associate with the Appender. + * @param layout The layout to use to format the event. + * @param ignoreExceptions If true, exceptions will be logged and suppressed. If + * false errors will be logged and then passed to the + * application. + */ + MailAppender(final Filter filter, final Layout<? extends Serializable> layout, final boolean ignoreExceptions) { + super(NAME, filter, layout, ignoreExceptions, null); + + } + + @Override + public void append(final LogEvent event) { + Mail mail = new Mail(); + mail.setFromAddress("agrometinfo@inrae.fr"); + mail.setSubject("AgroMetInfo - error log"); + mail.setContent(super.toSerializable(event).toString()); + mail.setToAddresses(List.of(configuration.get(ConfigurationKey.LOG_EMAIL))); + try { + send(mail); + } catch (AgroMetInfoException e) { + // do nothing + LOGGER.info("Cannot send email: {}", e.getMessage()); + } + } + } + + /** + * Keys from messages.properties used to warn about errors. + */ + public enum MailErrorType implements ErrorType { + /** + * Cannot get message details. + */ + DETAILS("01"), + /** + * Generic exception. + */ + SEND_FAILED("02"), + /** + * Some e-mail addresses are not valid. + */ + SEND_FAILED_INVALID("03"), + /** + * Some messages failed to be sent to valid e-mail addresses. + */ + SEND_FAILED_VALID("04"); + + /** + * Subcode for the error. + */ + @Getter + private final String subCode; + + /** + * Constructor. + * + * @param c Subcode for the error. + */ + MailErrorType(final String c) { + this.subCode = c; + } + + @Override + public ErrorCategory getCategory() { + return AgroMetInfoErrorCategory.MAIL; + } + + @Override + public String getName() { + return name(); + } + + } + + /** + * Application configuration. + */ + @Inject + private AgroMetInfoConfiguration configuration; + + /** + * Session created from parameters in context.xml on Tomcat. + */ + private Session session; + + /** + * Initialization of session and log appender. + */ + @PostConstruct + public void init() { + Properties props = new Properties(); + props.put("mail.smtp.auth", "true"); + props.put("mail.smtp.host", configuration.get(ConfigurationKey.SMTP_HOST)); + props.put("mail.smtp.port", configuration.get(ConfigurationKey.SMTP_PORT)); + final Authenticator authenticator = new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(configuration.get(ConfigurationKey.SMTP_USER), + configuration.get(ConfigurationKey.SMTP_PASSWORD)); + } + }; + session = Session.getInstance(props, authenticator); + // Send e-mails for ERROR level messages + final LoggerContext ctx = (LoggerContext) LogManager.getContext(false); + final Configuration config = ctx.getConfiguration(); + final String pattern = """ + date : %d + level : %-5p + class : %c#%M() + line : %L + msg : %m + throwable : %throwable + """; + final PatternLayout layout = PatternLayout.newBuilder() // + .withConfiguration(config) // + .withPattern(pattern).build(); + final Appender appender = new MailAppender(null, layout, true); + appender.start(); + config.addAppender(appender); + LoggerConfig loggerConfig = LoggerConfig.newBuilder() // + .withAdditivity(false) // + .withConfig(config) // + .withLevel(Level.ERROR) // + .withLoggerName(MailAppender.NAME) // + .build(); + loggerConfig.addAppender(appender, null, null); + config.addLogger("fr.agrometinfo", loggerConfig); + ctx.updateLoggers(); + } + + /** + * @param mail text message to send + * @throws AgroMetInfoException exception + */ + public void send(final Mail mail) throws AgroMetInfoException { + send(toMessage(mail)); + } + + /** + * @param message jakarta message to send + * @throws AgroMetInfoException exception + */ + private void send(final Message message) throws AgroMetInfoException { + final String subject; + final String recipients; + try { + subject = message.getSubject(); + recipients = toString(message.getAllRecipients()); + } catch (MessagingException e) { + throw new AgroMetInfoException(MailErrorType.DETAILS, e.getMessage()); + } + try { + Transport.send(message); + } catch (MessagingException e) { + if (e instanceof SendFailedException sfe) { + final Address[] invalid = sfe.getInvalidAddresses(); + if (invalid != null) { + throw new AgroMetInfoException(MailErrorType.SEND_FAILED_INVALID, subject, toString(invalid)); + } + final Address[] validUnsent = sfe.getValidUnsentAddresses(); + if (validUnsent != null) { + throw new AgroMetInfoException(MailErrorType.SEND_FAILED_VALID, subject, toString(validUnsent)); + } + } + throw new AgroMetInfoException(MailErrorType.SEND_FAILED, subject, recipients, e.getMessage()); + } + } + + /** + * @param mail text message to convert + * @return jakarta converted message + * @throws AgroMetInfoException exception + */ + private Message toMessage(final Mail mail) throws AgroMetInfoException { + final String environment = configuration.get(ConfigurationKey.ENVIRONMENT); + try { + final Message message = new MimeMessage(session); + if (mail.getFromAddress() == null) { + mail.setFromAddress(configuration.get(ConfigurationKey.APP_EMAIL)); + } + message.setFrom(new InternetAddress(mail.getFromAddress())); + List<InternetAddress> to = new ArrayList<>(); + if (mail.getToAddresses() == null || mail.getToAddresses().isEmpty()) { + mail.setToAddresses(List.of(configuration.get(ConfigurationKey.SUPPORT_EMAIL))); + } + for (String addr : mail.getToAddresses()) { + to.add(new InternetAddress(addr)); + } + message.setRecipients(Message.RecipientType.TO, to.toArray(InternetAddress[]::new)); + if ("prod".equals(environment)) { + message.setSubject("AgroMetInfo : " + mail.getSubject()); + } else { + message.setSubject("AgroMetInfo " + environment + " : " + mail.getSubject()); + } + final String content = mail.getContent() + "\n-- \n" + configuration.get(ConfigurationKey.APP_URL); + message.setContent(content, "text/plain; charset=UTF-8"); + message.setHeader("X-Environment", environment); + return message; + } catch (MessagingException e) { + throw new AgroMetInfoException(MailErrorType.DETAILS, e.getLocalizedMessage()); + } + } + + /** + * @param addresses e-mail addresses + * @return string representation of addresses + */ + private String toString(final Address[] addresses) { + final StringJoiner sj = new StringJoiner(", "); + for (Address addr : addresses) { + sj.add(addr.toString()); + } + return sj.toString(); + } + + /** + * Send an e-mail to log e-mail address at application start. + */ + public void sendApplicationStarted() { + if (configuration.get(ConfigurationKey.ENVIRONMENT).equals("dev")) { + LOGGER.trace("Environment is dev, e-mail isn't send"); + return; + } + Mail mail = new Mail(); + mail.setContent("Démarrage de AgroMetInfo-www : " + LocalDateTime.now() + "\n-- \n" + + configuration.get(ConfigurationKey.APP_URL)); + mail.setFromAddress(configuration.get(ConfigurationKey.APP_EMAIL)); + mail.setSubject("Démarrage"); + mail.setToAddresses(List.of(configuration.get(ConfigurationKey.LOG_EMAIL))); + try { + send(mail); + } catch (AgroMetInfoException e) { + LOGGER.info("failed to send e-mail : {}", e); + } + } + public void sendLoginFilled(final LoginFormDataDTO data) { + final Mail mail = createContentFromData(data); + mail.setSubject("Un utilisateur a rempli le formulaire d'enquête"); + mail.setFromAddress(configuration.get(ConfigurationKey.APP_EMAIL)); + mail.setToAddresses(List.of(configuration.get(ConfigurationKey.LOG_EMAIL))); + try { + send(mail); + } catch (AgroMetInfoException e) { + // en cas d'erreur, on ne fait rien de plus. + LOGGER.trace("failed to send e-mail"); + } + + }//*/ + public static Mail createContentFromData(final LoginFormDataDTO data) { + final Mail mail = new Mail(); + + final StringBuilder builder = new StringBuilder(); + builder.append("Bonjour,\nUn utilisateur vient de remplir le formulaire d'enquête d'AgroMetInfo à l'instant.\n\n"); + builder.append("Il a répondu à " + data.getQuestions().size() + " question(s) :\n"); + + data.getQuestions().forEach((q) -> { + builder.append("\t• « " + q.getFullName() + " » :\n"); + data.getResponses().stream().filter(f -> f.getQuestion().getQuestionRef() == q.getQuestionRef()) + .collect(Collectors.toList()) + .forEach((r) -> builder.append("\t\t- " + r.getFullname() + "\n")); + + if (data.getOtherTextMap().containsKey(q.getQuestionRef()) && data.getOtherTextMap().get(q.getQuestionRef()) != null) { + builder.append("\t\t- Réponse libre : « " + data.getOtherTextMap().get(q.getQuestionRef()) + " »\n"); + } + builder.append("\n"); + }); + mail.setContent(builder.toString()); + return mail; + } +} diff --git a/www-server/src/main/webapp/index.html b/www-server/src/main/webapp/index.html index 5498ba6..bbf735a 100644 --- a/www-server/src/main/webapp/index.html +++ b/www-server/src/main/webapp/index.html @@ -24,11 +24,11 @@ <!-- --> <!-- Consider inlining CSS to reduce the number of requested files --> <!-- --> - <link type="text/css" rel="stylesheet" href="app/style.css"> <link type="text/css" rel="stylesheet" href="app/vendors/ol/ol.css"> <link type="text/css" rel="stylesheet" href="app/vendors/ol/ol-layerswitcher.css"> <link type="text/css" rel="stylesheet" href="app/css/domino-ui.css"> <link type="text/css" rel="stylesheet" href="app/css/themes/all-themes.min.css"> + <link type="text/css" rel="stylesheet" href="app/style.css"> <!-- --> <!-- Any title is fine --> diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java new file mode 100644 index 0000000..eba1d30 --- /dev/null +++ b/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java @@ -0,0 +1,192 @@ +/** + * + */ +package fr.agrometinfo.www.server; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +import org.junit.jupiter.api.Test; + +import fr.agrometinfo.www.server.dao.QuestionsDao; +import fr.agrometinfo.www.server.dao.QuestionsDaoHibernate; +import fr.agrometinfo.www.server.dao.ResponsesDao; +import fr.agrometinfo.www.server.dao.ResponsesDaoHibernate; +import fr.agrometinfo.www.server.dao.UserResponsesDao; +import fr.agrometinfo.www.server.dao.UserResponsesDaoHibernate; +import fr.agrometinfo.www.server.model.Question; +import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.UserResponses; + +/** + * Test of UserResponsesDaoHibernate. + * @author jdecome + * + */ +public class LoginFormHibernateTest { + /** DAO for user's responses. */ + private UserResponsesDao userResponsesDao = new UserResponsesDaoHibernate(); + /** DAO for questions. */ + private QuestionsDao questionsDao = new QuestionsDaoHibernate(); + /** DAO for responses. */ + private ResponsesDao responsesDao = new ResponsesDaoHibernate(); + + @Test + public void getQuestion() { + final List<Question> list = questionsDao.findAll(); + assertNotEquals(list.size(), 0, "La liste de questions est vide"); + for (final Question q : list) { + // recherche de la question par sa référence + final Question foundedByRef = questionsDao.findByRef(q.getQuestionRef()); + assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getQuestionRef() + " est null"); + assertEquals(foundedByRef, q, "L'objet correspondant à la question " + q.getQuestionRef() + " ne correspond pas"); + + // recherche de la question par sa catégorie + final Question foundedByCategory = questionsDao.findByCategory(q.getCategory()); + assertNotNull(foundedByCategory, "La question correspondante à la catégorie « " + q.getCategory() + " » est null"); + assertEquals(foundedByCategory, q, "La question correspondante à la catégorie « " + q.getCategory() + " » est vide"); + } + } + + @Test + public void getResponses() { + final List<Question> questions = questionsDao.findAll(); + final List<Response> responses = responsesDao.findAll(); + assertNotEquals(responses.size(), 0, "La liste de réponses est vide"); + for (final Response r : responses) { + assertTrue(questions.contains(r.getQuestion()), "La liste de questions ne contient pas la question " + r.getQuestion().getQuestionRef()); + + // Test à partir de la question correspondante à la réponse + final Question q = r.getQuestion(); + assertNotNull(q, "La question correspondante à la réponse " + r.getResponseRef() + " est null"); + + final Question foundedByRef = questionsDao.findByRef(q.getQuestionRef()); + assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getQuestionRef() + " est null"); + assertEquals(foundedByRef, r.getQuestion(), "L'objet correspondant à la question " + q.getQuestionRef() + " ne correspond pas"); + + final Question foundedByCategory = questionsDao.findByCategory(q.getCategory()); + assertNotNull(foundedByCategory, "La question correspondante à la catégorie « " + q.getCategory() + " » est null"); + assertEquals(foundedByCategory, q, "La question correspondante à la catégorie « " + q.getCategory() + " » est vide"); + + // recherche de la réponse par sa référence + final Response responseByRef = responsesDao.findByRef(r.getResponseRef()); + assertNotNull(responseByRef, "La réponse correspondante à la réponse " + r.getResponseRef() + " est null"); + assertEquals(responseByRef, r, "La réponse correspondante à la réponse " + r.getResponseRef() + " est vide"); + } + } + + @Test + public void setUserResponses() { + final Question profession = questionsDao.findByCategory("profession"); + assertNotNull(profession, "Aucune question ne correspond à la catégorie « profession »"); + List<Response> responses = responsesDao.findAllByQuestion(profession.getQuestionRef()); + assertNotNull(responses, "Aucune réponse ne correspond à la catégorie « profession »"); + assertNotEquals(responses.size(), 0, "La liste de réponses pour la catégorie « profession » est vide"); + for (final Response r : responses) { + assertEquals(r.getQuestion(), profession, "La question de la réponse ne correspond pas avec la question d'origine"); + } + + // Insertion d'une réponse + final List<Response> listOfResponses = new ArrayList<>(); // liste des réponses insérées + Response r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); + userResponsesDao.insertResponse(profession, r, null); + listOfResponses.add(r); + + List<UserResponses> list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); + assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur doit contenir un élément"); + assertEquals(list.get(0).getQuestion(), profession, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); + assertEquals(list.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); + assertNull(list.get(0).getOtherText(), "Le texte libre doit être null"); + + // Insertion de plusieurs réponses + final int nbToInsert = 3; + for (final Response res : pickNRandom(responses, nbToInsert)) { + userResponsesDao.insertResponse(profession, res, null); + listOfResponses.add(res); + } + list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); + assertEquals(list.size(), (1 + nbToInsert), "La liste de réponses de l'utilisateur doit contenir la réponse précédente + " + nbToInsert + " réponses supplémentaires"); + for (final UserResponses ur : list) { + assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question"); + assertTrue(listOfResponses.contains(ur.getResponse()), "La réponse contenue dans la réponse de l'utilisateur n'est pas dans la liste des réponses insérées"); + assertEquals(ur.getResponse().getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); + assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); + } + + final int newNbResponses = 1 + nbToInsert; + + // Insertion d'une réponse à choix libre + String other = "Ceci est une réponse libre"; + userResponsesDao.insertResponse(profession, null, other); + + list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); + assertEquals(list.size(), (newNbResponses + 1), "La liste de réponses de l'utilisateur doit contenir les " + newNbResponses + " + la réponse libre"); + for (final UserResponses ur : list) { + assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); + if (ur.getOtherText() != null) { // on est sur une réponse libre + assertNull(ur.getResponse(), "L'objet response doit être null si il s'agit d'une réponse libre"); + assertEquals(ur.getOtherText(), other, "Le texte ne correspond pas à ce qui a été inséré en base"); + } else { + assertEquals(ur.getResponse().getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); + assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); + } + } + + // Essai de l'insertion par les références, avec une autre question + final Question useCase = questionsDao.findByCategory("useCase"); + assertNotNull(useCase, "Aucune question ne correspond à la catégorie « useCase »"); + responses = responsesDao.findAllByQuestion(useCase.getQuestionRef()); + assertNotNull(responses, "Aucune réponse ne correspond à la catégorie « useCase »"); + assertNotEquals(responses.size(), 0, "La liste de réponses pour la catégorie « useCase » est vide"); + + r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); + userResponsesDao.insertResponse(useCase.getQuestionRef(), r.getResponseRef(), null); + + list = userResponsesDao.findAllByQuestion(useCase.getQuestionRef()); + assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur pour la question « useCase » doit contenir un élément"); + assertEquals(list.get(0).getQuestion(), useCase, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); + assertEquals(list.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); + assertNull(list.get(0).getOtherText(), "Le texte libre doit être null"); + + other = other.concat(" pour la question « useCase »"); + userResponsesDao.insertResponse(useCase.getQuestionRef(), null, other); + + list = userResponsesDao.findAllByQuestion(useCase.getQuestionRef()); + assertEquals(list.size(), 2, "La liste de réponses de l'utilisateur pour la question « useCase » doit contenir deux éléments"); + for (final UserResponses ur : list) { + assertEquals(ur.getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); + if (ur.getOtherText() != null) { // on est sur une réponse libre + assertNull(ur.getResponse(), "L'objet response doit être null si il s'agit d'une réponse libre"); + assertEquals(ur.getOtherText(), other, "Le texte ne correspond pas à ce qui a été inséré en base"); + } else { + assertEquals(ur.getResponse().getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); + assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); + } + } + + + } + /** + * Return randomly responses list + * @param list original list + * @param nbElements to pick + * @return + */ + private List<Response> pickNRandom(final List<Response> list, final int nbElements) { + final List<Response> copy = new ArrayList<Response>(list); + Collections.shuffle(copy); + if (nbElements > copy.size()) { + return copy.subList(0, copy.size()); + } else { + return copy.subList(0, nbElements); + } + } +} diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/exception/ErrorTypeTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/exception/ErrorTypeTest.java index abbdc2a..678149f 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/exception/ErrorTypeTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/exception/ErrorTypeTest.java @@ -15,7 +15,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import fr.agrometinfo.www.server.I18n; -import fr.agrometinfo.www.server.service.MailService; +import fr.agrometinfo.www.server.service.MailServiceImpl; /** * Ensure all implementations of {@link ErrorType} are well defined. @@ -33,7 +33,7 @@ public class ErrorTypeTest { * @return classes to test. */ public static List<Class<? extends Enum<?>>> data() { - return Arrays.asList(MailService.MailErrorType.class); + return Arrays.asList(MailServiceImpl.MailErrorType.class); } /** diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java new file mode 100644 index 0000000..e0d1d75 --- /dev/null +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java @@ -0,0 +1,368 @@ +/** + * + */ +package fr.agrometinfo.www.server.rs; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; + + +import fr.agrometinfo.www.server.dao.QuestionsDao; +import fr.agrometinfo.www.server.dao.QuestionsDaoHibernate; +import fr.agrometinfo.www.server.dao.ResponsesDao; +import fr.agrometinfo.www.server.dao.ResponsesDaoHibernate; +import fr.agrometinfo.www.server.dao.UserResponsesDao; +import fr.agrometinfo.www.server.dao.UserResponsesDaoHibernate; +import fr.agrometinfo.www.server.exception.AgroMetInfoException; +import fr.agrometinfo.www.server.model.Question; +import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.UserResponses; +import fr.agrometinfo.www.server.service.MailService; +import fr.agrometinfo.www.server.service.MailServiceImpl; +import fr.agrometinfo.www.server.service.MailServiceImpl.Mail; +import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; +import fr.agrometinfo.www.shared.dto.QuestionDTO; +import fr.agrometinfo.www.shared.dto.ResponseDTO; + +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Form; +import lombok.Getter; +import lombok.extern.log4j.Log4j2; + +/** + * Test login form webservice. + * @author jdecome + * + */ +@Log4j2 +public class LoginFormResourceTest extends JerseyTest { + /** + * Mock class for mail service. + * @author jdecome + * + */ + public class MailServiceTest implements MailService { + /** Mail object. */ + @Getter + private Mail mail = null; + @Override + public void sendLoginFilled(LoginFormDataDTO data) { + this.mail = MailServiceImpl.createContentFromData(data); + } + + @Override + public void sendApplicationStarted() { + // do nothing + } + + @Override + public void send(Mail mail) throws AgroMetInfoException { + // do nothing + } + + }; + /** Path separator. */ + private static final String SEP = "/"; + /** Parsing JSON to object. */ + private final ObjectMapper objectMapper = new ObjectMapper(); + /** DAO for Questions. */ + private final QuestionsDao questionsDao = new QuestionsDaoHibernate(); + /** DAO for Responses. */ + private final ResponsesDao responsesDao = new ResponsesDaoHibernate(); + /** DAO for UserResponses. */ + private final UserResponsesDao userResponsesDao = new UserResponsesDaoHibernate(); + /** Mail service. */ + private final MailService mailService = new MailServiceTest(); + + @Override + protected final Application configure() { + return new ResourceConfig(LoginFormResource.class).register(new AbstractBinder() { + @Override + protected void configure() { + bind(questionsDao).to(QuestionsDao.class); + bind(responsesDao).to(ResponsesDao.class); + bind(userResponsesDao).to(UserResponsesDao.class); + bind(mailService).to(MailService.class); + } + }); + } + /** Test de la récupération des réponses. */ + @Test + public void getResponses() { + // On récupère les questions via le webservice + final String jsonQuestions = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_QUESTIONS_LIST).request().get(String.class); + assertNotNull(jsonQuestions, "Impossible de récupérer la ressource (objet null) pour les questions"); + assertFalse(jsonQuestions.isEmpty(), "La chaine de caractère JSON des questions est vide"); + try { + final List<Question> questions = objectMapper.readValue(jsonQuestions, new TypeReference<List<Question>>(){}); + assertNotNull(questions, "La conversion du JSON des questions en liste a échoué"); + assertNotEquals(questions.size(), 0, "La liste de questions est vide"); + + // On récupère l'ensemble des réponses + final String jsonAllResponses = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_RESPONSES_LIST).request().get(String.class); + assertNotNull(jsonAllResponses, "Impossible de récupérer la ressource (objet null) des réponses"); + assertFalse(jsonAllResponses.isEmpty(), "La chaine de caractère JSON des réponses est vide"); + + final List<Response> allResponses = objectMapper.readValue(jsonAllResponses, new TypeReference<List<Response>>() {}); + assertNotNull(allResponses, "La conversion du JSON des réponses en liste a échoué"); + assertNotEquals(allResponses.size(), 0, "La liste de réponses est vide"); + + for (final Response r : allResponses) { + assertTrue(questions.contains(r.getQuestion()), "La question de la réponse « " + r.getFullname() + " » n'est pas contenue dans la liste des questions"); + } + + // Pour chaque question, + for (final Question q : questions) { + // on vérifie que la question est retrouvable par la catégorie, via le webservice + final String jsonCategory = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_QUESTION_BY_CATEGORY) + .queryParam("category", q.getCategory()) + .request().get(String.class); + + assertNotNull(jsonCategory, "Impossible de récupérer la ressource (objet null) de la catégorie pour la question n°" + q.getQuestionRef()); + assertFalse(jsonCategory.isEmpty(), "La chaine de caractère JSON de la catégorie pour la question n° " + q.getQuestionRef() + " est vide"); + + final Question questionByCategory = objectMapper.readValue(jsonCategory, new TypeReference<Question>() {}); + assertNotNull(questionByCategory, "La conversion du JSON de la catégorie pour la question n° " + q.getQuestionRef() + " n'a pas fonctionnée"); + assertEquals(questionByCategory, q, "La question lue par la catégorie ne correspond pas avec la question n° " + q.getQuestionRef() + "d'origine"); + + // On vérifie, via le DAO + final Question questionByDao = questionsDao.findByCategory(q.getCategory()); + assertNotNull(questionByDao, "La lecture de la question n° " + q.getQuestionRef() + " via le DAO n'a pas fonctionnée"); + assertEquals(questionByDao, q, "La question lue par le DAO ne correspond pas avec la question n° " + q.getQuestionRef() + "d'origine"); + + // on récupère les réponses associées via le webservice + final String jsonResponses = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_RESPONSES_BY_QUESTION_LIST) + .queryParam("questionRef", String.valueOf(q.getQuestionRef())) + .request() + .get(String.class); + + assertNotNull(jsonResponses, "Impossible de récupérer la ressource (objet null) pour la question n° " + q.getQuestionRef() + " est vide"); + assertFalse(jsonResponses.isEmpty(), "La chaine de caractère JSON pour la question n° " + q.getQuestionRef() + " est vide"); + + final List<Response> responses = objectMapper.readValue(jsonResponses, new TypeReference<List<Response>>() {}); + assertNotNull(responses, "La conversion du JSON des réponses de la question n° " + q.getQuestionRef() + " n'a pas fonctionnée"); + assertNotEquals(responses.size(), 0, " La liste de réponses pour la question n° " + q.getQuestionRef() + " est vide"); + + final List<Response> responsesByDao = responsesDao.findAllByQuestion(q.getQuestionRef()); + assertNotNull(responsesByDao, " La lecture des réponses pour la question n° " + q.getQuestionRef() + " via le DAO n'a pas fonctionné"); + assertNotEquals(responsesByDao.size(), 0, " La liste de réponses via le DAO pour la question n° " + q.getQuestionRef() + " est vide"); + assertEquals(responses, responsesByDao, "La liste de réponses via le webservice n'est pas identique avec la liste via le DAO"); + + for (final Response r : responses) { + assertNotNull(r.getQuestion(), "La question de la réponse n° " + r.getResponseRef() + " est null"); + assertEquals(r.getQuestion(), q, "La question de la réponse n° " + r.getResponseRef() + " ne correspond pas à la question"); + assertTrue(responsesByDao.contains(r), "La liste via le DAO ne contient pas la réponse n° " + r.getResponseRef()); + } + + } + } catch (final JsonProcessingException e) { + log.info(e.getMessage()); + } + } + /** Test de l'écriture en base. */ + @Test + public void setUserResponses() { + this.resetUserResponses(); + final String category = "origin"; + // Question + final String jsonOrigins = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_QUESTION_BY_CATEGORY) + .queryParam("category", category) + .request().get(String.class); + assertNotNull(jsonOrigins, "Impossible de récupérer la ressource (objet null) de la catégorie pour la question de l'origine"); + assertFalse(jsonOrigins.isEmpty(), "La chaine de caractère JSON pour la question de catégorie « " + category + " » est vide"); + try { + final Question origin = objectMapper.readValue(jsonOrigins, new TypeReference<Question>() {}); + assertEquals(origin, questionsDao.findByCategory(category), "La question lue dans le webservice ne correspond pas avec la question via le DAO"); + + // on récupère les réponses de la question + final List<Response> responses = objectMapper.readValue(target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_RESPONSES_BY_QUESTION_LIST) + .queryParam("questionRef", String.valueOf(origin.getQuestionRef())) + .request() + .get(String.class), new TypeReference<List<Response>>() {}); + + assertNotNull(responses, "La conversion du JSON des réponses de la question « " + origin.getCategory() + " » n'a pas fonctionnée"); + assertNotEquals(responses.size(), " La liste de réponses pour la question " + origin.getCategory() + " est vide"); + for (final Response r : responses) { + assertEquals(r.getQuestion(), origin, "La question de la réponse ne correspond pas avec la question d'origine"); + } + + final List<Response> listOfResponses = new ArrayList<>(); // liste des réponses insérées + // Insertion d'une réponse prédéfénie + Response r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); + final Form form = new Form(); + form.param("questionRef", String.valueOf(origin.getQuestionRef())); + form.param("responseRef", String.valueOf(r.getResponseRef())); + form.param("otherText", "null"); + + target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE) + .request(MediaType.TEXT_PLAIN) + .post(Entity.form(form)); + listOfResponses.add(r); + + // On lit la réponse insérée, via le DAO + List<UserResponses> userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); + assertEquals(userResponsesList.size(), 1, "La liste de réponses de l'utilisateur doit contenir un élément"); + assertEquals(userResponsesList.get(0).getQuestion(), origin, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); + assertEquals(userResponsesList.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); + assertNull(userResponsesList.get(0).getOtherText(), "Le texte libre doit être null"); + + // insertion de plusieurs réponses + final int nbToInsert = 3; + final List<Response> randoms = this.pickNRandom(responses, nbToInsert); + for (final Response res : randoms) { + final Form f = new Form(); + f.param("questionRef", String.valueOf(origin.getQuestionRef())); + f.param("responseRef", String.valueOf(res.getResponseRef())); + f.param("otherText", "null"); + + target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE) + .request(MediaType.TEXT_PLAIN) + .post(Entity.form(f)); + + listOfResponses.add(res); + } + + // Vérification via le DAO + userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); + assertEquals(userResponsesList.size(), (1 + nbToInsert), "La liste de réponses de l'utilisateur doit contenir la réponse précédente + " + + nbToInsert + " réponses supplémentaires"); + for (final UserResponses ur : userResponsesList) { + assertEquals(ur.getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question"); + assertTrue(listOfResponses.contains(ur.getResponse()), "La réponse contenue dans la réponse de l'utilisateur n'est pas dans la liste des réponses insérées"); + assertEquals(ur.getResponse().getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); + assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); + } + + final int newNbResponses = 1 + nbToInsert; + + // insertion d'une réponse à choix libre + final String other = "Ceci est une réponse libre"; + final Form formOther = new Form(); + formOther.param("questionRef", String.valueOf(origin.getQuestionRef())); + formOther.param("responseRef", "null"); + formOther.param("otherText", other); + + target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE) + .request(MediaType.TEXT_PLAIN) + .post(Entity.form(formOther)); + + userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); + assertEquals(userResponsesList.size(), (newNbResponses + 1), "La liste de réponses de l'utilisateur doit contenir les " + + newNbResponses + " réponses + la réponse libre"); + for (final UserResponses ur : userResponsesList) { + assertEquals(ur.getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); + if (ur.getOtherText() != null) { // on est sur une réponse libre + assertNull(ur.getResponse(), "L'objet response doit être null si il s'agit d'une réponse libre"); + assertEquals(ur.getOtherText(), other, "Le texte ne correspond pas à ce qui a été inséré en base"); + } else { + assertEquals(ur.getResponse().getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); + assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); + } + } + } catch (JsonProcessingException e) { + log.info(e.getMessage()); + } + } + /** Test en définissant les réponses pour les questions. */ + @Test + public void testWithJsonResponses() { + this.resetUserResponses(); + final List<Question> questionsList = questionsDao.findAll(); + final List<QuestionDTO> questionsDTO = questionsList.stream().map(LoginFormResource::toDto).toList(); + + final List<Response> responsesList = new ArrayList<>(); + final HashMap<Long, String> otherTextMap = new HashMap<>(); + + for (final Question q : questionsList) { + final List<Response> responsesListForQuestion = responsesDao.findAllByQuestion(q.getQuestionRef()); + + // on récupère un nombre aléatoire de réponse + final List<Response> randomList = this.pickNRandom(responsesListForQuestion, ThreadLocalRandom.current().nextInt(0, responsesListForQuestion.size() - 1)); + + // si il y a au moins une réponse récupérée aléatoirement + if (randomList.size() > 0) { + responsesList.addAll(randomList); + } + + otherTextMap.put(q.getQuestionRef(), "Réponse libre pour la question « " + q.getFullName() + " »"); + } + final List<ResponseDTO> responsesDTO = responsesList.stream().map(LoginFormResource::toDto).toList(); + + final LoginFormDataDTO data = new LoginFormDataDTO(questionsDTO, responsesDTO, otherTextMap); + assertEquals(data.getQuestions(), questionsDTO, "La liste de questions dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); + assertEquals(data.getResponses(), responsesDTO, "La liste de réponses dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); + assertEquals(data.getOtherTextMap(), otherTextMap, "La liste de réponses libre dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); + + + jakarta.ws.rs.core.Response ret = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE_WITH_JSON) + .request(MediaType.APPLICATION_JSON).post(Entity.entity(data, MediaType.APPLICATION_JSON)); + + assertEquals(ret.getStatus(), jakarta.ws.rs.core.Response.Status.OK.getStatusCode(), "Le point d'entrée d'insertion doit retourner le code status 200 (OK)"); + + // Pour le test, vérifier, pour chaque question, les réponses via le DAO + for (final Question q : questionsDao.findAll()) { + final List<UserResponses> list = userResponsesDao.findAllByQuestion(q.getQuestionRef()); + assertNotNull(list, "La liste de réponses de l'utilisateur ne doit pas être null"); + for (final UserResponses ur : list) { + assertNotNull(ur.getDateTime(), "Le timestamp de la réponse ne doit pas être null"); + assertEquals(ur.getQuestion(), q, "La question contenue dans la réponse ne correspond pas avec la question d'origine « " + q.getFullName() + " »"); + assertTrue(ur.getUserResponseRef() > 0, "la référence de la réponse de l'utilisateur doit être supérieur à 0"); + if (ur.getResponse() != null) { + assertNotNull(ur.getResponse(), "La réponse de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); + assertNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, doit être null"); + } else { + assertNull(ur.getResponse(), "La réponse de l'utilisateur, pour une réponse libre, doit être null"); + assertNotNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); + } + } + } + + // on vérifie le mail + final Mail mail = ((MailServiceTest) this.mailService).getMail(); + assertNotNull(mail, "L'objet mail ne doit pas être null"); + assertNotNull(mail.getContent(), "Le corps du message n'est pas défini (= null)"); + assertFalse(mail.getContent().isEmpty(), "Le corps du message est vide"); + } + /** + * + * @param list origin list + * @param nbElements to pick in list + * @return randomized list with nbElements + */ + private List<Response> pickNRandom(final List<Response> list, final int nbElements) { + final List<Response> copy = new ArrayList<Response>(list); + Collections.shuffle(copy); + if (nbElements > copy.size()) { + return copy.subList(0, copy.size()); + } else { + return copy.subList(0, nbElements); + } + } + /** + * Reset user2responses table. + */ + private void resetUserResponses() { + this.userResponsesDao.deleteAll(); + } +} diff --git a/www-server/src/test/resources/META-INF/persistence.xml b/www-server/src/test/resources/META-INF/persistence.xml index 55e45d5..e0622b5 100644 --- a/www-server/src/test/resources/META-INF/persistence.xml +++ b/www-server/src/test/resources/META-INF/persistence.xml @@ -18,6 +18,9 @@ <class>fr.agrometinfo.www.server.model.PraDailyValue</class> <class>fr.agrometinfo.www.server.model.Region</class> <class>fr.agrometinfo.www.server.model.Simulation</class> + <class>fr.agrometinfo.www.server.model.Question</class> + <class>fr.agrometinfo.www.server.model.Response</class> + <class>fr.agrometinfo.www.server.model.UserResponses</class> <properties> <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:agrometinfo;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM '../sql/schema.types.h2.sql'\;RUNSCRIPT FROM '../sql/schema.tables.sql'\;RUNSCRIPT FROM '../sql/init_data.h2.sql';" /> <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver" /> diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java new file mode 100644 index 0000000..0d2cefc --- /dev/null +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java @@ -0,0 +1,84 @@ +/** + * + */ +package fr.agrometinfo.www.shared.dto; + +import java.util.HashMap; +import java.util.List; + + +/** + * Class contains all data of login form. + * @author jdecome + * + */ +public class LoginFormDataDTO { + /** + * List of login form questions.<br> + * This list questions contains available questions, obtained by {@link QuestionsDao} + */ + private List<QuestionDTO> questions; + /** + * List of login form responses.<br> + * This list responses contains available responses, obtained by {@link ResponsesDao} + */ + private List<ResponseDTO> responses; + /** + * Storage, for each response, the other text, if specified. + */ + private HashMap<Long, String> otherTextMap = new HashMap<>(); + /** + * Default constructor. + */ + public LoginFormDataDTO() { + + } + /** + * Constructor. + * @param qList questions list + * @param rList responses list + * @param otherText otherText map + */ + public LoginFormDataDTO(final List<QuestionDTO> qList, final List<ResponseDTO> rList, HashMap<Long, String> otherText) { + this.questions = qList; + this.responses = rList; + this.otherTextMap = otherText; + } + /** + * @return the questions + */ + public List<QuestionDTO> getQuestions() { + return questions; + } + /** + * @return the responses + */ + public List<ResponseDTO> getResponses() { + return responses; + } + /** + * @return the otherTextMap + */ + public HashMap<Long, String> getOtherTextMap() { + return otherTextMap; + } + /** + * @param questions the questions to set + */ + public void setQuestions(List<QuestionDTO> questions) { + this.questions = questions; + } + /** + * @param responses the responses to set + */ + public void setResponses(List<ResponseDTO> responses) { + this.responses = responses; + } + /** + * @param otherTextMap the otherTextMap to set + */ + public void setOtherTextMap(HashMap<Long, String> otherTextMap) { + this.otherTextMap = otherTextMap; + } + +} diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java new file mode 100644 index 0000000..3028802 --- /dev/null +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java @@ -0,0 +1,85 @@ +/** + * + */ +package fr.agrometinfo.www.shared.dto; + +import java.util.Objects; + +import org.dominokit.jackson.annotation.JSONMapper; + +/** + * DTO for questions of login form. + * @author jdecome + * + */ +@JSONMapper +public class QuestionDTO { + /** + * Ref of question. + */ + private long questionRef; + /** + * Category of question. + */ + private String category; + /** + * Label of question. + */ + private String fullName; + /** + * @return the questionRef + */ + public long getQuestionRef() { + return questionRef; + } + /** + * @return the category + */ + public String getCategory() { + return category; + } + /** + * @return the fullName + */ + public String getFullName() { + return fullName; + } + /** + * @param questionRef the questionRef to set + */ + public void setQuestionRef(final long questionRef) { + this.questionRef = questionRef; + } + /** + * @param category the category to set + */ + public void setCategory(final String category) { + this.category = category; + } + /** + * @param fullName the fullName to set + */ + public void setFullName(final String fullName) { + this.fullName = fullName; + } + @Override + public int hashCode() { + return Objects.hash(category, fullName, questionRef); + } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + QuestionDTO other = (QuestionDTO) obj; + return Objects.equals(category, other.category) && Objects.equals(fullName, other.fullName) + && questionRef == other.questionRef; + } + +} diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java new file mode 100644 index 0000000..f52837f --- /dev/null +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java @@ -0,0 +1,64 @@ +/** + * + */ +package fr.agrometinfo.www.shared.dto; + +import org.dominokit.jackson.annotation.JSONMapper; + +/** + * DTO for responses of login form. + * @author jdecome + * + */ +@JSONMapper +public class ResponseDTO { + /** + * Ref of this response. + */ + private long responseRef; + /** + * DTO of question associated to response. + */ + private QuestionDTO question; + /** + * Label of response. + */ + private String fullname; + /** + * @return the responseRef + */ + public long getResponseRef() { + return responseRef; + } + /** + * @return the question + */ + public QuestionDTO getQuestion() { + return question; + } + /** + * @return the fullname + */ + public String getFullname() { + return fullname; + } + /** + * @param responseRef the responseRef to set + */ + public void setResponseRef(final long responseRef) { + this.responseRef = responseRef; + } + /** + * @param question the question to set + */ + public void setQuestion(final QuestionDTO question) { + this.question = question; + } + /** + * @param fullname the fullname to set + */ + public void setFullname(final String fullname) { + this.fullname = fullname; + } + +} diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java new file mode 100644 index 0000000..d226069 --- /dev/null +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java @@ -0,0 +1,92 @@ +/** + * + */ +package fr.agrometinfo.www.shared.service; + +import java.util.List; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +import org.dominokit.rest.shared.request.service.annotations.RequestFactory; +import org.dominokit.rest.shared.request.service.annotations.RequestBody; + +import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; +import fr.agrometinfo.www.shared.dto.QuestionDTO; +import fr.agrometinfo.www.shared.dto.ResponseDTO; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.QueryParam; + +/** + * @author jdecome + * + */ +@RequestFactory +@Path(LoginFormService.PATH) +public interface LoginFormService { + /** Service base path. */ + public static final String PATH = "login"; + /** Path for {@link LoginFormService#getQuestions()}. */ + public static final String PATH_QUESTIONS_LIST = "questions"; + /**Path for {@link LoginFormService#getQuestionByCategory(String)}. */ + public static final String PATH_QUESTION_BY_CATEGORY = "question"; + /** Path for {@link LoginFormService#getResponses}. */ + public static final String PATH_RESPONSES_LIST = "responses"; + /** Path for {@link LoginFormService#getResponsesByQuestion(long)}. */ + public static final String PATH_RESPONSES_BY_QUESTION_LIST = "responsesByQuestion"; + /** Path for {@link LoginFormService#getResponses()}. */ + public static final String PATH_INSERT_RESPONSE = "insert"; + /** Path for {@link LoginFormService#insertResponse(String)}. */ + public static final String PATH_INSERT_RESPONSE_WITH_JSON = "insertMultipleValues"; + /** + * @return list of questions. + */ + @GET + @Path(PATH_QUESTIONS_LIST) + List<QuestionDTO> getQuestions(); + @GET + @Path(PATH_RESPONSES_LIST) + List<ResponseDTO> getResponses(); + /** + * Get question by his category. + * @param category of the question + * @return question + */ + @GET + @Path(PATH_QUESTION_BY_CATEGORY) + QuestionDTO getQuestionByCategory(@QueryParam(value = "category") final String category); + /** + * Returning the list of possible response for one question. + * @param questionRef ref of question + * @return list of question's responses + */ + @GET + @Path(PATH_RESPONSES_BY_QUESTION_LIST) + List<ResponseDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") final Long questionRef); + /** + * Insert response or text for specified question.<br> + * If responseRef is provided, {@code otherText} must be null.<br> + * If otherText is provided, {@code responseRef} must be null. + * @param questionRef ref of question + * @param responseRef ref of response or « null » String for null value + * @param otherText text if response is other + * + * @return + */ + @POST + @Path(PATH_INSERT_RESPONSE) + void insertResponse( + @FormParam(value = "questionRef") final Long questionRef, + @FormParam(value = "responseRef") @DefaultValue("null") final String responseRef, + @FormParam(value = "otherText") @DefaultValue("null") final String otherText + ); + /** + * Insert all responses of login form. + * @param responsesList + */ + @POST + @Path(PATH_INSERT_RESPONSE_WITH_JSON) + String insertAllResponses(@RequestBody final LoginFormDataDTO data); +} -- GitLab From 6451a7662f3c67e6aa2a245f6fc693f09b4acc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Thu, 23 May 2024 12:10:41 +0200 Subject: [PATCH 02/30] Corrections erreurs PMD. fixes #5 --- .../java/fr/agrometinfo/www/client/App.java | 1 - .../www/client/i18n/AppConstants.java | 2 - .../www/client/view/LayoutView.java | 2 + .../www/client/view/LoginView.java | 13 ++--- .../www/server/dao/DaoHibernate.java | 2 +- .../www/server/dao/QuestionsDaoHibernate.java | 1 - .../www/server/model/LoginFormData.java | 50 ------------------- .../www/server/model/Response.java | 2 - .../www/server/model/UserResponses.java | 4 -- .../www/server/rs/LoginFormResource.java | 10 +--- .../www/shared/service/LoginFormService.java | 14 +++--- 11 files changed, 15 insertions(+), 86 deletions(-) delete mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/model/LoginFormData.java diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/App.java b/www-client/src/main/java/fr/agrometinfo/www/client/App.java index d1895a5..37dd573 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/App.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/App.java @@ -82,7 +82,6 @@ public class App implements EntryPoint { public static EventBus getEventBus() { return EVENT_BUS; } - /** * This is the entry point method. */ diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java index b45c154..7d58fa5 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java @@ -1,7 +1,5 @@ package fr.agrometinfo.www.client.i18n; -import java.util.Map; - /** * Interface to represent the constants contained in resource bundle: * 'fr/agrometinfo/www/client/i18n/AppConstants.properties'. diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java index 6006d8a..4dcdfe4 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java @@ -17,6 +17,8 @@ import org.dominokit.domino.ui.loaders.LoaderEffect; import org.dominokit.domino.ui.menu.Menu; import org.dominokit.domino.ui.menu.MenuItem; import org.dominokit.domino.ui.notifications.Notification; +import org.dominokit.domino.ui.popover.PopupPosition; +import org.dominokit.domino.ui.popover.Tooltip; import org.dominokit.domino.ui.style.Styles; import org.dominokit.domino.ui.utils.DominoElement; import org.dominokit.domino.ui.utils.DominoUIConfig; diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java index b1f3164..57dc2eb 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java @@ -17,7 +17,6 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.storage.client.Storage; import fr.agrometinfo.www.client.i18n.AppConstants; -import fr.agrometinfo.www.client.i18n.AppMessages; import fr.agrometinfo.www.client.presenter.LoginPresenter; import fr.agrometinfo.www.shared.dto.QuestionDTO; import fr.agrometinfo.www.shared.dto.ResponseDTO; @@ -34,10 +33,6 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements * I18N constants. */ private static final AppConstants CSTS = GWT.create(AppConstants.class); - /** - * I18N messages. - */ - private static final AppMessages MSGS = GWT.create(AppMessages.class); /** * Is survey was already validated by user ? */ @@ -65,11 +60,9 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements GWT.log("LoginView.init()"); // on vérifie que le formulaire n'a pas déjà été rempli par l'utilisateur, via le LocalStorage du navigateur final Storage ls = Storage.getLocalStorageIfSupported(); - if (ls != null) { - if (ls.getItem(IS_VALIDATED_KEY) != null && ls.getItem(IS_VALIDATED_KEY).equals("true")) { - GWT.log("Survey was already validated for this user, don't showing again"); - return; - } + if (ls != null && ls.getItem(IS_VALIDATED_KEY) != null && ls.getItem(IS_VALIDATED_KEY).equals("true")) { + GWT.log("Survey was already validated for this user, don't showing again"); + return; } final Map<Long, TextArea> otherTextArea = new HashMap<>(); diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java index f6232d1..5045a5d 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java @@ -97,7 +97,7 @@ public abstract class DaoHibernate<T> { q.executeUpdate(); em.getTransaction().commit(); LOGGER.traceExit(); - }; + } /** * Use a consumer to execute JPA operations in a transaction. * diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java index 9369e17..147ccea 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java @@ -3,7 +3,6 @@ */ package fr.agrometinfo.www.server.dao; -import java.util.List; import java.util.Map; import fr.agrometinfo.www.server.model.Question; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/LoginFormData.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/LoginFormData.java deleted file mode 100644 index 236fbe4..0000000 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/LoginFormData.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * - */ -package fr.agrometinfo.www.server.model; - -import java.util.HashMap; -import java.util.List; - -import lombok.Data; -import lombok.Getter; -import lombok.Setter; - -/** - * Class contains all data of login form. - * @author jdecome - * - */ -@Deprecated -public class LoginFormData { - /** - * List of login form questions.<br> - * This list questions contains available questions, obtained by {@link QuestionsDao} - */ - @Getter - @Setter - private List<Question> questions; - /** - * List of login form responses.<br> - * This list responses contains available responses, obtained by {@link ResponsesDao} - */ - @Getter - @Setter - private List<Response> responses; - /** - * Storage, for each response, the other text, if specified. - */ - @Getter - private HashMap<Long, String> otherTextMap = new HashMap<>(); - /** - * Constructor. - * @param qList questions list - * @param rList responses list - * @param otherText otherText map - */ - public LoginFormData(final List<Question> qList, final List<Response> rList, HashMap<Long, String> otherText) { - this.questions = qList; - this.responses = rList; - this.otherTextMap = otherText; - } -} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java index 7f3c123..b87ec07 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java @@ -4,12 +4,10 @@ package fr.agrometinfo.www.server.model; import jakarta.persistence.Column; -import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.IdClass; import jakarta.persistence.JoinColumn; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java index e4d6e50..5c5371b 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java @@ -4,17 +4,13 @@ package fr.agrometinfo.www.server.model; import java.sql.Timestamp; -import java.util.List; import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.IdClass; import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import lombok.Data; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java index 432c54c..1a34f79 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java @@ -5,10 +5,8 @@ package fr.agrometinfo.www.server.rs; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; -import com.fasterxml.jackson.databind.ObjectMapper; import fr.agrometinfo.www.server.dao.QuestionsDao; import fr.agrometinfo.www.server.dao.ResponsesDao; @@ -16,7 +14,6 @@ import fr.agrometinfo.www.server.dao.UserResponsesDao; import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; import fr.agrometinfo.www.server.service.MailService; -import fr.agrometinfo.www.server.service.MailServiceImpl; import fr.agrometinfo.www.shared.dto.ErrorResponseDTO; import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; import fr.agrometinfo.www.shared.dto.QuestionDTO; @@ -33,13 +30,12 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.FormParam; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; -import lombok.extern.log4j.Log4j2; /** + * Endpoint for WS login form. * @author jdecome * */ -@Log4j2 @Path(LoginFormService.PATH) @RequestScoped public class LoginFormResource implements LoginFormService { @@ -194,8 +190,6 @@ public class LoginFormResource implements LoginFormService { this.userResponsesDao.insertResponse(questionRef, Long.valueOf(responseRef), null); } else if(responseRefIsNull && !otherTextIsNull) { // réponse libre this.userResponsesDao.insertResponse(questionRef, null, otherText); - } else { - // Do nothing } } } @@ -204,7 +198,7 @@ public class LoginFormResource implements LoginFormService { if (questionRef != null) { // on cherche dans le DAO final Question q = questionsDao.findByRef(questionRef); - return (q != null); + return q != null; } return false; } diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java index d226069..4c04cc0 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java @@ -27,19 +27,19 @@ import jakarta.ws.rs.QueryParam; @Path(LoginFormService.PATH) public interface LoginFormService { /** Service base path. */ - public static final String PATH = "login"; + String PATH = "login"; /** Path for {@link LoginFormService#getQuestions()}. */ - public static final String PATH_QUESTIONS_LIST = "questions"; + String PATH_QUESTIONS_LIST = "questions"; /**Path for {@link LoginFormService#getQuestionByCategory(String)}. */ - public static final String PATH_QUESTION_BY_CATEGORY = "question"; + String PATH_QUESTION_BY_CATEGORY = "question"; /** Path for {@link LoginFormService#getResponses}. */ - public static final String PATH_RESPONSES_LIST = "responses"; + String PATH_RESPONSES_LIST = "responses"; /** Path for {@link LoginFormService#getResponsesByQuestion(long)}. */ - public static final String PATH_RESPONSES_BY_QUESTION_LIST = "responsesByQuestion"; + String PATH_RESPONSES_BY_QUESTION_LIST = "responsesByQuestion"; /** Path for {@link LoginFormService#getResponses()}. */ - public static final String PATH_INSERT_RESPONSE = "insert"; + String PATH_INSERT_RESPONSE = "insert"; /** Path for {@link LoginFormService#insertResponse(String)}. */ - public static final String PATH_INSERT_RESPONSE_WITH_JSON = "insertMultipleValues"; + String PATH_INSERT_RESPONSE_WITH_JSON = "insertMultipleValues"; /** * @return list of questions. */ -- GitLab From d0866a937cb96b8d018e6974c97ede0494ca8ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Thu, 23 May 2024 15:13:04 +0200 Subject: [PATCH 03/30] Corrections PMD 2. fixes #5 --- config/pmd-suppressions.properties | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/config/pmd-suppressions.properties b/config/pmd-suppressions.properties index 11439c6..89c8232 100644 --- a/config/pmd-suppressions.properties +++ b/config/pmd-suppressions.properties @@ -8,9 +8,17 @@ fr.agrometinfo.www.shared.dto.IndicatorDTOBeanJsonDeserializerImpl=UnnecessaryIm fr.agrometinfo.www.shared.dto.IndicatorDTOBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.IndicatorDTO_MapperImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.MessageDTOBeanJsonSerializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.LoginFormDataDTOBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.PeriodDTOBeanJsonDeserializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.PeriodDTOBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.PeriodDTO_MapperImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.QuestionDTOBeanJsonDeserializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.QuestionDTOBeanJsonSerializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.QuestionDTO_MapperImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.ResponseDTOBeanJsonSerializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.ResponseDTOBeanJsonDeserializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.ResponseDTO_MapperImpl=UnnecessaryImport +fr.agrometinfo.www.shared.service.ResponseDTO_MapperImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.SimpleFeatureBeanJsonDeserializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.SimpleFeatureBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.SummaryDTOBeanJsonDeserializerImpl=UnnecessaryImport @@ -18,6 +26,9 @@ fr.agrometinfo.www.shared.dto.SummaryDTOBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.SummaryDTO_MapperImpl=UnnecessaryImport fr.agrometinfo.www.shared.service.ApplicationServiceFactory=UnnecessaryImport fr.agrometinfo.www.shared.service.IndicatorServiceFactory=UnnecessaryImport +fr.agrometinfo.www.shared.service.LoginFormServiceFactory=UnnecessaryImport +fr.agrometinfo.www.shared.service.QuestionDTO_MapperImpl=UnnecessaryImport +fr.agrometinfo.www.shared.service.ResponseDTOBeanJsonDeserializerImpl=UnnecessaryImport org.geojson.FeatureBeanJsonDeserializerImpl=UnnecessaryImport org.geojson.FeatureBeanJsonSerializerImpl=UnnecessaryImport org.geojson.FeatureCollectionBeanJsonDeserializerImpl=UnnecessaryImport -- GitLab From ca0c0725aeaf23e1f9dbbd337c5cffb911adb399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Fri, 24 May 2024 08:30:36 +0200 Subject: [PATCH 04/30] Corrections checkstyle. fixes #5 --- .../java/fr/agrometinfo/www/client/App.java | 3 +- .../www/client/i18n/AppConstants.java | 33 +++- .../www/client/presenter/LoginPresenter.java | 26 ++-- .../www/client/view/AbstractBaseView.java | 18 ++- .../www/client/view/LoginView.java | 147 +++++++++--------- .../www/server/dao/QuestionsDao.java | 32 ++-- .../www/server/dao/QuestionsDaoHibernate.java | 34 ++-- .../www/server/dao/ResponsesDao.java | 30 ++-- .../www/server/dao/ResponsesDaoHibernate.java | 23 ++- .../www/server/dao/UserResponsesDao.java | 56 ++++--- .../server/dao/UserResponsesDaoHibernate.java | 27 ++-- .../www/server/model/Question.java | 32 ++-- .../www/server/model/Response.java | 32 ++-- .../www/server/model/UserResponses.java | 38 ++--- .../www/server/rs/LoginFormResource.java | 30 ++-- .../www/server/service/MailServiceImpl.java | 29 ++-- .../www/server/rs/LoginFormResourceTest.java | 2 +- .../www/shared/dto/LoginFormDataDTO.java | 25 ++- .../www/shared/dto/QuestionDTO.java | 25 +-- .../www/shared/dto/ResponseDTO.java | 21 ++- .../www/shared/service/LoginFormService.java | 21 ++- 21 files changed, 363 insertions(+), 321 deletions(-) diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/App.java b/www-client/src/main/java/fr/agrometinfo/www/client/App.java index 37dd573..6134041 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/App.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/App.java @@ -97,8 +97,9 @@ public class App implements EntryPoint { // enabling Charba Charba.enable(); + new LayoutPresenter().start(); - + // formulaire d'enquête new LoginPresenter().start(); } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java index 7d58fa5..474fe81 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java @@ -338,29 +338,46 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo */ @DefaultStringValue("Yes") String yes(); - + // Formulaire d'enquête - #5 + /** + * @return translation + */ @DefaultStringValue("Valider") String validate(); - + /** + * @return translation + */ @DefaultStringValue("Ignorer") String ignore(); - + /** + * @return translation + */ @DefaultStringValue("Formulaire d'enquête") String loginFormTitle(); - + /** + * @return translation + */ @DefaultStringValue("Please complete this survey form to continue on AgroMetInfo.") String loginFormDescription(); - + /** + * @return translation + */ @DefaultStringValue("Other") String loginFormOtherTextCheckbox(); - + /** + * @return translation + */ @DefaultStringValue("You must click on checkbox above for activate this input field.") String loginFormOtherTextTooltip(); - + /** + * @return translation + */ @DefaultStringValue("Your responses have been recorded.") String loginFormSuccess(); - + /** + * @return translation + */ @DefaultStringValue("Your responses cannot been recorded, but you can use AgroMetInfo application.") String loginFormFail(); } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java index 1c7d2f9..a949503 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java @@ -40,14 +40,14 @@ public final class LoginPresenter implements Presenter { */ void close(); /** - * @param list list of availables responses. + * @param map list of availables responses. */ void setResponses(Map<QuestionDTO, List<ResponseDTO>> map); /** * Showing success login. * @param msg returned message from webservice */ - void displaySuccessLogin(final String msg); + void displaySuccessLogin(String msg); } /** @@ -63,10 +63,9 @@ public final class LoginPresenter implements Presenter { * @param list list of responses */ private void setResponses(final List<ResponseDTO> list) { - GWT.log("setResponses(" + list.size() +") start"); this.responses = list; final Map<QuestionDTO, List<ResponseDTO>> responsesMap = new HashMap<>(); - + // extraction des questions, à partir des réponses retournées par le webservice for (final ResponseDTO dto : list) { if (!responsesMap.containsKey(dto.getQuestion())) { // la map ne contient pas la question @@ -77,14 +76,13 @@ public final class LoginPresenter implements Presenter { } this.questions = new ArrayList<>(responsesMap.keySet()); view.setResponses(responsesMap); - GWT.log("setResponses() end"); - + view.init(); } @Override public void start() { view.setPresenter(this); - + LoginFormServiceFactory.INSTANCE.getResponses() .onSuccess(this::setResponses) .onFailed(view::failureNotification) @@ -92,11 +90,11 @@ public final class LoginPresenter implements Presenter { } public void insertUserResponses(final List<Long> responsesRef, final HashMap<Long, String> otherTextMap) { GWT.log("Insère les réponses de l'utilisateur"); - + // traitement des réponses prédéfinies final List<QuestionDTO> questionsDto = new ArrayList<>(); final List<ResponseDTO> responsesDto = new ArrayList<>(); - + for (final Long ref : responsesRef) { // on récupère la réponse correspondante à la référence final ResponseDTO rDto = this.responses.stream().filter(r -> r.getResponseRef() == ref).findFirst().get(); @@ -104,7 +102,7 @@ public final class LoginPresenter implements Presenter { if (!responsesDto.contains(rDto)) { responsesDto.add(rDto); } - + // on récupère la question correspondantes à la réponse if (!questionsDto.contains(rDto.getQuestion())) { questionsDto.add(rDto.getQuestion()); @@ -117,14 +115,14 @@ public final class LoginPresenter implements Presenter { questionsDto.add(q); } }); - - final LoginFormDataDTO data = new LoginFormDataDTO(questionsDto, responsesDto, otherTextMap); - + + // envoi au webservice + final LoginFormDataDTO data = new LoginFormDataDTO(questionsDto, responsesDto, otherTextMap); LoginFormServiceFactory.INSTANCE.insertAllResponses(data) .onSuccess(view::displaySuccessLogin) .onFailed(view::failureNotification) .send(); } - + } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/AbstractBaseView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/AbstractBaseView.java index 52236ee..5521df9 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/AbstractBaseView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/AbstractBaseView.java @@ -34,7 +34,7 @@ public abstract class AbstractBaseView<T> implements BaseView<T> { /** * * @param failure - * @return + * @return details of failure object */ protected static String getDetails(final FailedResponseBean failure) { final StringJoiner sj = new StringJoiner("<br/>"); @@ -54,14 +54,18 @@ public abstract class AbstractBaseView<T> implements BaseView<T> { protected final T getPresenter() { return presenter; } - + /** */ @Override public final void setPresenter(final T value) { this.presenter = value; } - - protected Notification notification(final String msg) { - DomGlobal.console.info("Notification!"); - return Notification.create(msg).setPosition(Notification.TOP_LEFT).show(); - } + /** + * Show notification with message. + * @param msg message to display + * @return notification object + */ + protected Notification notification(final String msg) { + DomGlobal.console.info("Notification!"); + return Notification.create(msg).setPosition(Notification.TOP_LEFT).show(); + } } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java index 57dc2eb..ab0502c 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java @@ -26,7 +26,6 @@ import fr.agrometinfo.www.shared.dto.ResponseDTO; * * @author Olivier Maury * @author Jérémie Décome - * */ public final class LoginView extends AbstractBaseView<LoginPresenter> implements LoginPresenter.View { /** @@ -34,9 +33,13 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements */ private static final AppConstants CSTS = GWT.create(AppConstants.class); /** - * Is survey was already validated by user ? + * Is survey was already validated by user ? Key for LocalStorage. */ private static final String IS_VALIDATED_KEY = "isValidated"; + /** + * Level for questions. + */ + private static final int SECTION_TITLE_LEVEL = 5; /** * List of available responses. */ @@ -57,26 +60,26 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements @Override public void init() { - GWT.log("LoginView.init()"); - // on vérifie que le formulaire n'a pas déjà été rempli par l'utilisateur, via le LocalStorage du navigateur - final Storage ls = Storage.getLocalStorageIfSupported(); - if (ls != null && ls.getItem(IS_VALIDATED_KEY) != null && ls.getItem(IS_VALIDATED_KEY).equals("true")) { - GWT.log("Survey was already validated for this user, don't showing again"); - return; - } - - final Map<Long, TextArea> otherTextArea = new HashMap<>(); - + GWT.log("LoginView.init()"); + // on vérifie que le formulaire n'a pas déjà été rempli par l'utilisateur, via le LocalStorage du navigateur + final Storage ls = Storage.getLocalStorageIfSupported(); + if (ls != null && ls.getItem(IS_VALIDATED_KEY) != null && ls.getItem(IS_VALIDATED_KEY).equals("true")) { + GWT.log("Survey was already validated for this user, don't showing again"); + return; + } + + final Map<Long, TextArea> otherTextArea = new HashMap<>(); + this.modal = ModalDialog.create(CSTS.loginFormTitle()).large().setAutoClose(true); - this.modal - .appendChild(Elements.p().textContent(CSTS.loginFormDescription()).css("login-paragraph")); - - for (Map.Entry<QuestionDTO, List<ResponseDTO>> entry : this.availableResponses.entrySet()) { - final QuestionDTO k = entry.getKey(); // Pour chaque question - + this.modal + .appendChild(Elements.p().textContent(CSTS.loginFormDescription()).css("login-paragraph")); + + for (Map.Entry<QuestionDTO, List<ResponseDTO>> entry : this.availableResponses.entrySet()) { + final QuestionDTO k = entry.getKey(); // Pour chaque question + // on affiche le libellé - this.modal.appendChild(Elements.h(5, "• " + k.getFullName())); - + this.modal.appendChild(Elements.h(SECTION_TITLE_LEVEL, "• " + k.getFullName())); + // on affiche les réponses possibles entry.getValue().forEach((r) -> { final CheckBox cb = CheckBox.create(r.getFullname()).id(Long.toString(r.getResponseRef())) @@ -84,15 +87,17 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements this.modal.appendChild(cb); this.checkBoxList.add(cb); }); - + // on affiche le champ pour la réponse libre - final CheckBox otherCb = CheckBox.create(CSTS.loginFormOtherTextCheckbox()).id(k.getCategory() + "_other").css("login-checkbox"); + final CheckBox otherCb = CheckBox.create(CSTS.loginFormOtherTextCheckbox()) + .id(k.getCategory() + "_other") + .css("login-checkbox"); final TextArea otherText = TextArea.create().setId(k.getCategory() + "_other_text") .setDisabled(true) .setTooltip(CSTS.loginFormOtherTextTooltip()) .setRows(2) .css("login-textarea"); - + otherCb.addChangeHandler((v) -> { otherText.setDisabled(!otherCb.getValue()); if (!otherText.isDisabled()) { @@ -104,69 +109,69 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements this.checkBoxList.add(otherCb); this.modal.appendChild(otherCb).appendChild(otherText); otherTextArea.put(k.getQuestionRef(), otherText); - } - // active le bouton Valider si au moins une case a été cochée - this.checkBoxList.forEach((c) -> { - c.addChangeHandler((v) -> this.activateValidateButton()); - }); - - // E-mail de l'utilisateur - - this.validate = Button.create(CSTS.validate()).linkify(); - this.validate.addClickListener((evt) -> { - final HashMap<Long, String> otherTextMap = new HashMap<>(); - - // on traite les réponses prédéfinies (récupération des références des réponses), en excluant les cases à cocher pour les réponses libre - final List<Long> selectedResponsesRef = this.checkBoxList.stream() - .filter((v) -> v.getValue() && v.getId().matches("[0-9]+")) - .map(v -> Long.parseLong(v.getId())).collect(Collectors.toList()); - - // traitement des réponses libre de la question - otherTextArea.forEach((k, v) -> { - // si le champ est actif, c'est qu'il y a (potentiellement) une réponse et si le champ n'est pas vide - if (!v.isDisabled() && !v.getValue().equals("")) { - otherTextMap.put(k, v.getValue()); - } - }); - - this.getPresenter().insertUserResponses(selectedResponsesRef, otherTextMap); - - ls.setItem(IS_VALIDATED_KEY, "true"); - this.modal.close(); - }); - this.validate.setDisabled(true); // le bouton Valider est désactivé par défaut - this.modal.appendFooterChild(validate); - - final Button ignore = Button.create(CSTS.ignore()).linkify(); - ignore.addClickListener((evt) -> { - this.modal.close(); - }); - this.modal.appendFooterChild(ignore); - - this.modal.open(); - GWT.log("LoginView.init() end"); + } + // active le bouton Valider si au moins une case a été cochée + this.checkBoxList.forEach((c) -> { + c.addChangeHandler((v) -> this.activateValidateButton()); + }); + + // E-mail de l'utilisateur + + // Boutons de la fenêtre modale + this.validate = Button.create(CSTS.validate()).linkify(); + this.validate.addClickListener((evt) -> { + final HashMap<Long, String> otherTextMap = new HashMap<>(); + + // on traite les réponses prédéfinies (récupération des références des réponses), + // en excluant les cases à cocher pour les réponses libre + final List<Long> selectedResponsesRef = this.checkBoxList.stream() + .filter((v) -> v.getValue() && v.getId().matches("[0-9]+")) + .map(v -> Long.parseLong(v.getId())).collect(Collectors.toList()); + + // traitement des réponses libre de la question + otherTextArea.forEach((k, v) -> { + // si le champ est actif, c'est qu'il y a (potentiellement) une réponse et si le champ n'est pas vide + if (!v.isDisabled() && !v.getValue().equals("")) { + otherTextMap.put(k, v.getValue()); + } + }); + + this.getPresenter().insertUserResponses(selectedResponsesRef, otherTextMap); + + ls.setItem(IS_VALIDATED_KEY, "true"); + this.modal.close(); + }); + this.validate.setDisabled(true); // le bouton Valider est désactivé par défaut + this.modal.appendFooterChild(validate); + + final Button ignore = Button.create(CSTS.ignore()).linkify(); + ignore.addClickListener((evt) -> { + this.modal.close(); + }); + this.modal.appendFooterChild(ignore); + + this.modal.open(); + GWT.log("LoginView.init() end"); } - + @Override - public void failureNotification(FailedResponseBean failedResponse) { + public void failureNotification(final FailedResponseBean failedResponse) { this.notification(CSTS.loginFormFail()); } @Override - public void setResponses(Map<QuestionDTO, List<ResponseDTO>> map) { - GWT.log("LoginView.setResponses(" + map.size() + ")"); + public void setResponses(final Map<QuestionDTO, List<ResponseDTO>> map) { this.availableResponses = map; - GWT.log("LoginView.setResponses() end"); } @Override - public void displaySuccessLogin(String msg) { + public void displaySuccessLogin(final String msg) { this.notification(CSTS.loginFormSuccess()); } /** * Enable or disable validate button depending of checkbox status. */ private void activateValidateButton() { - this.validate.setDisabled(!this.checkBoxList.stream().anyMatch((c) -> c.getValue() == true)); + this.validate.setDisabled(!this.checkBoxList.stream().anyMatch((c) -> c.getValue())); } } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java index e68aaf0..7e65a6d 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java @@ -13,20 +13,20 @@ import fr.agrometinfo.www.server.model.Question; * */ public interface QuestionsDao { - /** - * @return all of Questions - */ - List<Question> findAll(); - /** - * Find question object by reference. - * @param questionRef question_ref - * @return Question object - */ - Question findByRef(long questionRef); - /** - * Find question object by category. - * @param category of question - * @return Question object - */ - Question findByCategory(final String category); + /** + * @return all of Questions + */ + List<Question> findAll(); + /** + * Find question object by reference. + * @param questionRef question_ref + * @return Question object + */ + Question findByRef(long questionRef); + /** + * Find question object by category. + * @param category of question + * @return Question object + */ + Question findByCategory(String category); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java index 147ccea..e243e48 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.server.dao; @@ -14,20 +14,22 @@ import jakarta.enterprise.context.ApplicationScoped; */ @ApplicationScoped public class QuestionsDaoHibernate extends DaoHibernate<Question> implements QuestionsDao { - - public QuestionsDaoHibernate() { - super(Question.class); - } - - @Override - public Question findByRef(long ref) { - return super.find(ref); - } - - @Override - public Question findByCategory(String category) { - final String jpql = "SELECT q FROM Question q WHERE q.category = :cat"; - return super.findOneByJPQL(jpql, Map.of("cat", category), Question.class); - } + /** + * Constructor. + */ + public QuestionsDaoHibernate() { + super(Question.class); + } + /** */ + @Override + public Question findByRef(final long ref) { + return super.find(ref); + } + /** */ + @Override + public Question findByCategory(final String category) { + final String jpql = "SELECT q FROM Question q WHERE q.category = :cat"; + return super.findOneByJPQL(jpql, Map.of("cat", category), Question.class); + } } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java index 9715217..acd4cb9 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.server.dao; @@ -9,26 +9,24 @@ import java.util.List; /** * DAO for {@link Response}. - * * @author jdecome - * */ public interface ResponsesDao { /** * Find all responses in database. * @return all responses */ - List<Response> findAll(); - /** - * Find all responses by question. - * @param questionRef - * @return list of responses - */ - List<Response> findAllByQuestion(final long questionRef); - /** - * Get response with reference. - * @param responseRef - * @return response - */ - Response findByRef(final long responseRef); + List<Response> findAll(); + /** + * Find all responses by question. + * @param questionRef + * @return list of responses + */ + List<Response> findAllByQuestion(long questionRef); + /** + * Get response with reference. + * @param responseRef + * @return response + */ + Response findByRef(long responseRef); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java index 5577d8e..ecaebf4 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.server.dao; @@ -18,19 +18,18 @@ public class ResponsesDaoHibernate extends DaoHibernate<Response> implements Res /** * Constructor. */ - public ResponsesDaoHibernate() { - super(Response.class); - } - - @Override - public List<Response> findAllByQuestion(final long questionRef) { - final String jpql = "SELECT r FROM Response r WHERE r.question.questionRef = :ref"; - return super.findAllByJPQL(jpql, Map.of("ref", questionRef), Response.class); - } - + public ResponsesDaoHibernate() { + super(Response.class); + } + /** */ + @Override + public List<Response> findAllByQuestion(final long questionRef) { + final String jpql = "SELECT r FROM Response r WHERE r.question.questionRef = :ref"; + return super.findAllByJPQL(jpql, Map.of("ref", questionRef), Response.class); + } + /** */ @Override public Response findByRef(final long responseRef) { return super.find(responseRef); } - } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java index 32c8a9d..d45e51d 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java @@ -7,9 +7,7 @@ import fr.agrometinfo.www.server.model.Response; import fr.agrometinfo.www.server.model.UserResponses; /** * DAO for {@link UserResponsesDao}. - * * @author jdecome - * */ public interface UserResponsesDao { /** @@ -17,32 +15,32 @@ public interface UserResponsesDao { * @param questionRef * @return list of user's responses */ - List<UserResponses> findAllByQuestion(final long questionRef); - /** - * Insert response or text for specified question.<br> + List<UserResponses> findAllByQuestion(long questionRef); + /** + * Insert response or text for specified question.<br> * If r is provided, {@code otherText} must be null.<br> - * If otherText is provided, {@code r} must be null. - * @param q question to answer - * @param r response - * @param otherText text if response is other - */ - void insertResponse(final Question q, final Response r, final String otherText); - /** - * Insert response or text for specified question, identified by reference.<br> - * If responseRef is provided, {@code otherText} must be null.<br> - * If otherText is provided, {@code responseRef} must be null. - * @param questionRef reference of question to answer - * @param responseRef reference of response - * @param otherText text if response is other - */ - void insertResponse(final Long questionRef, final Long responseRef, final String otherText); - /** - * Get all user responses. - * @return number of responses - */ - int getNbUserResponses(); - /** - * - */ - void deleteAll(); + * If otherText is provided, {@code r} must be null. + * @param q question to answer + * @param r response + * @param otherText text if response is other + */ + void insertResponse(Question q, Response r, String otherText); + /** + * Insert response or text for specified question, identified by reference.<br> + * If responseRef is provided, {@code otherText} must be null.<br> + * If otherText is provided, {@code responseRef} must be null. + * @param questionRef reference of question to answer + * @param responseRef reference of response + * @param otherText text if response is other + */ + void insertResponse(Long questionRef, Long responseRef, String otherText); + /** + * Get all user responses. + * @return number of responses + */ + int getNbUserResponses(); + /** + * Delete all rows in table. + */ + void deleteAll(); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java index 322dd2e..8c9f128 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.server.dao; @@ -25,25 +25,29 @@ public class UserResponsesDaoHibernate extends DaoHibernate<UserResponses> imple /** DAO for responses. */ private ResponsesDao responsesDao = new ResponsesDaoHibernate(); /** Default constructor. */ - public UserResponsesDaoHibernate() { - super(UserResponses.class); - } - @Override - public List<UserResponses> findAllByQuestion(final long questionRef) { - final String jpql = "SELECT u FROM UserResponses u WHERE u.question.questionRef = :ref"; - return super.findAllByJPQL(jpql, Map.of("ref", questionRef), UserResponses.class); - } + public UserResponsesDaoHibernate() { + super(UserResponses.class); + } + /** */ + @Override + public List<UserResponses> findAllByQuestion(final long questionRef) { + final String jpql = "SELECT u FROM UserResponses u WHERE u.question.questionRef = :ref"; + return super.findAllByJPQL(jpql, Map.of("ref", questionRef), UserResponses.class); + } + /** */ @Override public void insertResponse(final Question q, final Response r, final String otherText) { final UserResponses ur = new UserResponses(); - ur.setDateTime(Timestamp.valueOf(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()))); + ur.setDateTime(Timestamp.valueOf(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + .format(LocalDateTime.now()))); ur.setQuestion(q); ur.setResponse(r); ur.setOtherText(otherText); - + this.save(ur); } + /** */ @Override public void insertResponse(final Long questionRef, final Long responseRef, final String otherText) { // recherche de la question @@ -57,6 +61,7 @@ public class UserResponsesDaoHibernate extends DaoHibernate<UserResponses> imple } } } + /** */ @Override public int getNbUserResponses() { return super.findAll().size(); diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java index 0d2537a..fcbea50 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.server.model; @@ -20,19 +20,19 @@ import lombok.Data; @Entity @Table(name = "questions") public class Question { - /** PK. */ - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "question_ref") - private long questionRef; - /** - * Catogory of question. - */ - @Column(name = "category") - private String category; - /** - * Label of question. - */ - @Column(name = "fullname") - private String fullName; + /** PK. */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "question_ref") + private long questionRef; + /** + * Catogory of question. + */ + @Column(name = "category") + private String category; + /** + * Label of question. + */ + @Column(name = "fullname") + private String fullName; } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java index b87ec07..5e044c9 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.server.model; @@ -25,19 +25,19 @@ public class Response { /** * Reference of response. */ - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "response_ref") - private long responseRef; - /** - * Question related to response. - */ - @OneToOne - @JoinColumn(name = "question_ref") - private Question question; - /** - * Label of the response. - */ - @Column(name = "fullname") - private String fullname; + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "response_ref") + private long responseRef; + /** + * Question related to response. + */ + @OneToOne + @JoinColumn(name = "question_ref") + private Question question; + /** + * Label of the response. + */ + @Column(name = "fullname") + private String fullname; } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java index 5c5371b..4938f83 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java @@ -30,23 +30,23 @@ public class UserResponses { @Column(name = "user_response_ref") private long userResponseRef; /** Date time of user responses. */ - @Column(name = "datetime") - private Timestamp dateTime; - /** Related question. */ - @OneToOne - @JoinColumn(name = "question_ref") - private Question question; - /** - * Related response.<br> - * Can be null if it's a other response. - */ - @OneToOne - @JoinColumn(name = "response_ref") - private Response response; - /** - * Other text response.<br> - * Can be null if it's a related response. - */ - @Column(name = "other_text") - private String otherText; + @Column(name = "datetime") + private Timestamp dateTime; + /** Related question. */ + @OneToOne + @JoinColumn(name = "question_ref") + private Question question; + /** + * Related response.<br> + * Can be null if it's a other response. + */ + @OneToOne + @JoinColumn(name = "response_ref") + private Response response; + /** + * Other text response.<br> + * Can be null if it's a related response. + */ + @Column(name = "other_text") + private String otherText; } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java index 1a34f79..b5454cd 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.server.rs; @@ -98,7 +98,7 @@ public class LoginFormResource implements LoginFormService { @Inject private ResponsesDao responsesDao; /** - * DAO for user responses ({@link UserResponsesDao} + * DAO for user responses ({@link UserResponsesDao}. */ @Inject private UserResponsesDao userResponsesDao; @@ -118,8 +118,8 @@ public class LoginFormResource implements LoginFormService { final jakarta.ws.rs.core.Response.Status badRequest = jakarta.ws.rs.core.Response.Status.BAD_REQUEST; throw new WebApplicationException( jakarta.ws.rs.core.Response.status(badRequest).entity(ErrorResponseDTO.of( - badRequest.getStatusCode(), - badRequest.getReasonPhrase(), + badRequest.getStatusCode(), + badRequest.getReasonPhrase(), queryParamName + " parameter is mandatory") ).build()); } @@ -160,7 +160,6 @@ public class LoginFormResource implements LoginFormService { return responses; } return null; - } @GET @Path(LoginFormService.PATH_RESPONSES_LIST) @@ -179,8 +178,8 @@ public class LoginFormResource implements LoginFormService { @Produces(MediaType.TEXT_PLAIN) @Override public void insertResponse( - @FormParam(value = "questionRef") final Long questionRef, - @FormParam(value = "responseRef") final String responseRef, + @FormParam(value = "questionRef") final Long questionRef, + @FormParam(value = "responseRef") final String responseRef, @FormParam(value = "otherText") final String otherText) { this.checkRequired(questionRef, "questionRef"); final boolean responseRefIsNull = responseRef == null || responseRef.equals("null"); @@ -188,12 +187,16 @@ public class LoginFormResource implements LoginFormService { if (this.checkIfQuestionExist(questionRef)) { if (!responseRefIsNull && otherTextIsNull) { // réponse prédéfinie this.userResponsesDao.insertResponse(questionRef, Long.valueOf(responseRef), null); - } else if(responseRefIsNull && !otherTextIsNull) { // réponse libre + } else if (responseRefIsNull && !otherTextIsNull) { // réponse libre this.userResponsesDao.insertResponse(questionRef, null, otherText); } } } - + /** + * Check on database if reference of question exists. + * @param questionRef + * @return {@code true} if question exists or {@code false} otherwise + */ private boolean checkIfQuestionExist(final Long questionRef) { if (questionRef != null) { // on cherche dans le DAO @@ -213,10 +216,13 @@ public class LoginFormResource implements LoginFormService { // Insérer les réponses associés final Question q = toEntity(dto); final Long qRef = dto.getQuestionRef(); - List<ResponseDTO> associatedResponses = data.getResponses().stream().filter(f -> f.getQuestion().getQuestionRef() == qRef).collect(Collectors.toList()); + List<ResponseDTO> associatedResponses = data.getResponses() + .stream().filter(f -> f.getQuestion().getQuestionRef() == qRef) + .collect(Collectors.toList()); + // On insère les réponses prédéfinies for (final ResponseDTO rDto : associatedResponses) { - final Response r = toEntity(rDto); + final Response r = toEntity(rDto); this.userResponsesDao.insertResponse(q, r, null); } @@ -226,7 +232,7 @@ public class LoginFormResource implements LoginFormService { this.userResponsesDao.insertResponse(q, null, data.getOtherTextMap().get(q.getQuestionRef())); } } - + // une fois que tout est inséré, on envoi un mail au support this.mailService.sendLoginFilled(data); return "0"; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java index e752839..ce6cc68 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java @@ -10,6 +10,7 @@ import java.util.stream.Collectors; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -324,6 +325,10 @@ public class MailServiceImpl implements MailService { LOGGER.info("failed to send e-mail : {}", e); } } + /** + * Send an e-mail when user filled survey form. + * @param data data of survey + */ public void sendLoginFilled(final LoginFormDataDTO data) { final Mail mail = createContentFromData(data); mail.setSubject("Un utilisateur a rempli le formulaire d'enquête"); @@ -332,25 +337,31 @@ public class MailServiceImpl implements MailService { try { send(mail); } catch (AgroMetInfoException e) { - // en cas d'erreur, on ne fait rien de plus. - LOGGER.trace("failed to send e-mail"); + LOGGER.info("failed to send e-mail : {}", e); } - - }//*/ + } + /** + * Generate body e-mail with survey data.<br> + * Mail object returned is just a mail with content. + * @param data data of survey + * @return mail object + */ public static Mail createContentFromData(final LoginFormDataDTO data) { final Mail mail = new Mail(); - + final StringBuilder builder = new StringBuilder(); - builder.append("Bonjour,\nUn utilisateur vient de remplir le formulaire d'enquête d'AgroMetInfo à l'instant.\n\n"); + builder.append("Bonjour,\n"); + builder.append("Un utilisateur vient de remplir le formulaire d'enquête d'AgroMetInfo à l'instant.\\n\\n"); builder.append("Il a répondu à " + data.getQuestions().size() + " question(s) :\n"); - + data.getQuestions().forEach((q) -> { builder.append("\t• « " + q.getFullName() + " » :\n"); data.getResponses().stream().filter(f -> f.getQuestion().getQuestionRef() == q.getQuestionRef()) .collect(Collectors.toList()) .forEach((r) -> builder.append("\t\t- " + r.getFullname() + "\n")); - - if (data.getOtherTextMap().containsKey(q.getQuestionRef()) && data.getOtherTextMap().get(q.getQuestionRef()) != null) { + + if (data.getOtherTextMap().containsKey(q.getQuestionRef()) + && data.getOtherTextMap().get(q.getQuestionRef()) != null) { builder.append("\t\t- Réponse libre : « " + data.getOtherTextMap().get(q.getQuestionRef()) + " »\n"); } builder.append("\n"); diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java index e0d1d75..4bf7ab3 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java @@ -81,7 +81,7 @@ public class LoginFormResourceTest extends JerseyTest { // do nothing } - }; + } /** Path separator. */ private static final String SEP = "/"; /** Parsing JSON to object. */ diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java index 0d2cefc..30493a8 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.shared.dto; @@ -31,7 +31,6 @@ public class LoginFormDataDTO { * Default constructor. */ public LoginFormDataDTO() { - } /** * Constructor. @@ -39,7 +38,8 @@ public class LoginFormDataDTO { * @param rList responses list * @param otherText otherText map */ - public LoginFormDataDTO(final List<QuestionDTO> qList, final List<ResponseDTO> rList, HashMap<Long, String> otherText) { + public LoginFormDataDTO(final List<QuestionDTO> qList, + final List<ResponseDTO> rList, final HashMap<Long, String> otherText) { this.questions = qList; this.responses = rList; this.otherTextMap = otherText; @@ -63,22 +63,21 @@ public class LoginFormDataDTO { return otherTextMap; } /** - * @param questions the questions to set + * @param questionsList the questions to set */ - public void setQuestions(List<QuestionDTO> questions) { - this.questions = questions; + public void setQuestions(final List<QuestionDTO> questionsList) { + this.questions = questionsList; } /** - * @param responses the responses to set + * @param responsesList the responses to set */ - public void setResponses(List<ResponseDTO> responses) { - this.responses = responses; + public void setResponses(final List<ResponseDTO> responsesList) { + this.responses = responsesList; } /** - * @param otherTextMap the otherTextMap to set + * @param map the otherTextMap to set */ - public void setOtherTextMap(HashMap<Long, String> otherTextMap) { - this.otherTextMap = otherTextMap; + public void setOtherTextMap(final HashMap<Long, String> map) { + this.otherTextMap = map; } - } diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java index 3028802..60de95d 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.shared.dto; @@ -45,29 +45,31 @@ public class QuestionDTO { return fullName; } /** - * @param questionRef the questionRef to set + * @param value the questionRef to set */ - public void setQuestionRef(final long questionRef) { - this.questionRef = questionRef; + public void setQuestionRef(final long value) { + this.questionRef = value; } /** - * @param category the category to set + * @param value the category to set */ - public void setCategory(final String category) { - this.category = category; + public void setCategory(final String value) { + this.category = value; } /** - * @param fullName the fullName to set + * @param value the fullName to set */ - public void setFullName(final String fullName) { - this.fullName = fullName; + public void setFullName(final String value) { + this.fullName = value; } + /** */ @Override public int hashCode() { return Objects.hash(category, fullName, questionRef); } + /** */ @Override - public boolean equals(Object obj) { + public boolean equals(final Object obj) { if (this == obj) { return true; } @@ -81,5 +83,4 @@ public class QuestionDTO { return Objects.equals(category, other.category) && Objects.equals(fullName, other.fullName) && questionRef == other.questionRef; } - } diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java index f52837f..f1e86aa 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.shared.dto; @@ -43,22 +43,21 @@ public class ResponseDTO { return fullname; } /** - * @param responseRef the responseRef to set + * @param value the responseRef to set */ - public void setResponseRef(final long responseRef) { - this.responseRef = responseRef; + public void setResponseRef(final long value) { + this.responseRef = value; } /** - * @param question the question to set + * @param dto the question to set */ - public void setQuestion(final QuestionDTO question) { - this.question = question; + public void setQuestion(final QuestionDTO dto) { + this.question = dto; } /** - * @param fullname the fullname to set + * @param value the fullname to set */ - public void setFullname(final String fullname) { - this.fullname = fullname; + public void setFullname(final String value) { + this.fullname = value; } - } diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java index 4c04cc0..94083e2 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java @@ -1,5 +1,5 @@ /** - * + * */ package fr.agrometinfo.www.shared.service; @@ -56,7 +56,7 @@ public interface LoginFormService { */ @GET @Path(PATH_QUESTION_BY_CATEGORY) - QuestionDTO getQuestionByCategory(@QueryParam(value = "category") final String category); + QuestionDTO getQuestionByCategory(@QueryParam(value = "category") String category); /** * Returning the list of possible response for one question. * @param questionRef ref of question @@ -64,29 +64,28 @@ public interface LoginFormService { */ @GET @Path(PATH_RESPONSES_BY_QUESTION_LIST) - List<ResponseDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") final Long questionRef); + List<ResponseDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") Long questionRef); /** * Insert response or text for specified question.<br> * If responseRef is provided, {@code otherText} must be null.<br> - * If otherText is provided, {@code responseRef} must be null. + * If otherText is provided, {@code responseRef} must be null. * @param questionRef ref of question * @param responseRef ref of response or « null » String for null value * @param otherText text if response is other - * - * @return */ @POST @Path(PATH_INSERT_RESPONSE) void insertResponse( - @FormParam(value = "questionRef") final Long questionRef, - @FormParam(value = "responseRef") @DefaultValue("null") final String responseRef, - @FormParam(value = "otherText") @DefaultValue("null") final String otherText + @FormParam(value = "questionRef") Long questionRef, + @FormParam(value = "responseRef") @DefaultValue("null") String responseRef, + @FormParam(value = "otherText") @DefaultValue("null") String otherText ); /** * Insert all responses of login form. - * @param responsesList + * @param data object to insert + * @return return code */ @POST @Path(PATH_INSERT_RESPONSE_WITH_JSON) - String insertAllResponses(@RequestBody final LoginFormDataDTO data); + String insertAllResponses(@RequestBody LoginFormDataDTO data); } -- GitLab From eab03e1e27cefae59e49cd6c96ce81e858178222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Fri, 24 May 2024 14:03:50 +0200 Subject: [PATCH 05/30] =?UTF-8?q?Ajout=20du=20texte=20de=20pr=C3=A9sentati?= =?UTF-8?q?on.=20Corrections=20suite=20revue=20de=20code=20d'Olivier=20fix?= =?UTF-8?q?es=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fr/agrometinfo/www/client/style.css | 208 ------------------ 1 file changed, 208 deletions(-) delete mode 100644 www-client/src/main/resources/fr/agrometinfo/www/client/style.css diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/style.css deleted file mode 100644 index bdd54e8..0000000 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/style.css +++ /dev/null @@ -1,208 +0,0 @@ -footer { - background-color: #353854; -} -footer.footer { - max-height: 2em; - min-height: 2em; - text-align: center; - margin-left: auto; - margin-right: auto; -} -footer, footer a { - color: #b5b5c8; - font-weight: bold; - margin-right: 1em; - padding: 0.3em; -} -footer a:hover { - color: #ffffff; -} -select { - width: 100%; - height: 2.5em; - font-size: 1.1em; -} -/** - * Font awesome icons. - */ -/*! - * Font Awesome Free 5.5.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - */ -@font-face { - font-family:"Font Awesome 5 Free"; - font-style:normal; - font-weight:900; - src:url(vendors/fa/fa-solid-900.eot); - src:url(vendors/fa/fa-solid-900.eot?#iefix) format("embedded-opentype"), - url(vendors/fa/fa-solid-900.woff2) format("woff2"), - url(vendors/fa/fa-solid-900.woff) format("woff"), - url(vendors/fa/fa-solid-900.ttf) format("truetype"), - url(vendors/fa/fa-solid-900.svg#fontawesome) format("svg") -} -.fa, .fab, .fal, .far, .fas { - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - display: inline-block; - font-style: normal; - font-variant: normal; - text-rendering: auto; - line-height: 1; -} -.fa, .fas { - font-family: "Font Awesome 5 Free"; - font-weight: 900; -} -.fa-cloud-showers-heavy::before { - content: "\f740"; -} -.fa-snowflake::before { - content: "\f2dc"; -} -.fa-thermometer-half::before { - content: "\f2c9"; -} -.fa-thermometer-quarter::before { - content: "\f2ca"; -} -.fa-thermometer-three-quarters::before { - content: "\f2c8"; -} -.agroclim-apps img { - height: 60px; - width: 60px; -} -.agroclim-apps ul { - box-sizing: content-box; - width: 200px; -} -.agroclim-apps.dom-ui.menu .simple-menu-item { - display: inline-block; - padding-bottom: 15px; - text-align: center; - width: 100px; -} -.agrometinfo-navbar .navbar-header { - min-height: var(--logo-height); - padding-top: 0px; -} -.agrometinfo-navbar .navbar-header .menu-toggle .bars { - line-height: 15px; -} -.agrometinfo-leftsidebar.sidebar, -.agrometinfo-rightsidebar.right-sidebar { - height: calc(100vh - var(--logo-height)); - top: var(--logo-height); -} -.agrometinfo-rightsidebar.right-sidebar { - width: var(--rightsidebar-width); -} -.agrometinfo-rightsidebar.right-sidebar.slide-out-right { - right: calc(-1 * var(--rightsidebar-width)); -} -.agrometinfo-topbar.navbar { - border: 0px; -} -.agrometinfo-topbar.navbar-nav > li > a { - padding-bottom: 6px; - padding-top: 6px; -} -.float-right { - float: right; -} -div.idp { - padding: 0.5em; -} -.idp img { - padding-right: 1em; -} -.idp span { - font-weight: bold; -} -.indicator-categories > i { - font-size: 40px; - padding-left: 5px; -} -.javascript-disabled { - width: 22em; - position: absolute; - left: 50%; - margin-left: -11em; - color: red; - background-color: white; - border: 1px solid red; - padding: 4px; - font-family: sans-serif -} -.logo-in img { - background-color: white; - height: var(--logo-height); -} -#mapContainer .ol-attribution.ol-uncollapsible { - top: auto; - right: auto; - bottom: 0.2em; - right: .5em; -} -#mapContainer .ol-control button { - /* same as layer switcher */ - height: 38px; - width: 38px; -} -#mapContainer .ol-full-screen { - top: .5em; - right: .5em; - bottom: auto; - left: auto; -} -#mapContainer .layer-switcher { - top: 3.5em; - right: .5em; - bottom: auto; - left: auto; -} -#mapContainer .ol-zoom-extent { - top: auto; - bottom: 8em; - right: .5em; - left: auto; -} -#mapContainer .ol-zoom { - top: auto; - bottom: 2em; - right: .5em; - left: auto; -} -:root { - --logo-height: 50px; -} -@media screen and (max-width: 450px) { - .navbar-brand { - display: none; - } -} -@media screen and (max-width: 700px) { - :root { - --rightsidebar-width: 90%; - } -} -@media screen and (min-width: 700px) { - :root { - --rightsidebar-width: 400px; - } -} - -/* Formulaire d'enquête */ -.login-paragraph { - font-size: 18px; -} -.login-checkbox { - margin: 0 0 2px 5px; -} -.login-checkbox .field-cntr { - padding: 0 10px !important; -} -.login-checkbox label { - top: 0px !important; - margin-bottom: 0px !important; -} -- GitLab From 07a4f73a13c5530048b67f8cc78db0e03a933744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Fri, 24 May 2024 14:08:13 +0200 Subject: [PATCH 06/30] Checkstyle --- pom.xml | 1 + .../main/java/fr/agrometinfo/www/client/view/LoginView.java | 5 ++++- .../agrometinfo/www/client/i18n/AppConstants_fr.properties | 6 +++--- .../resources/fr/agrometinfo/www/client/public/style.css | 2 +- .../fr/agrometinfo/www/server/rs/LoginFormResource.java | 4 ++-- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 5cfaed5..ee1f2a4 100644 --- a/pom.xml +++ b/pom.xml @@ -433,6 +433,7 @@ <failOnViolation>true</failOnViolation> <propertyExpansion>basedir=${project.basedir}</propertyExpansion> <violationSeverity>warning</violationSeverity> + <consoleOutput>true</consoleOutput> </configuration> </plugin> <plugin> diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java index ab0502c..a4b9431 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java @@ -11,6 +11,7 @@ import org.dominokit.domino.ui.forms.CheckBox; import org.dominokit.domino.ui.forms.TextArea; import org.dominokit.domino.ui.modals.ModalDialog; import org.dominokit.rest.shared.request.FailedResponseBean; +import org.gwtproject.safehtml.shared.SafeHtmlBuilder; import org.jboss.elemento.Elements; import com.google.gwt.core.client.GWT; @@ -72,7 +73,9 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements this.modal = ModalDialog.create(CSTS.loginFormTitle()).large().setAutoClose(true); this.modal - .appendChild(Elements.p().textContent(CSTS.loginFormDescription()).css("login-paragraph")); + .appendChild(Elements.p() + .innerHtml(new SafeHtmlBuilder().appendHtmlConstant(CSTS.loginFormDescription()).toSafeHtml()) + ); for (Map.Entry<QuestionDTO, List<ResponseDTO>> entry : this.availableResponses.entrySet()) { final QuestionDTO k = entry.getKey(); // Pour chaque question diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties index 685c04a..e68475e 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties @@ -54,8 +54,8 @@ whyConnectionIsRequired = Vous devez vous identifier pour accéder à AgroMetInf validate = Valider ignore = Ignorer loginFormTitle = Formulaire d'enquête -loginFormDescription = Merci de compléter ce formulaire d'enquête afin de continuer sur AgroMetInfo +loginFormDescription = Bienvenu.e.s à la nouvelle version d'AgroMetInfo !<br/>Afin de nous aider à la faire évoluer et l'adapter le plus possible à vos besoins, <b>merci de renseigner</b> la petite enquête çi dessous. L'ensemble des informations est anonyme, mais nous aidera à mieux comprendre l'utilisation de l'application. N'hésitez pas à <b>nous laisser votre adresse courriel</b> pour vous tenir informés de toutes les évolutions dans les mois et années à venir.<br/><br/>L'équipe AgroMetInfo. loginFormOtherTextCheckbox = Autre, à préciser -loginFormOtherTextTooltip = Vous devez cliquer sur la case à cocher ci-dessus pour activer ce champ de saisie. +loginFormOtherTextTooltip = Vous devez cliquer sur la case à cocher çi dessus pour activer ce champ de saisie. loginFormSuccess = Vos réponses au formulaire d'enquête ont bien été enregistrées. -loginFormFail = Vos réponses au formulaire n'ont pas pu être, mais vous pouvez tout de même utiliser AgroMetInfo. \ No newline at end of file +loginFormFail = Vos réponses au formulaire n'ont pas pu être enregistrées, mais vous pouvez tout de même utiliser AgroMetInfo. \ No newline at end of file diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css index 1cf0b4c..4dac15b 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/public/style.css @@ -351,7 +351,7 @@ body > .modal-backdrop { /* Formulaire d'enquête */ .login-paragraph { - font-size: 18px; + font-size: 15px; } .login-checkbox { margin: 0 0 2px 5px; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java index b5454cd..ef3dac4 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java @@ -44,7 +44,7 @@ public class LoginFormResource implements LoginFormService { * @param question entity * @return dto */ - public static QuestionDTO toDto(final Question question) { + static QuestionDTO toDto(final Question question) { final QuestionDTO dto = new QuestionDTO(); dto.setQuestionRef(question.getQuestionRef()); dto.setCategory(question.getCategory()); @@ -56,7 +56,7 @@ public class LoginFormResource implements LoginFormService { * @param response entity * @return dto */ - public static ResponseDTO toDto(final Response response) { + static ResponseDTO toDto(final Response response) { final ResponseDTO dto = new ResponseDTO(); dto.setResponseRef(response.getResponseRef()); dto.setQuestion(toDto(response.getQuestion())); -- GitLab From 7b37f5d65985be947a7816a7f92eb1ac87ed1999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Fri, 24 May 2024 15:48:29 +0200 Subject: [PATCH 07/30] =?UTF-8?q?Texte=20de=20pr=C3=A9sentation=20en=20ang?= =?UTF-8?q?lais.=20fixes=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/fr/agrometinfo/www/client/i18n/AppConstants.java | 8 +++++++- .../www/client/i18n/AppConstants_fr.properties | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java index 474fe81..0c09cec 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java @@ -358,7 +358,13 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo /** * @return translation */ - @DefaultStringValue("Please complete this survey form to continue on AgroMetInfo.") + @DefaultStringValue("Welcome to the new version of AgroMetInfo !<br/>" + + "To help us improve the application and make it as responsive as possible to your needs, " + + "<b>please fill in the short survey below</b> (it will take 2 minutes maximum).<br/>" + + "All information is anonymous, but will help us to better understand how you use the application." + + "<br/><b>Don't hesitate to give us your email address</b> " + + "so that we can keep you informed of all developments in the coming months and years." + + "<br/><br/>The AgroMetInfo development team") String loginFormDescription(); /** * @return translation diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties index e68475e..fe21225 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties @@ -54,7 +54,7 @@ whyConnectionIsRequired = Vous devez vous identifier pour accéder à AgroMetInf validate = Valider ignore = Ignorer loginFormTitle = Formulaire d'enquête -loginFormDescription = Bienvenu.e.s à la nouvelle version d'AgroMetInfo !<br/>Afin de nous aider à la faire évoluer et l'adapter le plus possible à vos besoins, <b>merci de renseigner</b> la petite enquête çi dessous. L'ensemble des informations est anonyme, mais nous aidera à mieux comprendre l'utilisation de l'application. N'hésitez pas à <b>nous laisser votre adresse courriel</b> pour vous tenir informés de toutes les évolutions dans les mois et années à venir.<br/><br/>L'équipe AgroMetInfo. +loginFormDescription = Bienvenu.e.s à la nouvelle version d'AgroMetInfo !<br/>Afin de nous aider à la faire évoluer et l'adapter le plus possible à vos besoins, <b>merci de renseigner</b> la petite enquête çi dessous (cela prendra 2 minutes maximum). L'ensemble des informations est anonyme, mais nous aidera à mieux comprendre l'utilisation de l'application. N'hésitez pas à <b>nous laisser votre adresse courriel</b> pour vous tenir informés de toutes les évolutions dans les mois et années à venir.<br/><br/>L'équipe AgroMetInfo. loginFormOtherTextCheckbox = Autre, à préciser loginFormOtherTextTooltip = Vous devez cliquer sur la case à cocher çi dessus pour activer ce champ de saisie. loginFormSuccess = Vos réponses au formulaire d'enquête ont bien été enregistrées. -- GitLab From 3b7b610a8a8dbee44fcb237f888b6e40c61a572b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Fri, 24 May 2024 16:24:17 +0200 Subject: [PATCH 08/30] Suite revue de code d'Olivier (23/05/2024) : - Commentaires SQL en anglais - Nom des tables au singulier --- .../www/server/model/{UserResponses.java => UserResponse.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename www-server/src/main/java/fr/agrometinfo/www/server/model/{UserResponses.java => UserResponse.java} (100%) diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java similarity index 100% rename from www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponses.java rename to www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java -- GitLab From 8e2fdf6d82c7fd5aad4045473629036936b702cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Mon, 27 May 2024 09:26:30 +0200 Subject: [PATCH 09/30] Renommer les tables au singulier Commentaires en anglais --- sql/init_data.h2.sql | 4 +-- sql/init_data.postgresql.sql | 8 +++--- sql/schema.tables.sql | 26 ++++++++++--------- .../www/server/dao/UserResponsesDao.java | 4 +-- .../server/dao/UserResponsesDaoHibernate.java | 14 +++++----- .../www/server/model/Question.java | 2 +- .../www/server/model/Response.java | 2 +- .../www/server/model/UserResponse.java | 5 ++-- .../www/server/LoginFormHibernateTest.java | 10 +++---- .../www/server/rs/LoginFormResourceTest.java | 12 ++++----- .../test/resources/META-INF/persistence.xml | 2 +- 11 files changed, 45 insertions(+), 44 deletions(-) diff --git a/sql/init_data.h2.sql b/sql/init_data.h2.sql index 6095f2c..f994c42 100644 --- a/sql/init_data.h2.sql +++ b/sql/init_data.h2.sql @@ -127,9 +127,9 @@ INSERT INTO simulation (date, simulationid, started, ended) VALUES -- REFRESH MATERIALIZED VIEW v_pra_dailyvalue; -INSERT INTO questions(question_ref, category, fullname) +INSERT INTO question(question_ref, category, fullname) SELECT * FROM CSVREAD('../sql/questions.csv'); -INSERT INTO responses(question_ref, fullname) +INSERT INTO response(question_ref, fullname) SELECT * FROM CSVREAD('../sql/responses.csv', null, 'fieldSeparator=;'); diff --git a/sql/init_data.postgresql.sql b/sql/init_data.postgresql.sql index 056f7c5..b63281d 100644 --- a/sql/init_data.postgresql.sql +++ b/sql/init_data.postgresql.sql @@ -11,8 +11,8 @@ DELETE FROM period; DELETE FROM i18n; DELETE FROM i18nkey; DELETE FROM locale; -DELETE FROM questions; -DELETE FROM responses; +DELETE FROM question; +DELETE FROM response; -- translations CREATE TEMPORARY TABLE IF NOT EXISTS tmp_translation ( @@ -170,9 +170,9 @@ INSERT INTO normalvalue (indicator, cell, doy, medianvalue, q5, q95) ON CONFLICT ON CONSTRAINT "UK_normalvalue" DO NOTHING; -- questions -\COPY questions(question_ref, category, fullname) FROM questions.csv WITH DELIMITER ',' HEADER CSV; +\COPY question(question_ref, category, fullname) FROM questions.csv WITH DELIMITER ',' HEADER CSV; -- responses -- WARNING : responses CSV file use semicolon (« ; ») as separator !! -\COPY responses(question_ref, fullname) FROM sql/responses.csv WITH DELIMITER ';' HEADER CSV; +\COPY response(question_ref, fullname) FROM responses.csv WITH DELIMITER ';' HEADER CSV; diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql index a469a08..fdeb30b 100644 --- a/sql/schema.tables.sql +++ b/sql/schema.tables.sql @@ -214,33 +214,35 @@ CREATE TABLE IF NOT EXISTS dailyvisit( ); COMMENT ON TABLE dailyvisit IS 'Number of visits per day.'; --- Tables pour le formulaire d'enquête -CREATE TABLE IF NOT EXISTS questions ( +-- Tables for survey form - #5 +CREATE TABLE IF NOT EXISTS question ( question_ref serial NOT NULL, category varchar(20) NOT NULL, fullname varchar(255) NULL, - CONSTRAINT questions_pk PRIMARY KEY (question_ref) + CONSTRAINT question_pk PRIMARY KEY (question_ref) ); -COMMENT ON TABLE questions IS 'Questions pour le formulaire d''enquête'; +COMMENT ON TABLE question IS 'Questions for survey form'; -CREATE TABLE IF NOT EXISTS responses ( +CREATE TABLE IF NOT EXISTS response ( response_ref serial NOT NULL, question_ref int4 NOT NULL, fullname varchar NULL, - CONSTRAINT responses_pk PRIMARY KEY (response_ref), - CONSTRAINT responses_questions_fk FOREIGN KEY (question_ref) REFERENCES questions(question_ref) + CONSTRAINT response_pk PRIMARY KEY (response_ref), + CONSTRAINT response_question_fk FOREIGN KEY (question_ref) REFERENCES question(question_ref) ); -CREATE TABLE IF NOT EXISTS user2responses ( +COMMENT ON TABLE response IS 'Options responses for questions.'; + +CREATE TABLE IF NOT EXISTS user2response ( user_response_ref serial NOT NULL, datetime timestamp NOT NULL, question_ref int4 NOT NULL, response_ref int4 NULL, other_text varchar NULL, - CONSTRAINT user2responses_pk PRIMARY KEY (user_response_ref), - CONSTRAINT user2responses_questions_fk FOREIGN KEY (question_ref) REFERENCES questions(question_ref), - CONSTRAINT user2responses_responses_fk FOREIGN KEY (response_ref) REFERENCES responses(response_ref) + CONSTRAINT user2response_pk PRIMARY KEY (user_response_ref), + CONSTRAINT user2response_question_fk FOREIGN KEY (question_ref) REFERENCES question(question_ref), + CONSTRAINT user2response_response_fk FOREIGN KEY (response_ref) REFERENCES response(response_ref) ); -COMMENT ON TABLE user2responses IS 'Réponses des utilisateurs'; +COMMENT ON TABLE user2response IS 'Responses of user to questions, and other text if present'; CREATE OR REPLACE VIEW v_i18n diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java index d45e51d..06260f1 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java @@ -4,7 +4,7 @@ import java.util.List; import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; -import fr.agrometinfo.www.server.model.UserResponses; +import fr.agrometinfo.www.server.model.UserResponse; /** * DAO for {@link UserResponsesDao}. * @author jdecome @@ -15,7 +15,7 @@ public interface UserResponsesDao { * @param questionRef * @return list of user's responses */ - List<UserResponses> findAllByQuestion(long questionRef); + List<UserResponse> findAllByQuestion(long questionRef); /** * Insert response or text for specified question.<br> * If r is provided, {@code otherText} must be null.<br> diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java index 8c9f128..9baf80b 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java @@ -11,7 +11,7 @@ import java.util.Map; import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; -import fr.agrometinfo.www.server.model.UserResponses; +import fr.agrometinfo.www.server.model.UserResponse; import jakarta.enterprise.context.ApplicationScoped; /** @@ -19,25 +19,25 @@ import jakarta.enterprise.context.ApplicationScoped; * */ @ApplicationScoped -public class UserResponsesDaoHibernate extends DaoHibernate<UserResponses> implements UserResponsesDao { +public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implements UserResponsesDao { /** DAO for questions. */ private QuestionsDao questionsDao = new QuestionsDaoHibernate(); /** DAO for responses. */ private ResponsesDao responsesDao = new ResponsesDaoHibernate(); /** Default constructor. */ public UserResponsesDaoHibernate() { - super(UserResponses.class); + super(UserResponse.class); } /** */ @Override - public List<UserResponses> findAllByQuestion(final long questionRef) { - final String jpql = "SELECT u FROM UserResponses u WHERE u.question.questionRef = :ref"; - return super.findAllByJPQL(jpql, Map.of("ref", questionRef), UserResponses.class); + public List<UserResponse> findAllByQuestion(final long questionRef) { + final String jpql = "SELECT u FROM UserResponse u WHERE u.question.questionRef = :ref"; + return super.findAllByJPQL(jpql, Map.of("ref", questionRef), UserResponse.class); } /** */ @Override public void insertResponse(final Question q, final Response r, final String otherText) { - final UserResponses ur = new UserResponses(); + final UserResponse ur = new UserResponse(); ur.setDateTime(Timestamp.valueOf(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") .format(LocalDateTime.now()))); ur.setQuestion(q); diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java index fcbea50..57da32f 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java @@ -18,7 +18,7 @@ import lombok.Data; */ @Data @Entity -@Table(name = "questions") +@Table(name = "question") public class Question { /** PK. */ @Id diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java index 5e044c9..c48ef5c 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java @@ -20,7 +20,7 @@ import lombok.Data; */ @Data @Entity -@Table(name = "responses") +@Table(name = "response") public class Response { /** * Reference of response. diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java index 4938f83..1193939 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java @@ -18,12 +18,11 @@ import lombok.Data; /** * User's responses values. * @author jdecome - * */ @Data @Entity -@Table(name = "user2responses") -public class UserResponses { +@Table(name = "user2response") +public class UserResponse { /** Primary key. */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java index eba1d30..33d3395 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java @@ -24,7 +24,7 @@ import fr.agrometinfo.www.server.dao.UserResponsesDao; import fr.agrometinfo.www.server.dao.UserResponsesDaoHibernate; import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; -import fr.agrometinfo.www.server.model.UserResponses; +import fr.agrometinfo.www.server.model.UserResponse; /** * Test of UserResponsesDaoHibernate. @@ -100,7 +100,7 @@ public class LoginFormHibernateTest { userResponsesDao.insertResponse(profession, r, null); listOfResponses.add(r); - List<UserResponses> list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); + List<UserResponse> list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur doit contenir un élément"); assertEquals(list.get(0).getQuestion(), profession, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); assertEquals(list.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); @@ -114,7 +114,7 @@ public class LoginFormHibernateTest { } list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); assertEquals(list.size(), (1 + nbToInsert), "La liste de réponses de l'utilisateur doit contenir la réponse précédente + " + nbToInsert + " réponses supplémentaires"); - for (final UserResponses ur : list) { + for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question"); assertTrue(listOfResponses.contains(ur.getResponse()), "La réponse contenue dans la réponse de l'utilisateur n'est pas dans la liste des réponses insérées"); assertEquals(ur.getResponse().getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); @@ -129,7 +129,7 @@ public class LoginFormHibernateTest { list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); assertEquals(list.size(), (newNbResponses + 1), "La liste de réponses de l'utilisateur doit contenir les " + newNbResponses + " + la réponse libre"); - for (final UserResponses ur : list) { + for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); if (ur.getOtherText() != null) { // on est sur une réponse libre assertNull(ur.getResponse(), "L'objet response doit être null si il s'agit d'une réponse libre"); @@ -161,7 +161,7 @@ public class LoginFormHibernateTest { list = userResponsesDao.findAllByQuestion(useCase.getQuestionRef()); assertEquals(list.size(), 2, "La liste de réponses de l'utilisateur pour la question « useCase » doit contenir deux éléments"); - for (final UserResponses ur : list) { + for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); if (ur.getOtherText() != null) { // on est sur une réponse libre assertNull(ur.getResponse(), "L'objet response doit être null si il s'agit d'une réponse libre"); diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java index 4bf7ab3..3ec6678 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java @@ -35,7 +35,7 @@ import fr.agrometinfo.www.server.dao.UserResponsesDaoHibernate; import fr.agrometinfo.www.server.exception.AgroMetInfoException; import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; -import fr.agrometinfo.www.server.model.UserResponses; +import fr.agrometinfo.www.server.model.UserResponse; import fr.agrometinfo.www.server.service.MailService; import fr.agrometinfo.www.server.service.MailServiceImpl; import fr.agrometinfo.www.server.service.MailServiceImpl.Mail; @@ -221,7 +221,7 @@ public class LoginFormResourceTest extends JerseyTest { listOfResponses.add(r); // On lit la réponse insérée, via le DAO - List<UserResponses> userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); + List<UserResponse> userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); assertEquals(userResponsesList.size(), 1, "La liste de réponses de l'utilisateur doit contenir un élément"); assertEquals(userResponsesList.get(0).getQuestion(), origin, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); assertEquals(userResponsesList.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); @@ -247,7 +247,7 @@ public class LoginFormResourceTest extends JerseyTest { userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); assertEquals(userResponsesList.size(), (1 + nbToInsert), "La liste de réponses de l'utilisateur doit contenir la réponse précédente + " + nbToInsert + " réponses supplémentaires"); - for (final UserResponses ur : userResponsesList) { + for (final UserResponse ur : userResponsesList) { assertEquals(ur.getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question"); assertTrue(listOfResponses.contains(ur.getResponse()), "La réponse contenue dans la réponse de l'utilisateur n'est pas dans la liste des réponses insérées"); assertEquals(ur.getResponse().getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); @@ -270,7 +270,7 @@ public class LoginFormResourceTest extends JerseyTest { userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); assertEquals(userResponsesList.size(), (newNbResponses + 1), "La liste de réponses de l'utilisateur doit contenir les " + newNbResponses + " réponses + la réponse libre"); - for (final UserResponses ur : userResponsesList) { + for (final UserResponse ur : userResponsesList) { assertEquals(ur.getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); if (ur.getOtherText() != null) { // on est sur une réponse libre assertNull(ur.getResponse(), "L'objet response doit être null si il s'agit d'une réponse libre"); @@ -322,9 +322,9 @@ public class LoginFormResourceTest extends JerseyTest { // Pour le test, vérifier, pour chaque question, les réponses via le DAO for (final Question q : questionsDao.findAll()) { - final List<UserResponses> list = userResponsesDao.findAllByQuestion(q.getQuestionRef()); + final List<UserResponse> list = userResponsesDao.findAllByQuestion(q.getQuestionRef()); assertNotNull(list, "La liste de réponses de l'utilisateur ne doit pas être null"); - for (final UserResponses ur : list) { + for (final UserResponse ur : list) { assertNotNull(ur.getDateTime(), "Le timestamp de la réponse ne doit pas être null"); assertEquals(ur.getQuestion(), q, "La question contenue dans la réponse ne correspond pas avec la question d'origine « " + q.getFullName() + " »"); assertTrue(ur.getUserResponseRef() > 0, "la référence de la réponse de l'utilisateur doit être supérieur à 0"); diff --git a/www-server/src/test/resources/META-INF/persistence.xml b/www-server/src/test/resources/META-INF/persistence.xml index e0622b5..d790ccb 100644 --- a/www-server/src/test/resources/META-INF/persistence.xml +++ b/www-server/src/test/resources/META-INF/persistence.xml @@ -20,7 +20,7 @@ <class>fr.agrometinfo.www.server.model.Simulation</class> <class>fr.agrometinfo.www.server.model.Question</class> <class>fr.agrometinfo.www.server.model.Response</class> - <class>fr.agrometinfo.www.server.model.UserResponses</class> + <class>fr.agrometinfo.www.server.model.UserResponse</class> <properties> <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:agrometinfo;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM '../sql/schema.types.h2.sql'\;RUNSCRIPT FROM '../sql/schema.tables.sql'\;RUNSCRIPT FROM '../sql/init_data.h2.sql';" /> <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver" /> -- GitLab From 571049a604c175f0ad1cfe47e9829e603928273d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Mon, 27 May 2024 11:50:59 +0200 Subject: [PATCH 10/30] Renommer les colonnes des tables --- sql/init_data.h2.sql | 4 +- sql/init_data.postgresql.sql | 4 +- sql/questions.csv | 2 +- sql/responses.csv | 2 +- sql/schema.tables.sql | 34 +++++----- .../www/client/presenter/LoginPresenter.java | 4 +- .../www/client/view/LoginView.java | 6 +- .../www/server/dao/ResponsesDaoHibernate.java | 2 +- .../server/dao/UserResponsesDaoHibernate.java | 2 +- .../www/server/model/Question.java | 13 ++-- .../www/server/model/Response.java | 13 ++-- .../www/server/model/UserResponse.java | 8 +-- .../www/server/rs/LoginFormResource.java | 26 ++++---- .../www/server/service/MailServiceImpl.java | 12 ++-- .../www/server/LoginFormHibernateTest.java | 40 ++++++------ .../www/server/rs/LoginFormResourceTest.java | 64 +++++++++---------- .../www/shared/dto/QuestionDTO.java | 26 ++++---- .../www/shared/dto/ResponseDTO.java | 20 +++--- 18 files changed, 143 insertions(+), 139 deletions(-) diff --git a/sql/init_data.h2.sql b/sql/init_data.h2.sql index f994c42..74219fe 100644 --- a/sql/init_data.h2.sql +++ b/sql/init_data.h2.sql @@ -127,9 +127,9 @@ INSERT INTO simulation (date, simulationid, started, ended) VALUES -- REFRESH MATERIALIZED VIEW v_pra_dailyvalue; -INSERT INTO question(question_ref, category, fullname) +INSERT INTO question(id, category, description) SELECT * FROM CSVREAD('../sql/questions.csv'); -INSERT INTO response(question_ref, fullname) +INSERT INTO response(question, description) SELECT * FROM CSVREAD('../sql/responses.csv', null, 'fieldSeparator=;'); diff --git a/sql/init_data.postgresql.sql b/sql/init_data.postgresql.sql index b63281d..d53ac68 100644 --- a/sql/init_data.postgresql.sql +++ b/sql/init_data.postgresql.sql @@ -170,9 +170,9 @@ INSERT INTO normalvalue (indicator, cell, doy, medianvalue, q5, q95) ON CONFLICT ON CONSTRAINT "UK_normalvalue" DO NOTHING; -- questions -\COPY question(question_ref, category, fullname) FROM questions.csv WITH DELIMITER ',' HEADER CSV; +\COPY question(id, category, description) FROM questions.csv WITH DELIMITER ',' HEADER CSV; -- responses -- WARNING : responses CSV file use semicolon (« ; ») as separator !! -\COPY response(question_ref, fullname) FROM responses.csv WITH DELIMITER ';' HEADER CSV; +\COPY response(question, description) FROM responses.csv WITH DELIMITER ';' HEADER CSV; diff --git a/sql/questions.csv b/sql/questions.csv index faac491..927f34e 100644 --- a/sql/questions.csv +++ b/sql/questions.csv @@ -1,4 +1,4 @@ -question_ref,category,fullname +id,category,description 1,profession,Quelle est votre profession ? 2,origin,Comment avez-vous connu AgroMetInfo ? 3,useCase,Dans quel but voulez-vous utiliser cette application ? diff --git a/sql/responses.csv b/sql/responses.csv index a88a2c0..930e6f7 100644 --- a/sql/responses.csv +++ b/sql/responses.csv @@ -1,4 +1,4 @@ -question_ref;fullname +question;description 1;Agriculteur 1;Conseiller agricole (Chambre d'agriculture, Entreprise de service) 1;Scientifique diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql index fdeb30b..c4a57a7 100644 --- a/sql/schema.tables.sql +++ b/sql/schema.tables.sql @@ -216,31 +216,31 @@ COMMENT ON TABLE dailyvisit IS 'Number of visits per day.'; -- Tables for survey form - #5 CREATE TABLE IF NOT EXISTS question ( - question_ref serial NOT NULL, - category varchar(20) NOT NULL, - fullname varchar(255) NULL, - CONSTRAINT question_pk PRIMARY KEY (question_ref) + id SERIAL NOT NULL, + category VARCHAR(20) NOT NULL, + description VARCHAR(255) NULL, + CONSTRAINT PK_question PRIMARY KEY (id) ); COMMENT ON TABLE question IS 'Questions for survey form'; CREATE TABLE IF NOT EXISTS response ( - response_ref serial NOT NULL, - question_ref int4 NOT NULL, - fullname varchar NULL, - CONSTRAINT response_pk PRIMARY KEY (response_ref), - CONSTRAINT response_question_fk FOREIGN KEY (question_ref) REFERENCES question(question_ref) + id SERIAL NOT NULL, + question INT4 NOT NULL, + description VARCHAR NULL, + CONSTRAINT PK_response PRIMARY KEY (id), + CONSTRAINT FK_response_question FOREIGN KEY (question) REFERENCES question(id) ); COMMENT ON TABLE response IS 'Options responses for questions.'; CREATE TABLE IF NOT EXISTS user2response ( - user_response_ref serial NOT NULL, - datetime timestamp NOT NULL, - question_ref int4 NOT NULL, - response_ref int4 NULL, - other_text varchar NULL, - CONSTRAINT user2response_pk PRIMARY KEY (user_response_ref), - CONSTRAINT user2response_question_fk FOREIGN KEY (question_ref) REFERENCES question(question_ref), - CONSTRAINT user2response_response_fk FOREIGN KEY (response_ref) REFERENCES response(response_ref) + id SERIAL NOT NULL, + datetime TIMESTAMP NOT NULL, + question INT4 NOT NULL, + response INT4 NULL, + other_text VARCHAR NULL, + CONSTRAINT PK_user2response PRIMARY KEY (id), + CONSTRAINT FK_user2response_question FOREIGN KEY (question) REFERENCES question(id), + CONSTRAINT FK_user2response_response FOREIGN KEY (response) REFERENCES response(id) ); COMMENT ON TABLE user2response IS 'Responses of user to questions, and other text if present'; diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java index a949503..336eba3 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java @@ -97,7 +97,7 @@ public final class LoginPresenter implements Presenter { for (final Long ref : responsesRef) { // on récupère la réponse correspondante à la référence - final ResponseDTO rDto = this.responses.stream().filter(r -> r.getResponseRef() == ref).findFirst().get(); + final ResponseDTO rDto = this.responses.stream().filter(r -> r.getId() == ref).findFirst().get(); if (rDto != null) { if (!responsesDto.contains(rDto)) { responsesDto.add(rDto); @@ -111,7 +111,7 @@ public final class LoginPresenter implements Presenter { } // ajout de la question, si celle çi n'a qu'une réponse libre this.questions.forEach((q) -> { - if (!questionsDto.contains(q) && otherTextMap.containsKey(q.getQuestionRef())) { + if (!questionsDto.contains(q) && otherTextMap.containsKey(q.getId())) { questionsDto.add(q); } }); diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java index a4b9431..3e175a4 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java @@ -81,11 +81,11 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements final QuestionDTO k = entry.getKey(); // Pour chaque question // on affiche le libellé - this.modal.appendChild(Elements.h(SECTION_TITLE_LEVEL, "• " + k.getFullName())); + this.modal.appendChild(Elements.h(SECTION_TITLE_LEVEL, "• " + k.getDescription())); // on affiche les réponses possibles entry.getValue().forEach((r) -> { - final CheckBox cb = CheckBox.create(r.getFullname()).id(Long.toString(r.getResponseRef())) + final CheckBox cb = CheckBox.create(r.getDescription()).id(Long.toString(r.getId())) .css("login-checkbox"); this.modal.appendChild(cb); this.checkBoxList.add(cb); @@ -111,7 +111,7 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements }); this.checkBoxList.add(otherCb); this.modal.appendChild(otherCb).appendChild(otherText); - otherTextArea.put(k.getQuestionRef(), otherText); + otherTextArea.put(k.getId(), otherText); } // active le bouton Valider si au moins une case a été cochée this.checkBoxList.forEach((c) -> { diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java index ecaebf4..ed2ad39 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java @@ -24,7 +24,7 @@ public class ResponsesDaoHibernate extends DaoHibernate<Response> implements Res /** */ @Override public List<Response> findAllByQuestion(final long questionRef) { - final String jpql = "SELECT r FROM Response r WHERE r.question.questionRef = :ref"; + final String jpql = "SELECT r FROM Response r WHERE r.question.id = :ref"; return super.findAllByJPQL(jpql, Map.of("ref", questionRef), Response.class); } /** */ diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java index 9baf80b..8d147b9 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java @@ -31,7 +31,7 @@ public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implem /** */ @Override public List<UserResponse> findAllByQuestion(final long questionRef) { - final String jpql = "SELECT u FROM UserResponse u WHERE u.question.questionRef = :ref"; + final String jpql = "SELECT u FROM UserResponse u WHERE u.question.id = :ref"; return super.findAllByJPQL(jpql, Map.of("ref", questionRef), UserResponse.class); } /** */ diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java index 57da32f..8f26872 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java @@ -20,11 +20,14 @@ import lombok.Data; @Entity @Table(name = "question") public class Question { - /** PK. */ + /** + * Reference of question.<br> + * Primary key. + */ @Id @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "question_ref") - private long questionRef; + @Column(name = "id") + private long id; /** * Catogory of question. */ @@ -33,6 +36,6 @@ public class Question { /** * Label of question. */ - @Column(name = "fullname") - private String fullName; + @Column(name = "description") + private String description; } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java index c48ef5c..8e132f9 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java @@ -23,21 +23,22 @@ import lombok.Data; @Table(name = "response") public class Response { /** - * Reference of response. + * Reference of response.<br> + * Primary key. */ @Id @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "response_ref") - private long responseRef; + @Column(name = "id") + private long id; /** * Question related to response. */ @OneToOne - @JoinColumn(name = "question_ref") + @JoinColumn(name = "question") private Question question; /** * Label of the response. */ - @Column(name = "fullname") - private String fullname; + @Column(name = "description") + private String description; } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java index 1193939..a143f06 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java @@ -26,21 +26,21 @@ public class UserResponse { /** Primary key. */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "user_response_ref") - private long userResponseRef; + @Column(name = "id") + private long id; /** Date time of user responses. */ @Column(name = "datetime") private Timestamp dateTime; /** Related question. */ @OneToOne - @JoinColumn(name = "question_ref") + @JoinColumn(name = "question") private Question question; /** * Related response.<br> * Can be null if it's a other response. */ @OneToOne - @JoinColumn(name = "response_ref") + @JoinColumn(name = "response") private Response response; /** * Other text response.<br> diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java index ef3dac4..88f81e7 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java @@ -46,9 +46,9 @@ public class LoginFormResource implements LoginFormService { */ static QuestionDTO toDto(final Question question) { final QuestionDTO dto = new QuestionDTO(); - dto.setQuestionRef(question.getQuestionRef()); + dto.setId(question.getId()); dto.setCategory(question.getCategory()); - dto.setFullName(question.getFullName()); + dto.setDescription(question.getDescription()); return dto; } /** @@ -58,9 +58,9 @@ public class LoginFormResource implements LoginFormService { */ static ResponseDTO toDto(final Response response) { final ResponseDTO dto = new ResponseDTO(); - dto.setResponseRef(response.getResponseRef()); + dto.setId(response.getId()); dto.setQuestion(toDto(response.getQuestion())); - dto.setFullname(response.getFullname()); + dto.setDescription(response.getDescription()); return dto; } /** @@ -70,9 +70,9 @@ public class LoginFormResource implements LoginFormService { */ private static Question toEntity(final QuestionDTO dto) { final Question question = new Question(); - question.setQuestionRef(dto.getQuestionRef()); + question.setId(dto.getId()); question.setCategory(dto.getCategory()); - question.setFullName(dto.getFullName()); + question.setDescription(dto.getDescription()); return question; } /** @@ -82,9 +82,9 @@ public class LoginFormResource implements LoginFormService { */ private static Response toEntity(final ResponseDTO dto) { final Response response = new Response(); - response.setResponseRef(dto.getResponseRef()); + response.setId(dto.getId()); response.setQuestion(toEntity(dto.getQuestion())); - response.setFullname(dto.getFullname()); + response.setDescription(dto.getDescription()); return response; } /** @@ -215,9 +215,9 @@ public class LoginFormResource implements LoginFormService { for (final QuestionDTO dto : data.getQuestions()) { // Pour chaque question répondue // Insérer les réponses associés final Question q = toEntity(dto); - final Long qRef = dto.getQuestionRef(); + final Long qRef = dto.getId(); List<ResponseDTO> associatedResponses = data.getResponses() - .stream().filter(f -> f.getQuestion().getQuestionRef() == qRef) + .stream().filter(f -> f.getQuestion().getId() == qRef) .collect(Collectors.toList()); // On insère les réponses prédéfinies @@ -227,9 +227,9 @@ public class LoginFormResource implements LoginFormService { } // Si il existe une réponse libre, l'insérer - if (data.getOtherTextMap().containsKey(dto.getQuestionRef()) - && data.getOtherTextMap().get(dto.getQuestionRef()) != null) { - this.userResponsesDao.insertResponse(q, null, data.getOtherTextMap().get(q.getQuestionRef())); + if (data.getOtherTextMap().containsKey(dto.getId()) + && data.getOtherTextMap().get(dto.getId()) != null) { + this.userResponsesDao.insertResponse(q, null, data.getOtherTextMap().get(q.getId())); } } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java index ce6cc68..c4dcaa4 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java @@ -355,14 +355,14 @@ public class MailServiceImpl implements MailService { builder.append("Il a répondu à " + data.getQuestions().size() + " question(s) :\n"); data.getQuestions().forEach((q) -> { - builder.append("\t• « " + q.getFullName() + " » :\n"); - data.getResponses().stream().filter(f -> f.getQuestion().getQuestionRef() == q.getQuestionRef()) + builder.append("\t• « " + q.getDescription() + " » :\n"); + data.getResponses().stream().filter(f -> f.getQuestion().getId() == q.getId()) .collect(Collectors.toList()) - .forEach((r) -> builder.append("\t\t- " + r.getFullname() + "\n")); + .forEach((r) -> builder.append("\t\t- " + r.getDescription() + "\n")); - if (data.getOtherTextMap().containsKey(q.getQuestionRef()) - && data.getOtherTextMap().get(q.getQuestionRef()) != null) { - builder.append("\t\t- Réponse libre : « " + data.getOtherTextMap().get(q.getQuestionRef()) + " »\n"); + if (data.getOtherTextMap().containsKey(q.getId()) + && data.getOtherTextMap().get(q.getId()) != null) { + builder.append("\t\t- Réponse libre : « " + data.getOtherTextMap().get(q.getId()) + " »\n"); } builder.append("\n"); }); diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java index 33d3395..65f4d27 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java @@ -45,9 +45,9 @@ public class LoginFormHibernateTest { assertNotEquals(list.size(), 0, "La liste de questions est vide"); for (final Question q : list) { // recherche de la question par sa référence - final Question foundedByRef = questionsDao.findByRef(q.getQuestionRef()); - assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getQuestionRef() + " est null"); - assertEquals(foundedByRef, q, "L'objet correspondant à la question " + q.getQuestionRef() + " ne correspond pas"); + final Question foundedByRef = questionsDao.findByRef(q.getId()); + assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getId() + " est null"); + assertEquals(foundedByRef, q, "L'objet correspondant à la question " + q.getId() + " ne correspond pas"); // recherche de la question par sa catégorie final Question foundedByCategory = questionsDao.findByCategory(q.getCategory()); @@ -62,24 +62,24 @@ public class LoginFormHibernateTest { final List<Response> responses = responsesDao.findAll(); assertNotEquals(responses.size(), 0, "La liste de réponses est vide"); for (final Response r : responses) { - assertTrue(questions.contains(r.getQuestion()), "La liste de questions ne contient pas la question " + r.getQuestion().getQuestionRef()); + assertTrue(questions.contains(r.getQuestion()), "La liste de questions ne contient pas la question " + r.getQuestion().getId()); // Test à partir de la question correspondante à la réponse final Question q = r.getQuestion(); - assertNotNull(q, "La question correspondante à la réponse " + r.getResponseRef() + " est null"); + assertNotNull(q, "La question correspondante à la réponse " + r.getId() + " est null"); - final Question foundedByRef = questionsDao.findByRef(q.getQuestionRef()); - assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getQuestionRef() + " est null"); - assertEquals(foundedByRef, r.getQuestion(), "L'objet correspondant à la question " + q.getQuestionRef() + " ne correspond pas"); + final Question foundedByRef = questionsDao.findByRef(q.getId()); + assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getId() + " est null"); + assertEquals(foundedByRef, r.getQuestion(), "L'objet correspondant à la question " + q.getId() + " ne correspond pas"); final Question foundedByCategory = questionsDao.findByCategory(q.getCategory()); assertNotNull(foundedByCategory, "La question correspondante à la catégorie « " + q.getCategory() + " » est null"); assertEquals(foundedByCategory, q, "La question correspondante à la catégorie « " + q.getCategory() + " » est vide"); // recherche de la réponse par sa référence - final Response responseByRef = responsesDao.findByRef(r.getResponseRef()); - assertNotNull(responseByRef, "La réponse correspondante à la réponse " + r.getResponseRef() + " est null"); - assertEquals(responseByRef, r, "La réponse correspondante à la réponse " + r.getResponseRef() + " est vide"); + final Response responseByRef = responsesDao.findByRef(r.getId()); + assertNotNull(responseByRef, "La réponse correspondante à la réponse " + r.getId() + " est null"); + assertEquals(responseByRef, r, "La réponse correspondante à la réponse " + r.getId() + " est vide"); } } @@ -87,7 +87,7 @@ public class LoginFormHibernateTest { public void setUserResponses() { final Question profession = questionsDao.findByCategory("profession"); assertNotNull(profession, "Aucune question ne correspond à la catégorie « profession »"); - List<Response> responses = responsesDao.findAllByQuestion(profession.getQuestionRef()); + List<Response> responses = responsesDao.findAllByQuestion(profession.getId()); assertNotNull(responses, "Aucune réponse ne correspond à la catégorie « profession »"); assertNotEquals(responses.size(), 0, "La liste de réponses pour la catégorie « profession » est vide"); for (final Response r : responses) { @@ -100,7 +100,7 @@ public class LoginFormHibernateTest { userResponsesDao.insertResponse(profession, r, null); listOfResponses.add(r); - List<UserResponse> list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); + List<UserResponse> list = userResponsesDao.findAllByQuestion(profession.getId()); assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur doit contenir un élément"); assertEquals(list.get(0).getQuestion(), profession, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); assertEquals(list.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); @@ -112,7 +112,7 @@ public class LoginFormHibernateTest { userResponsesDao.insertResponse(profession, res, null); listOfResponses.add(res); } - list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); + list = userResponsesDao.findAllByQuestion(profession.getId()); assertEquals(list.size(), (1 + nbToInsert), "La liste de réponses de l'utilisateur doit contenir la réponse précédente + " + nbToInsert + " réponses supplémentaires"); for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question"); @@ -127,7 +127,7 @@ public class LoginFormHibernateTest { String other = "Ceci est une réponse libre"; userResponsesDao.insertResponse(profession, null, other); - list = userResponsesDao.findAllByQuestion(profession.getQuestionRef()); + list = userResponsesDao.findAllByQuestion(profession.getId()); assertEquals(list.size(), (newNbResponses + 1), "La liste de réponses de l'utilisateur doit contenir les " + newNbResponses + " + la réponse libre"); for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); @@ -143,23 +143,23 @@ public class LoginFormHibernateTest { // Essai de l'insertion par les références, avec une autre question final Question useCase = questionsDao.findByCategory("useCase"); assertNotNull(useCase, "Aucune question ne correspond à la catégorie « useCase »"); - responses = responsesDao.findAllByQuestion(useCase.getQuestionRef()); + responses = responsesDao.findAllByQuestion(useCase.getId()); assertNotNull(responses, "Aucune réponse ne correspond à la catégorie « useCase »"); assertNotEquals(responses.size(), 0, "La liste de réponses pour la catégorie « useCase » est vide"); r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); - userResponsesDao.insertResponse(useCase.getQuestionRef(), r.getResponseRef(), null); + userResponsesDao.insertResponse(useCase.getId(), r.getId(), null); - list = userResponsesDao.findAllByQuestion(useCase.getQuestionRef()); + list = userResponsesDao.findAllByQuestion(useCase.getId()); assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur pour la question « useCase » doit contenir un élément"); assertEquals(list.get(0).getQuestion(), useCase, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); assertEquals(list.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); assertNull(list.get(0).getOtherText(), "Le texte libre doit être null"); other = other.concat(" pour la question « useCase »"); - userResponsesDao.insertResponse(useCase.getQuestionRef(), null, other); + userResponsesDao.insertResponse(useCase.getId(), null, other); - list = userResponsesDao.findAllByQuestion(useCase.getQuestionRef()); + list = userResponsesDao.findAllByQuestion(useCase.getId()); assertEquals(list.size(), 2, "La liste de réponses de l'utilisateur pour la question « useCase » doit contenir deux éléments"); for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java index 3ec6678..e36a2bb 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java @@ -129,7 +129,7 @@ public class LoginFormResourceTest extends JerseyTest { assertNotEquals(allResponses.size(), 0, "La liste de réponses est vide"); for (final Response r : allResponses) { - assertTrue(questions.contains(r.getQuestion()), "La question de la réponse « " + r.getFullname() + " » n'est pas contenue dans la liste des questions"); + assertTrue(questions.contains(r.getQuestion()), "La question de la réponse « " + r.getDescription() + " » n'est pas contenue dans la liste des questions"); } // Pour chaque question, @@ -139,40 +139,40 @@ public class LoginFormResourceTest extends JerseyTest { .queryParam("category", q.getCategory()) .request().get(String.class); - assertNotNull(jsonCategory, "Impossible de récupérer la ressource (objet null) de la catégorie pour la question n°" + q.getQuestionRef()); - assertFalse(jsonCategory.isEmpty(), "La chaine de caractère JSON de la catégorie pour la question n° " + q.getQuestionRef() + " est vide"); + assertNotNull(jsonCategory, "Impossible de récupérer la ressource (objet null) de la catégorie pour la question n°" + q.getId()); + assertFalse(jsonCategory.isEmpty(), "La chaine de caractère JSON de la catégorie pour la question n° " + q.getId() + " est vide"); final Question questionByCategory = objectMapper.readValue(jsonCategory, new TypeReference<Question>() {}); - assertNotNull(questionByCategory, "La conversion du JSON de la catégorie pour la question n° " + q.getQuestionRef() + " n'a pas fonctionnée"); - assertEquals(questionByCategory, q, "La question lue par la catégorie ne correspond pas avec la question n° " + q.getQuestionRef() + "d'origine"); + assertNotNull(questionByCategory, "La conversion du JSON de la catégorie pour la question n° " + q.getId() + " n'a pas fonctionnée"); + assertEquals(questionByCategory, q, "La question lue par la catégorie ne correspond pas avec la question n° " + q.getId() + "d'origine"); // On vérifie, via le DAO final Question questionByDao = questionsDao.findByCategory(q.getCategory()); - assertNotNull(questionByDao, "La lecture de la question n° " + q.getQuestionRef() + " via le DAO n'a pas fonctionnée"); - assertEquals(questionByDao, q, "La question lue par le DAO ne correspond pas avec la question n° " + q.getQuestionRef() + "d'origine"); + assertNotNull(questionByDao, "La lecture de la question n° " + q.getId() + " via le DAO n'a pas fonctionnée"); + assertEquals(questionByDao, q, "La question lue par le DAO ne correspond pas avec la question n° " + q.getId() + "d'origine"); // on récupère les réponses associées via le webservice final String jsonResponses = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_RESPONSES_BY_QUESTION_LIST) - .queryParam("questionRef", String.valueOf(q.getQuestionRef())) + .queryParam("questionRef", String.valueOf(q.getId())) .request() .get(String.class); - assertNotNull(jsonResponses, "Impossible de récupérer la ressource (objet null) pour la question n° " + q.getQuestionRef() + " est vide"); - assertFalse(jsonResponses.isEmpty(), "La chaine de caractère JSON pour la question n° " + q.getQuestionRef() + " est vide"); + assertNotNull(jsonResponses, "Impossible de récupérer la ressource (objet null) pour la question n° " + q.getId() + " est vide"); + assertFalse(jsonResponses.isEmpty(), "La chaine de caractère JSON pour la question n° " + q.getId() + " est vide"); final List<Response> responses = objectMapper.readValue(jsonResponses, new TypeReference<List<Response>>() {}); - assertNotNull(responses, "La conversion du JSON des réponses de la question n° " + q.getQuestionRef() + " n'a pas fonctionnée"); - assertNotEquals(responses.size(), 0, " La liste de réponses pour la question n° " + q.getQuestionRef() + " est vide"); + assertNotNull(responses, "La conversion du JSON des réponses de la question n° " + q.getId() + " n'a pas fonctionnée"); + assertNotEquals(responses.size(), 0, " La liste de réponses pour la question n° " + q.getId() + " est vide"); - final List<Response> responsesByDao = responsesDao.findAllByQuestion(q.getQuestionRef()); - assertNotNull(responsesByDao, " La lecture des réponses pour la question n° " + q.getQuestionRef() + " via le DAO n'a pas fonctionné"); - assertNotEquals(responsesByDao.size(), 0, " La liste de réponses via le DAO pour la question n° " + q.getQuestionRef() + " est vide"); + final List<Response> responsesByDao = responsesDao.findAllByQuestion(q.getId()); + assertNotNull(responsesByDao, " La lecture des réponses pour la question n° " + q.getId() + " via le DAO n'a pas fonctionné"); + assertNotEquals(responsesByDao.size(), 0, " La liste de réponses via le DAO pour la question n° " + q.getId() + " est vide"); assertEquals(responses, responsesByDao, "La liste de réponses via le webservice n'est pas identique avec la liste via le DAO"); for (final Response r : responses) { - assertNotNull(r.getQuestion(), "La question de la réponse n° " + r.getResponseRef() + " est null"); - assertEquals(r.getQuestion(), q, "La question de la réponse n° " + r.getResponseRef() + " ne correspond pas à la question"); - assertTrue(responsesByDao.contains(r), "La liste via le DAO ne contient pas la réponse n° " + r.getResponseRef()); + assertNotNull(r.getQuestion(), "La question de la réponse n° " + r.getId() + " est null"); + assertEquals(r.getQuestion(), q, "La question de la réponse n° " + r.getId() + " ne correspond pas à la question"); + assertTrue(responsesByDao.contains(r), "La liste via le DAO ne contient pas la réponse n° " + r.getId()); } } @@ -197,7 +197,7 @@ public class LoginFormResourceTest extends JerseyTest { // on récupère les réponses de la question final List<Response> responses = objectMapper.readValue(target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_RESPONSES_BY_QUESTION_LIST) - .queryParam("questionRef", String.valueOf(origin.getQuestionRef())) + .queryParam("questionRef", String.valueOf(origin.getId())) .request() .get(String.class), new TypeReference<List<Response>>() {}); @@ -211,8 +211,8 @@ public class LoginFormResourceTest extends JerseyTest { // Insertion d'une réponse prédéfénie Response r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); final Form form = new Form(); - form.param("questionRef", String.valueOf(origin.getQuestionRef())); - form.param("responseRef", String.valueOf(r.getResponseRef())); + form.param("questionRef", String.valueOf(origin.getId())); + form.param("responseRef", String.valueOf(r.getId())); form.param("otherText", "null"); target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE) @@ -221,7 +221,7 @@ public class LoginFormResourceTest extends JerseyTest { listOfResponses.add(r); // On lit la réponse insérée, via le DAO - List<UserResponse> userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); + List<UserResponse> userResponsesList = userResponsesDao.findAllByQuestion(origin.getId()); assertEquals(userResponsesList.size(), 1, "La liste de réponses de l'utilisateur doit contenir un élément"); assertEquals(userResponsesList.get(0).getQuestion(), origin, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); assertEquals(userResponsesList.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); @@ -232,8 +232,8 @@ public class LoginFormResourceTest extends JerseyTest { final List<Response> randoms = this.pickNRandom(responses, nbToInsert); for (final Response res : randoms) { final Form f = new Form(); - f.param("questionRef", String.valueOf(origin.getQuestionRef())); - f.param("responseRef", String.valueOf(res.getResponseRef())); + f.param("questionRef", String.valueOf(origin.getId())); + f.param("responseRef", String.valueOf(res.getId())); f.param("otherText", "null"); target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE) @@ -244,7 +244,7 @@ public class LoginFormResourceTest extends JerseyTest { } // Vérification via le DAO - userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); + userResponsesList = userResponsesDao.findAllByQuestion(origin.getId()); assertEquals(userResponsesList.size(), (1 + nbToInsert), "La liste de réponses de l'utilisateur doit contenir la réponse précédente + " + nbToInsert + " réponses supplémentaires"); for (final UserResponse ur : userResponsesList) { @@ -259,7 +259,7 @@ public class LoginFormResourceTest extends JerseyTest { // insertion d'une réponse à choix libre final String other = "Ceci est une réponse libre"; final Form formOther = new Form(); - formOther.param("questionRef", String.valueOf(origin.getQuestionRef())); + formOther.param("questionRef", String.valueOf(origin.getId())); formOther.param("responseRef", "null"); formOther.param("otherText", other); @@ -267,7 +267,7 @@ public class LoginFormResourceTest extends JerseyTest { .request(MediaType.TEXT_PLAIN) .post(Entity.form(formOther)); - userResponsesList = userResponsesDao.findAllByQuestion(origin.getQuestionRef()); + userResponsesList = userResponsesDao.findAllByQuestion(origin.getId()); assertEquals(userResponsesList.size(), (newNbResponses + 1), "La liste de réponses de l'utilisateur doit contenir les " + newNbResponses + " réponses + la réponse libre"); for (final UserResponse ur : userResponsesList) { @@ -295,7 +295,7 @@ public class LoginFormResourceTest extends JerseyTest { final HashMap<Long, String> otherTextMap = new HashMap<>(); for (final Question q : questionsList) { - final List<Response> responsesListForQuestion = responsesDao.findAllByQuestion(q.getQuestionRef()); + final List<Response> responsesListForQuestion = responsesDao.findAllByQuestion(q.getId()); // on récupère un nombre aléatoire de réponse final List<Response> randomList = this.pickNRandom(responsesListForQuestion, ThreadLocalRandom.current().nextInt(0, responsesListForQuestion.size() - 1)); @@ -305,7 +305,7 @@ public class LoginFormResourceTest extends JerseyTest { responsesList.addAll(randomList); } - otherTextMap.put(q.getQuestionRef(), "Réponse libre pour la question « " + q.getFullName() + " »"); + otherTextMap.put(q.getId(), "Réponse libre pour la question « " + q.getDescription() + " »"); } final List<ResponseDTO> responsesDTO = responsesList.stream().map(LoginFormResource::toDto).toList(); @@ -322,12 +322,12 @@ public class LoginFormResourceTest extends JerseyTest { // Pour le test, vérifier, pour chaque question, les réponses via le DAO for (final Question q : questionsDao.findAll()) { - final List<UserResponse> list = userResponsesDao.findAllByQuestion(q.getQuestionRef()); + final List<UserResponse> list = userResponsesDao.findAllByQuestion(q.getId()); assertNotNull(list, "La liste de réponses de l'utilisateur ne doit pas être null"); for (final UserResponse ur : list) { assertNotNull(ur.getDateTime(), "Le timestamp de la réponse ne doit pas être null"); - assertEquals(ur.getQuestion(), q, "La question contenue dans la réponse ne correspond pas avec la question d'origine « " + q.getFullName() + " »"); - assertTrue(ur.getUserResponseRef() > 0, "la référence de la réponse de l'utilisateur doit être supérieur à 0"); + assertEquals(ur.getQuestion(), q, "La question contenue dans la réponse ne correspond pas avec la question d'origine « " + q.getDescription() + " »"); + assertTrue(ur.getId() > 0, "la référence de la réponse de l'utilisateur doit être supérieur à 0"); if (ur.getResponse() != null) { assertNotNull(ur.getResponse(), "La réponse de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); assertNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, doit être null"); diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java index 60de95d..cab54a7 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java @@ -17,7 +17,7 @@ public class QuestionDTO { /** * Ref of question. */ - private long questionRef; + private long id; /** * Category of question. */ @@ -25,12 +25,12 @@ public class QuestionDTO { /** * Label of question. */ - private String fullName; + private String description; /** * @return the questionRef */ - public long getQuestionRef() { - return questionRef; + public long getId() { + return id; } /** * @return the category @@ -41,14 +41,14 @@ public class QuestionDTO { /** * @return the fullName */ - public String getFullName() { - return fullName; + public String getDescription() { + return description; } /** * @param value the questionRef to set */ - public void setQuestionRef(final long value) { - this.questionRef = value; + public void setId(final long value) { + this.id = value; } /** * @param value the category to set @@ -59,13 +59,13 @@ public class QuestionDTO { /** * @param value the fullName to set */ - public void setFullName(final String value) { - this.fullName = value; + public void setDescription(final String value) { + this.description = value; } /** */ @Override public int hashCode() { - return Objects.hash(category, fullName, questionRef); + return Objects.hash(category, description, id); } /** */ @Override @@ -80,7 +80,7 @@ public class QuestionDTO { return false; } QuestionDTO other = (QuestionDTO) obj; - return Objects.equals(category, other.category) && Objects.equals(fullName, other.fullName) - && questionRef == other.questionRef; + return Objects.equals(category, other.category) && Objects.equals(description, other.description) + && id == other.id; } } diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java index f1e86aa..849f10b 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java @@ -15,7 +15,7 @@ public class ResponseDTO { /** * Ref of this response. */ - private long responseRef; + private long id; /** * DTO of question associated to response. */ @@ -23,12 +23,12 @@ public class ResponseDTO { /** * Label of response. */ - private String fullname; + private String description; /** * @return the responseRef */ - public long getResponseRef() { - return responseRef; + public long getId() { + return id; } /** * @return the question @@ -39,14 +39,14 @@ public class ResponseDTO { /** * @return the fullname */ - public String getFullname() { - return fullname; + public String getDescription() { + return description; } /** * @param value the responseRef to set */ - public void setResponseRef(final long value) { - this.responseRef = value; + public void setId(final long value) { + this.id = value; } /** * @param dto the question to set @@ -57,7 +57,7 @@ public class ResponseDTO { /** * @param value the fullname to set */ - public void setFullname(final String value) { - this.fullname = value; + public void setDescription(final String value) { + this.description = value; } } -- GitLab From 7abca50bee6145e516a9c974ea34ae2585e3cd0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Mon, 27 May 2024 12:53:58 +0200 Subject: [PATCH 11/30] =?UTF-8?q?Modifier=20les=20noms=20de=20classe=20?= =?UTF-8?q?=C2=AB=20Login=20=C2=BB=20en=20=C2=AB=20Survey=20=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/fr/agrometinfo/www/client/App.java | 3 +- ...ginPresenter.java => SurveyPresenter.java} | 44 ++++++------- .../view/{LoginView.java => SurveyView.java} | 16 ++--- .../www/server/rs/ApplicationConfig.java | 2 +- ...mResource.java => SurveyFormResource.java} | 62 +++++++++---------- .../www/server/service/MailService.java | 4 +- .../www/server/service/MailServiceImpl.java | 6 +- ...Test.java => SurveyFormHibernateTest.java} | 2 +- ...eTest.java => SurveyFormResourceTest.java} | 38 ++++++------ ...{ResponseDTO.java => SurveyOptionDTO.java} | 10 +-- ...uestionDTO.java => SurveyQuestionDTO.java} | 4 +- ...ormDataDTO.java => SurveyResponseDTO.java} | 20 +++--- ...ormService.java => SurveyFormService.java} | 32 +++++----- 13 files changed, 122 insertions(+), 121 deletions(-) rename www-client/src/main/java/fr/agrometinfo/www/client/presenter/{LoginPresenter.java => SurveyPresenter.java} (69%) rename www-client/src/main/java/fr/agrometinfo/www/client/view/{LoginView.java => SurveyView.java} (90%) rename www-server/src/main/java/fr/agrometinfo/www/server/rs/{LoginFormResource.java => SurveyFormResource.java} (78%) rename www-server/src/test/java/fr/agrometinfo/www/server/{LoginFormHibernateTest.java => SurveyFormHibernateTest.java} (99%) rename www-server/src/test/java/fr/agrometinfo/www/server/rs/{LoginFormResourceTest.java => SurveyFormResourceTest.java} (91%) rename www-shared/src/main/java/fr/agrometinfo/www/shared/dto/{ResponseDTO.java => SurveyOptionDTO.java} (81%) rename www-shared/src/main/java/fr/agrometinfo/www/shared/dto/{QuestionDTO.java => SurveyQuestionDTO.java} (94%) rename www-shared/src/main/java/fr/agrometinfo/www/shared/dto/{LoginFormDataDTO.java => SurveyResponseDTO.java} (73%) rename www-shared/src/main/java/fr/agrometinfo/www/shared/service/{LoginFormService.java => SurveyFormService.java} (69%) diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/App.java b/www-client/src/main/java/fr/agrometinfo/www/client/App.java index 6134041..2de0783 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/App.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/App.java @@ -22,6 +22,7 @@ import fr.agrometinfo.www.client.i18n.AppMessages; import fr.agrometinfo.www.client.presenter.LayoutPresenter; import fr.agrometinfo.www.client.util.ApplicationUtils; import fr.agrometinfo.www.shared.service.ApplicationServiceFactory; +import fr.agrometinfo.www.client.presenter.SurveyPresenter; /** * Entry point classes define <code>onModuleLoad()</code>. @@ -101,6 +102,6 @@ public class App implements EntryPoint { new LayoutPresenter().start(); // formulaire d'enquête - new LoginPresenter().start(); + new SurveyPresenter().start(); } } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java similarity index 69% rename from www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java rename to www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java index 336eba3..13d349d 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/LoginPresenter.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java @@ -8,27 +8,27 @@ import org.dominokit.rest.shared.request.FailedResponseBean; import com.google.gwt.core.client.GWT; import fr.agrometinfo.www.client.view.BaseView; -import fr.agrometinfo.www.client.view.LoginView; -import fr.agrometinfo.www.shared.dto.QuestionDTO; -import fr.agrometinfo.www.shared.dto.ResponseDTO; -import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; -import fr.agrometinfo.www.shared.service.LoginFormServiceFactory; +import fr.agrometinfo.www.client.view.SurveyView; +import fr.agrometinfo.www.shared.dto.SurveyQuestionDTO; +import fr.agrometinfo.www.shared.dto.SurveyOptionDTO; +import fr.agrometinfo.www.shared.dto.SurveyResponseDTO; +import fr.agrometinfo.www.shared.service.SurveyFormServiceFactory; import java.util.HashMap; import java.util.Map; /** - * Presenter to login the user with survey form. + * Presenter for survey form. * * @author Olivier Maury * @author Jérémie Décome */ -public final class LoginPresenter implements Presenter { +public final class SurveyPresenter implements Presenter { /** * Interface for the related view. */ - public interface View extends BaseView<LoginPresenter> { + public interface View extends BaseView<SurveyPresenter> { /** * Display notification on failure. * @@ -42,7 +42,7 @@ public final class LoginPresenter implements Presenter { /** * @param map list of availables responses. */ - void setResponses(Map<QuestionDTO, List<ResponseDTO>> map); + void setResponses(Map<SurveyQuestionDTO, List<SurveyOptionDTO>> map); /** * Showing success login. * @param msg returned message from webservice @@ -53,24 +53,24 @@ public final class LoginPresenter implements Presenter { /** * Related view. */ - private final LoginView view = new LoginView(); + private final SurveyView view = new SurveyView(); /** List of responses from webservice. */ - private List<ResponseDTO> responses; + private List<SurveyOptionDTO> responses; /** List of questions, extracted from responses list. */ - private List<QuestionDTO> questions; + private List<SurveyQuestionDTO> questions; /** * Set responses and extract questions from responses list. * @param list list of responses */ - private void setResponses(final List<ResponseDTO> list) { + private void setResponses(final List<SurveyOptionDTO> list) { this.responses = list; - final Map<QuestionDTO, List<ResponseDTO>> responsesMap = new HashMap<>(); + final Map<SurveyQuestionDTO, List<SurveyOptionDTO>> responsesMap = new HashMap<>(); // extraction des questions, à partir des réponses retournées par le webservice - for (final ResponseDTO dto : list) { + for (final SurveyOptionDTO dto : list) { if (!responsesMap.containsKey(dto.getQuestion())) { // la map ne contient pas la question // on crée l'entrée, avec une liste vide - responsesMap.put(dto.getQuestion(), new ArrayList<ResponseDTO>()); + responsesMap.put(dto.getQuestion(), new ArrayList<SurveyOptionDTO>()); } responsesMap.get(dto.getQuestion()).add(dto); } @@ -83,7 +83,7 @@ public final class LoginPresenter implements Presenter { public void start() { view.setPresenter(this); - LoginFormServiceFactory.INSTANCE.getResponses() + SurveyFormServiceFactory.INSTANCE.getResponses() .onSuccess(this::setResponses) .onFailed(view::failureNotification) .send(); @@ -92,12 +92,12 @@ public final class LoginPresenter implements Presenter { GWT.log("Insère les réponses de l'utilisateur"); // traitement des réponses prédéfinies - final List<QuestionDTO> questionsDto = new ArrayList<>(); - final List<ResponseDTO> responsesDto = new ArrayList<>(); + final List<SurveyQuestionDTO> questionsDto = new ArrayList<>(); + final List<SurveyOptionDTO> responsesDto = new ArrayList<>(); for (final Long ref : responsesRef) { // on récupère la réponse correspondante à la référence - final ResponseDTO rDto = this.responses.stream().filter(r -> r.getId() == ref).findFirst().get(); + final SurveyOptionDTO rDto = this.responses.stream().filter(r -> r.getId() == ref).findFirst().get(); if (rDto != null) { if (!responsesDto.contains(rDto)) { responsesDto.add(rDto); @@ -118,8 +118,8 @@ public final class LoginPresenter implements Presenter { // envoi au webservice - final LoginFormDataDTO data = new LoginFormDataDTO(questionsDto, responsesDto, otherTextMap); - LoginFormServiceFactory.INSTANCE.insertAllResponses(data) + final SurveyResponseDTO data = new SurveyResponseDTO(questionsDto, responsesDto, otherTextMap); + SurveyFormServiceFactory.INSTANCE.insertAllResponses(data) .onSuccess(view::displaySuccessLogin) .onFailed(view::failureNotification) .send(); diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java similarity index 90% rename from www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java rename to www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java index 3e175a4..adc2e38 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LoginView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java @@ -18,9 +18,9 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.storage.client.Storage; import fr.agrometinfo.www.client.i18n.AppConstants; -import fr.agrometinfo.www.client.presenter.LoginPresenter; -import fr.agrometinfo.www.shared.dto.QuestionDTO; -import fr.agrometinfo.www.shared.dto.ResponseDTO; +import fr.agrometinfo.www.client.presenter.SurveyPresenter; +import fr.agrometinfo.www.shared.dto.SurveyQuestionDTO; +import fr.agrometinfo.www.shared.dto.SurveyOptionDTO; /** * View for survey form. @@ -28,7 +28,7 @@ import fr.agrometinfo.www.shared.dto.ResponseDTO; * @author Olivier Maury * @author Jérémie Décome */ -public final class LoginView extends AbstractBaseView<LoginPresenter> implements LoginPresenter.View { +public final class SurveyView extends AbstractBaseView<SurveyPresenter> implements SurveyPresenter.View { /** * I18N constants. */ @@ -44,7 +44,7 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements /** * List of available responses. */ - private Map<QuestionDTO, List<ResponseDTO>> availableResponses; + private Map<SurveyQuestionDTO, List<SurveyOptionDTO>> availableResponses; /** * The modal used to display the login form. */ @@ -77,8 +77,8 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements .innerHtml(new SafeHtmlBuilder().appendHtmlConstant(CSTS.loginFormDescription()).toSafeHtml()) ); - for (Map.Entry<QuestionDTO, List<ResponseDTO>> entry : this.availableResponses.entrySet()) { - final QuestionDTO k = entry.getKey(); // Pour chaque question + for (Map.Entry<SurveyQuestionDTO, List<SurveyOptionDTO>> entry : this.availableResponses.entrySet()) { + final SurveyQuestionDTO k = entry.getKey(); // Pour chaque question // on affiche le libellé this.modal.appendChild(Elements.h(SECTION_TITLE_LEVEL, "• " + k.getDescription())); @@ -163,7 +163,7 @@ public final class LoginView extends AbstractBaseView<LoginPresenter> implements } @Override - public void setResponses(final Map<QuestionDTO, List<ResponseDTO>> map) { + public void setResponses(final Map<SurveyQuestionDTO, List<SurveyOptionDTO>> map) { this.availableResponses = map; } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java index 60623c8..de1362f 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java @@ -43,7 +43,7 @@ public class ApplicationConfig extends Application { // Jackson configuration JacksonConfig.class, // JAX-RS resources - ApplicationResource.class, GeometryResource.class, IndicatorResource.class, LoginFormResource.class, UserResource.class, + ApplicationResource.class, GeometryResource.class, IndicatorResource.class, SurveyFormResource.class, UserResource.class, // POJO // Dependencies of resources LogFilter.class diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java similarity index 78% rename from www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java rename to www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java index 88f81e7..67e57b1 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/LoginFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java @@ -15,10 +15,10 @@ import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; import fr.agrometinfo.www.server.service.MailService; import fr.agrometinfo.www.shared.dto.ErrorResponseDTO; -import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; -import fr.agrometinfo.www.shared.dto.QuestionDTO; -import fr.agrometinfo.www.shared.dto.ResponseDTO; -import fr.agrometinfo.www.shared.service.LoginFormService; +import fr.agrometinfo.www.shared.dto.SurveyResponseDTO; +import fr.agrometinfo.www.shared.dto.SurveyQuestionDTO; +import fr.agrometinfo.www.shared.dto.SurveyOptionDTO; +import fr.agrometinfo.www.shared.service.SurveyFormService; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; @@ -36,16 +36,16 @@ import jakarta.ws.rs.core.MediaType; * @author jdecome * */ -@Path(LoginFormService.PATH) +@Path(SurveyFormService.PATH) @RequestScoped -public class LoginFormResource implements LoginFormService { +public class SurveyFormResource implements SurveyFormService { /** * Convert {@link Question} entity to dto. * @param question entity * @return dto */ - static QuestionDTO toDto(final Question question) { - final QuestionDTO dto = new QuestionDTO(); + static SurveyQuestionDTO toDto(final Question question) { + final SurveyQuestionDTO dto = new SurveyQuestionDTO(); dto.setId(question.getId()); dto.setCategory(question.getCategory()); dto.setDescription(question.getDescription()); @@ -56,19 +56,19 @@ public class LoginFormResource implements LoginFormService { * @param response entity * @return dto */ - static ResponseDTO toDto(final Response response) { - final ResponseDTO dto = new ResponseDTO(); + static SurveyOptionDTO toDto(final Response response) { + final SurveyOptionDTO dto = new SurveyOptionDTO(); dto.setId(response.getId()); dto.setQuestion(toDto(response.getQuestion())); dto.setDescription(response.getDescription()); return dto; } /** - * Convert {@link QuestionDTO} dto to entity. + * Convert {@link SurveyQuestionDTO} dto to entity. * @param dto question * @return entity */ - private static Question toEntity(final QuestionDTO dto) { + private static Question toEntity(final SurveyQuestionDTO dto) { final Question question = new Question(); question.setId(dto.getId()); question.setCategory(dto.getCategory()); @@ -76,11 +76,11 @@ public class LoginFormResource implements LoginFormService { return question; } /** - * Convert {@link ResponseDTO} dto to entity. + * Convert {@link SurveyOptionDTO} dto to entity. * @param dto response * @return entity */ - private static Response toEntity(final ResponseDTO dto) { + private static Response toEntity(final SurveyOptionDTO dto) { final Response response = new Response(); response.setId(dto.getId()); response.setQuestion(toEntity(dto.getQuestion())); @@ -125,35 +125,35 @@ public class LoginFormResource implements LoginFormService { } } @GET - @Path(LoginFormService.PATH_QUESTIONS_LIST) + @Path(SurveyFormService.PATH_QUESTIONS_LIST) @Produces(MediaType.APPLICATION_JSON) @Override - public List<QuestionDTO> getQuestions() { + public List<SurveyQuestionDTO> getQuestions() { final List<Question> list = questionsDao.findAll(); - final List<QuestionDTO> questions = new ArrayList<>(); + final List<SurveyQuestionDTO> questions = new ArrayList<>(); for (Question q : list) { questions.add(toDto(q)); } return questions; } @GET - @Path(LoginFormService.PATH_QUESTION_BY_CATEGORY) + @Path(SurveyFormService.PATH_QUESTION_BY_CATEGORY) @Produces(MediaType.APPLICATION_JSON) @Override - public QuestionDTO getQuestionByCategory(@QueryParam(value = "category") final String category) { + public SurveyQuestionDTO getQuestionByCategory(@QueryParam(value = "category") final String category) { this.checkRequired(category, "category"); final Question question = questionsDao.findByCategory(category); return toDto(question); } @GET - @Path(LoginFormService.PATH_RESPONSES_BY_QUESTION_LIST) + @Path(SurveyFormService.PATH_RESPONSES_BY_QUESTION_LIST) @Produces(MediaType.APPLICATION_JSON) @Override - public List<ResponseDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") final Long questionRef) { + public List<SurveyOptionDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") final Long questionRef) { this.checkRequired(questionRef, "questionRef"); if (this.checkIfQuestionExist(questionRef)) { final List<Response> list = responsesDao.findAllByQuestion(questionRef); - final List<ResponseDTO> responses = new ArrayList<>(); + final List<SurveyOptionDTO> responses = new ArrayList<>(); for (final Response r : list) { responses.add(toDto(r)); } @@ -162,19 +162,19 @@ public class LoginFormResource implements LoginFormService { return null; } @GET - @Path(LoginFormService.PATH_RESPONSES_LIST) + @Path(SurveyFormService.PATH_RESPONSES_LIST) @Produces(MediaType.APPLICATION_JSON) @Override - public List<ResponseDTO> getResponses() { + public List<SurveyOptionDTO> getResponses() { final List<Response> list = responsesDao.findAll(); - final List<ResponseDTO> responses = new ArrayList<>(); + final List<SurveyOptionDTO> responses = new ArrayList<>(); for (final Response r : list) { responses.add(toDto(r)); } return responses; } @POST - @Path(LoginFormService.PATH_INSERT_RESPONSE) + @Path(SurveyFormService.PATH_INSERT_RESPONSE) @Produces(MediaType.TEXT_PLAIN) @Override public void insertResponse( @@ -206,22 +206,22 @@ public class LoginFormResource implements LoginFormService { return false; } @POST - @Path(LoginFormService.PATH_INSERT_RESPONSE_WITH_JSON) + @Path(SurveyFormService.PATH_INSERT_RESPONSE_WITH_JSON) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Override - public String insertAllResponses(final LoginFormDataDTO data) { + public String insertAllResponses(final SurveyResponseDTO data) { // traitement des réponses prédéfinies - for (final QuestionDTO dto : data.getQuestions()) { // Pour chaque question répondue + for (final SurveyQuestionDTO dto : data.getQuestions()) { // Pour chaque question répondue // Insérer les réponses associés final Question q = toEntity(dto); final Long qRef = dto.getId(); - List<ResponseDTO> associatedResponses = data.getResponses() + List<SurveyOptionDTO> associatedResponses = data.getResponses() .stream().filter(f -> f.getQuestion().getId() == qRef) .collect(Collectors.toList()); // On insère les réponses prédéfinies - for (final ResponseDTO rDto : associatedResponses) { + for (final SurveyOptionDTO rDto : associatedResponses) { final Response r = toEntity(rDto); this.userResponsesDao.insertResponse(q, r, null); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java index c2524f0..a472586 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java @@ -2,7 +2,7 @@ package fr.agrometinfo.www.server.service; import fr.agrometinfo.www.server.exception.AgroMetInfoException; import fr.agrometinfo.www.server.service.MailServiceImpl.Mail; -import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; +import fr.agrometinfo.www.shared.dto.SurveyResponseDTO; public interface MailService { /** @@ -19,5 +19,5 @@ public interface MailService { * Send mail when user fill login form, with questions and responses. * @param data */ - void sendLoginFilled(LoginFormDataDTO data); + void sendLoginFilled(SurveyResponseDTO data); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java index c4dcaa4..2a2933f 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java @@ -27,7 +27,7 @@ import fr.agrometinfo.www.server.exception.AgroMetInfoErrorCategory; import fr.agrometinfo.www.server.exception.AgroMetInfoException; import fr.agrometinfo.www.server.exception.ErrorCategory; import fr.agrometinfo.www.server.exception.ErrorType; -import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; +import fr.agrometinfo.www.shared.dto.SurveyResponseDTO; import jakarta.annotation.PostConstruct; import jakarta.mail.Address; import jakarta.mail.Authenticator; @@ -329,7 +329,7 @@ public class MailServiceImpl implements MailService { * Send an e-mail when user filled survey form. * @param data data of survey */ - public void sendLoginFilled(final LoginFormDataDTO data) { + public void sendLoginFilled(final SurveyResponseDTO data) { final Mail mail = createContentFromData(data); mail.setSubject("Un utilisateur a rempli le formulaire d'enquête"); mail.setFromAddress(configuration.get(ConfigurationKey.APP_EMAIL)); @@ -346,7 +346,7 @@ public class MailServiceImpl implements MailService { * @param data data of survey * @return mail object */ - public static Mail createContentFromData(final LoginFormDataDTO data) { + public static Mail createContentFromData(final SurveyResponseDTO data) { final Mail mail = new Mail(); final StringBuilder builder = new StringBuilder(); diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java similarity index 99% rename from www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java rename to www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index 65f4d27..93a8c1b 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/LoginFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -31,7 +31,7 @@ import fr.agrometinfo.www.server.model.UserResponse; * @author jdecome * */ -public class LoginFormHibernateTest { +public class SurveyFormHibernateTest { /** DAO for user's responses. */ private UserResponsesDao userResponsesDao = new UserResponsesDaoHibernate(); /** DAO for questions. */ diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java similarity index 91% rename from www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java rename to www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java index e36a2bb..5ffca0c 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/LoginFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java @@ -39,9 +39,9 @@ import fr.agrometinfo.www.server.model.UserResponse; import fr.agrometinfo.www.server.service.MailService; import fr.agrometinfo.www.server.service.MailServiceImpl; import fr.agrometinfo.www.server.service.MailServiceImpl.Mail; -import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; -import fr.agrometinfo.www.shared.dto.QuestionDTO; -import fr.agrometinfo.www.shared.dto.ResponseDTO; +import fr.agrometinfo.www.shared.dto.SurveyResponseDTO; +import fr.agrometinfo.www.shared.dto.SurveyQuestionDTO; +import fr.agrometinfo.www.shared.dto.SurveyOptionDTO; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.core.Application; @@ -56,7 +56,7 @@ import lombok.extern.log4j.Log4j2; * */ @Log4j2 -public class LoginFormResourceTest extends JerseyTest { +public class SurveyFormResourceTest extends JerseyTest { /** * Mock class for mail service. * @author jdecome @@ -67,7 +67,7 @@ public class LoginFormResourceTest extends JerseyTest { @Getter private Mail mail = null; @Override - public void sendLoginFilled(LoginFormDataDTO data) { + public void sendLoginFilled(SurveyResponseDTO data) { this.mail = MailServiceImpl.createContentFromData(data); } @@ -97,7 +97,7 @@ public class LoginFormResourceTest extends JerseyTest { @Override protected final Application configure() { - return new ResourceConfig(LoginFormResource.class).register(new AbstractBinder() { + return new ResourceConfig(SurveyFormResource.class).register(new AbstractBinder() { @Override protected void configure() { bind(questionsDao).to(QuestionsDao.class); @@ -111,7 +111,7 @@ public class LoginFormResourceTest extends JerseyTest { @Test public void getResponses() { // On récupère les questions via le webservice - final String jsonQuestions = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_QUESTIONS_LIST).request().get(String.class); + final String jsonQuestions = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_QUESTIONS_LIST).request().get(String.class); assertNotNull(jsonQuestions, "Impossible de récupérer la ressource (objet null) pour les questions"); assertFalse(jsonQuestions.isEmpty(), "La chaine de caractère JSON des questions est vide"); try { @@ -120,7 +120,7 @@ public class LoginFormResourceTest extends JerseyTest { assertNotEquals(questions.size(), 0, "La liste de questions est vide"); // On récupère l'ensemble des réponses - final String jsonAllResponses = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_RESPONSES_LIST).request().get(String.class); + final String jsonAllResponses = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_RESPONSES_LIST).request().get(String.class); assertNotNull(jsonAllResponses, "Impossible de récupérer la ressource (objet null) des réponses"); assertFalse(jsonAllResponses.isEmpty(), "La chaine de caractère JSON des réponses est vide"); @@ -135,7 +135,7 @@ public class LoginFormResourceTest extends JerseyTest { // Pour chaque question, for (final Question q : questions) { // on vérifie que la question est retrouvable par la catégorie, via le webservice - final String jsonCategory = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_QUESTION_BY_CATEGORY) + final String jsonCategory = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_QUESTION_BY_CATEGORY) .queryParam("category", q.getCategory()) .request().get(String.class); @@ -152,7 +152,7 @@ public class LoginFormResourceTest extends JerseyTest { assertEquals(questionByDao, q, "La question lue par le DAO ne correspond pas avec la question n° " + q.getId() + "d'origine"); // on récupère les réponses associées via le webservice - final String jsonResponses = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_RESPONSES_BY_QUESTION_LIST) + final String jsonResponses = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_RESPONSES_BY_QUESTION_LIST) .queryParam("questionRef", String.valueOf(q.getId())) .request() .get(String.class); @@ -186,7 +186,7 @@ public class LoginFormResourceTest extends JerseyTest { this.resetUserResponses(); final String category = "origin"; // Question - final String jsonOrigins = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_QUESTION_BY_CATEGORY) + final String jsonOrigins = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_QUESTION_BY_CATEGORY) .queryParam("category", category) .request().get(String.class); assertNotNull(jsonOrigins, "Impossible de récupérer la ressource (objet null) de la catégorie pour la question de l'origine"); @@ -196,7 +196,7 @@ public class LoginFormResourceTest extends JerseyTest { assertEquals(origin, questionsDao.findByCategory(category), "La question lue dans le webservice ne correspond pas avec la question via le DAO"); // on récupère les réponses de la question - final List<Response> responses = objectMapper.readValue(target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_RESPONSES_BY_QUESTION_LIST) + final List<Response> responses = objectMapper.readValue(target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_RESPONSES_BY_QUESTION_LIST) .queryParam("questionRef", String.valueOf(origin.getId())) .request() .get(String.class), new TypeReference<List<Response>>() {}); @@ -215,7 +215,7 @@ public class LoginFormResourceTest extends JerseyTest { form.param("responseRef", String.valueOf(r.getId())); form.param("otherText", "null"); - target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE) + target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE) .request(MediaType.TEXT_PLAIN) .post(Entity.form(form)); listOfResponses.add(r); @@ -236,7 +236,7 @@ public class LoginFormResourceTest extends JerseyTest { f.param("responseRef", String.valueOf(res.getId())); f.param("otherText", "null"); - target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE) + target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE) .request(MediaType.TEXT_PLAIN) .post(Entity.form(f)); @@ -263,7 +263,7 @@ public class LoginFormResourceTest extends JerseyTest { formOther.param("responseRef", "null"); formOther.param("otherText", other); - target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE) + target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE) .request(MediaType.TEXT_PLAIN) .post(Entity.form(formOther)); @@ -289,7 +289,7 @@ public class LoginFormResourceTest extends JerseyTest { public void testWithJsonResponses() { this.resetUserResponses(); final List<Question> questionsList = questionsDao.findAll(); - final List<QuestionDTO> questionsDTO = questionsList.stream().map(LoginFormResource::toDto).toList(); + final List<SurveyQuestionDTO> questionsDTO = questionsList.stream().map(SurveyFormResource::toDto).toList(); final List<Response> responsesList = new ArrayList<>(); final HashMap<Long, String> otherTextMap = new HashMap<>(); @@ -307,15 +307,15 @@ public class LoginFormResourceTest extends JerseyTest { otherTextMap.put(q.getId(), "Réponse libre pour la question « " + q.getDescription() + " »"); } - final List<ResponseDTO> responsesDTO = responsesList.stream().map(LoginFormResource::toDto).toList(); + final List<SurveyOptionDTO> responsesDTO = responsesList.stream().map(SurveyFormResource::toDto).toList(); - final LoginFormDataDTO data = new LoginFormDataDTO(questionsDTO, responsesDTO, otherTextMap); + final SurveyResponseDTO data = new SurveyResponseDTO(questionsDTO, responsesDTO, otherTextMap); assertEquals(data.getQuestions(), questionsDTO, "La liste de questions dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); assertEquals(data.getResponses(), responsesDTO, "La liste de réponses dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); assertEquals(data.getOtherTextMap(), otherTextMap, "La liste de réponses libre dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); - jakarta.ws.rs.core.Response ret = target(LoginFormResource.PATH + SEP + LoginFormResource.PATH_INSERT_RESPONSE_WITH_JSON) + jakarta.ws.rs.core.Response ret = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE_WITH_JSON) .request(MediaType.APPLICATION_JSON).post(Entity.entity(data, MediaType.APPLICATION_JSON)); assertEquals(ret.getStatus(), jakarta.ws.rs.core.Response.Status.OK.getStatusCode(), "Le point d'entrée d'insertion doit retourner le code status 200 (OK)"); diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyOptionDTO.java similarity index 81% rename from www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java rename to www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyOptionDTO.java index 849f10b..438217d 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/ResponseDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyOptionDTO.java @@ -6,12 +6,12 @@ package fr.agrometinfo.www.shared.dto; import org.dominokit.jackson.annotation.JSONMapper; /** - * DTO for responses of login form. + * DTO for responses (as options) for survey form. * @author jdecome * */ @JSONMapper -public class ResponseDTO { +public class SurveyOptionDTO { /** * Ref of this response. */ @@ -19,7 +19,7 @@ public class ResponseDTO { /** * DTO of question associated to response. */ - private QuestionDTO question; + private SurveyQuestionDTO question; /** * Label of response. */ @@ -33,7 +33,7 @@ public class ResponseDTO { /** * @return the question */ - public QuestionDTO getQuestion() { + public SurveyQuestionDTO getQuestion() { return question; } /** @@ -51,7 +51,7 @@ public class ResponseDTO { /** * @param dto the question to set */ - public void setQuestion(final QuestionDTO dto) { + public void setQuestion(final SurveyQuestionDTO dto) { this.question = dto; } /** diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java similarity index 94% rename from www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java rename to www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java index cab54a7..78ceb88 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/QuestionDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java @@ -13,7 +13,7 @@ import org.dominokit.jackson.annotation.JSONMapper; * */ @JSONMapper -public class QuestionDTO { +public class SurveyQuestionDTO { /** * Ref of question. */ @@ -79,7 +79,7 @@ public class QuestionDTO { if (getClass() != obj.getClass()) { return false; } - QuestionDTO other = (QuestionDTO) obj; + SurveyQuestionDTO other = (SurveyQuestionDTO) obj; return Objects.equals(category, other.category) && Objects.equals(description, other.description) && id == other.id; } diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java similarity index 73% rename from www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java rename to www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java index 30493a8..8982cea 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/LoginFormDataDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java @@ -12,17 +12,17 @@ import java.util.List; * @author jdecome * */ -public class LoginFormDataDTO { +public class SurveyResponseDTO { /** * List of login form questions.<br> * This list questions contains available questions, obtained by {@link QuestionsDao} */ - private List<QuestionDTO> questions; + private List<SurveyQuestionDTO> questions; /** * List of login form responses.<br> * This list responses contains available responses, obtained by {@link ResponsesDao} */ - private List<ResponseDTO> responses; + private List<SurveyOptionDTO> responses; /** * Storage, for each response, the other text, if specified. */ @@ -30,7 +30,7 @@ public class LoginFormDataDTO { /** * Default constructor. */ - public LoginFormDataDTO() { + public SurveyResponseDTO() { } /** * Constructor. @@ -38,8 +38,8 @@ public class LoginFormDataDTO { * @param rList responses list * @param otherText otherText map */ - public LoginFormDataDTO(final List<QuestionDTO> qList, - final List<ResponseDTO> rList, final HashMap<Long, String> otherText) { + public SurveyResponseDTO(final List<SurveyQuestionDTO> qList, + final List<SurveyOptionDTO> rList, final HashMap<Long, String> otherText) { this.questions = qList; this.responses = rList; this.otherTextMap = otherText; @@ -47,13 +47,13 @@ public class LoginFormDataDTO { /** * @return the questions */ - public List<QuestionDTO> getQuestions() { + public List<SurveyQuestionDTO> getQuestions() { return questions; } /** * @return the responses */ - public List<ResponseDTO> getResponses() { + public List<SurveyOptionDTO> getResponses() { return responses; } /** @@ -65,13 +65,13 @@ public class LoginFormDataDTO { /** * @param questionsList the questions to set */ - public void setQuestions(final List<QuestionDTO> questionsList) { + public void setQuestions(final List<SurveyQuestionDTO> questionsList) { this.questions = questionsList; } /** * @param responsesList the responses to set */ - public void setResponses(final List<ResponseDTO> responsesList) { + public void setResponses(final List<SurveyOptionDTO> responsesList) { this.responses = responsesList; } /** diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java similarity index 69% rename from www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java rename to www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java index 94083e2..a253ead 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/LoginFormService.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java @@ -12,9 +12,9 @@ import javax.ws.rs.Path; import org.dominokit.rest.shared.request.service.annotations.RequestFactory; import org.dominokit.rest.shared.request.service.annotations.RequestBody; -import fr.agrometinfo.www.shared.dto.LoginFormDataDTO; -import fr.agrometinfo.www.shared.dto.QuestionDTO; -import fr.agrometinfo.www.shared.dto.ResponseDTO; +import fr.agrometinfo.www.shared.dto.SurveyResponseDTO; +import fr.agrometinfo.www.shared.dto.SurveyQuestionDTO; +import fr.agrometinfo.www.shared.dto.SurveyOptionDTO; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.FormParam; import jakarta.ws.rs.QueryParam; @@ -24,31 +24,31 @@ import jakarta.ws.rs.QueryParam; * */ @RequestFactory -@Path(LoginFormService.PATH) -public interface LoginFormService { +@Path(SurveyFormService.PATH) +public interface SurveyFormService { /** Service base path. */ String PATH = "login"; - /** Path for {@link LoginFormService#getQuestions()}. */ + /** Path for {@link SurveyFormService#getQuestions()}. */ String PATH_QUESTIONS_LIST = "questions"; - /**Path for {@link LoginFormService#getQuestionByCategory(String)}. */ + /**Path for {@link SurveyFormService#getQuestionByCategory(String)}. */ String PATH_QUESTION_BY_CATEGORY = "question"; - /** Path for {@link LoginFormService#getResponses}. */ + /** Path for {@link SurveyFormService#getResponses}. */ String PATH_RESPONSES_LIST = "responses"; - /** Path for {@link LoginFormService#getResponsesByQuestion(long)}. */ + /** Path for {@link SurveyFormService#getResponsesByQuestion(long)}. */ String PATH_RESPONSES_BY_QUESTION_LIST = "responsesByQuestion"; - /** Path for {@link LoginFormService#getResponses()}. */ + /** Path for {@link SurveyFormService#getResponses()}. */ String PATH_INSERT_RESPONSE = "insert"; - /** Path for {@link LoginFormService#insertResponse(String)}. */ + /** Path for {@link SurveyFormService#insertResponse(String)}. */ String PATH_INSERT_RESPONSE_WITH_JSON = "insertMultipleValues"; /** * @return list of questions. */ @GET @Path(PATH_QUESTIONS_LIST) - List<QuestionDTO> getQuestions(); + List<SurveyQuestionDTO> getQuestions(); @GET @Path(PATH_RESPONSES_LIST) - List<ResponseDTO> getResponses(); + List<SurveyOptionDTO> getResponses(); /** * Get question by his category. * @param category of the question @@ -56,7 +56,7 @@ public interface LoginFormService { */ @GET @Path(PATH_QUESTION_BY_CATEGORY) - QuestionDTO getQuestionByCategory(@QueryParam(value = "category") String category); + SurveyQuestionDTO getQuestionByCategory(@QueryParam(value = "category") String category); /** * Returning the list of possible response for one question. * @param questionRef ref of question @@ -64,7 +64,7 @@ public interface LoginFormService { */ @GET @Path(PATH_RESPONSES_BY_QUESTION_LIST) - List<ResponseDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") Long questionRef); + List<SurveyOptionDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") Long questionRef); /** * Insert response or text for specified question.<br> * If responseRef is provided, {@code otherText} must be null.<br> @@ -87,5 +87,5 @@ public interface LoginFormService { */ @POST @Path(PATH_INSERT_RESPONSE_WITH_JSON) - String insertAllResponses(@RequestBody LoginFormDataDTO data); + String insertAllResponses(@RequestBody SurveyResponseDTO data); } -- GitLab From 56824e83f532def732e1f80a46682ebef5d41656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Mon, 27 May 2024 15:35:11 +0200 Subject: [PATCH 12/30] =?UTF-8?q?Modification=20de=20la=20transaction=20po?= =?UTF-8?q?ur=20la=20m=C3=A9thode=20deleteAll()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agrometinfo/www/server/dao/DaoHibernate.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java index 5045a5d..14fa4db 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java @@ -91,11 +91,15 @@ public abstract class DaoHibernate<T> { */ public void deleteAll() { LOGGER.traceEntry(); - final ScopedEntityManager em = getScopedEntityManager(); - final Query q = em.createQuery("DELETE FROM " + clazz.getName() + " t"); - em.getTransaction().begin(); - q.executeUpdate(); - em.getTransaction().commit(); + try (ScopedEntityManager em = getScopedEntityManager()) { + final Query q = em.createQuery("DELETE FROM " + clazz.getName() + " t"); + em.getTransaction().begin(); + q.executeUpdate(); + em.getTransaction().commit(); + } catch (final Exception e) { + LOGGER.catching(e); + } + LOGGER.traceExit(); } /** -- GitLab From 3639cb42d3550ca13736db623625a779d7ca8c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Mon, 27 May 2024 16:17:16 +0200 Subject: [PATCH 13/30] corrections pmd --- config/pmd-suppressions.properties | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/config/pmd-suppressions.properties b/config/pmd-suppressions.properties index 89c8232..a22f226 100644 --- a/config/pmd-suppressions.properties +++ b/config/pmd-suppressions.properties @@ -8,17 +8,17 @@ fr.agrometinfo.www.shared.dto.IndicatorDTOBeanJsonDeserializerImpl=UnnecessaryIm fr.agrometinfo.www.shared.dto.IndicatorDTOBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.IndicatorDTO_MapperImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.MessageDTOBeanJsonSerializerImpl=UnnecessaryImport -fr.agrometinfo.www.shared.dto.LoginFormDataDTOBeanJsonSerializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.SurveyResponseDTOBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.PeriodDTOBeanJsonDeserializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.PeriodDTOBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.PeriodDTO_MapperImpl=UnnecessaryImport -fr.agrometinfo.www.shared.dto.QuestionDTOBeanJsonDeserializerImpl=UnnecessaryImport -fr.agrometinfo.www.shared.dto.QuestionDTOBeanJsonSerializerImpl=UnnecessaryImport -fr.agrometinfo.www.shared.dto.QuestionDTO_MapperImpl=UnnecessaryImport -fr.agrometinfo.www.shared.dto.ResponseDTOBeanJsonSerializerImpl=UnnecessaryImport -fr.agrometinfo.www.shared.dto.ResponseDTOBeanJsonDeserializerImpl=UnnecessaryImport -fr.agrometinfo.www.shared.dto.ResponseDTO_MapperImpl=UnnecessaryImport -fr.agrometinfo.www.shared.service.ResponseDTO_MapperImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.SurveyQuestionDTOBeanJsonDeserializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.SurveyQuestionDTOBeanJsonSerializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.SurveyQuestionDTO_MapperImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.SurveyOptionDTOBeanJsonSerializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.SurveyOptionDTOBeanJsonDeserializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.dto.SurveyOptionDTO_MapperImpl=UnnecessaryImport +fr.agrometinfo.www.shared.service.SurveyOptionDTO_MapperImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.SimpleFeatureBeanJsonDeserializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.SimpleFeatureBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.SummaryDTOBeanJsonDeserializerImpl=UnnecessaryImport @@ -26,9 +26,9 @@ fr.agrometinfo.www.shared.dto.SummaryDTOBeanJsonSerializerImpl=UnnecessaryImport fr.agrometinfo.www.shared.dto.SummaryDTO_MapperImpl=UnnecessaryImport fr.agrometinfo.www.shared.service.ApplicationServiceFactory=UnnecessaryImport fr.agrometinfo.www.shared.service.IndicatorServiceFactory=UnnecessaryImport -fr.agrometinfo.www.shared.service.LoginFormServiceFactory=UnnecessaryImport -fr.agrometinfo.www.shared.service.QuestionDTO_MapperImpl=UnnecessaryImport -fr.agrometinfo.www.shared.service.ResponseDTOBeanJsonDeserializerImpl=UnnecessaryImport +fr.agrometinfo.www.shared.service.SurveyFormServiceFactory=UnnecessaryImport +fr.agrometinfo.www.shared.service.SurveyQuestionDTO_MapperImpl=UnnecessaryImport +fr.agrometinfo.www.shared.service.SurveyOptionDTOBeanJsonDeserializerImpl=UnnecessaryImport org.geojson.FeatureBeanJsonDeserializerImpl=UnnecessaryImport org.geojson.FeatureBeanJsonSerializerImpl=UnnecessaryImport org.geojson.FeatureCollectionBeanJsonDeserializerImpl=UnnecessaryImport -- GitLab From 4d49b7a383e0c6bdadca6fd5ecd64760bf2d8041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Tue, 28 May 2024 07:59:16 +0200 Subject: [PATCH 14/30] corrections checkstyle commit 2f4ce26e --- .../main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java | 1 - 1 file changed, 1 deletion(-) diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java index 14fa4db..48899a6 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java @@ -99,7 +99,6 @@ public abstract class DaoHibernate<T> { } catch (final Exception e) { LOGGER.catching(e); } - LOGGER.traceExit(); } /** -- GitLab From d8d76f5e9204fdca9faa92fc00bd42d2fffefb4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Tue, 28 May 2024 09:41:13 +0200 Subject: [PATCH 15/30] Utiliser des LinkedHashSet pour les listes. fixes #5 --- .../www/client/presenter/SurveyPresenter.java | 25 +++++++++++-------- .../www/server/rs/SurveyFormResource.java | 16 +++--------- .../www/shared/dto/SurveyResponseDTO.java | 7 +++--- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java index 13d349d..eb295e7 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java @@ -17,6 +17,9 @@ import fr.agrometinfo.www.shared.service.SurveyFormServiceFactory; import java.util.HashMap; import java.util.Map; +import java.util.LinkedHashSet; +import java.util.Set; + /** * Presenter for survey form. * @@ -88,37 +91,37 @@ public final class SurveyPresenter implements Presenter { .onFailed(view::failureNotification) .send(); } - public void insertUserResponses(final List<Long> responsesRef, final HashMap<Long, String> otherTextMap) { + public void insertUserResponses(final List<Long> responsesRef, final Map<Long, String> otherTextMap) { GWT.log("Insère les réponses de l'utilisateur"); // traitement des réponses prédéfinies - final List<SurveyQuestionDTO> questionsDto = new ArrayList<>(); - final List<SurveyOptionDTO> responsesDto = new ArrayList<>(); + final Set<SurveyQuestionDTO> questionsDto = new LinkedHashSet<>(); + final Set<SurveyOptionDTO> responsesDto = new LinkedHashSet<>(); for (final Long ref : responsesRef) { // on récupère la réponse correspondante à la référence final SurveyOptionDTO rDto = this.responses.stream().filter(r -> r.getId() == ref).findFirst().get(); if (rDto != null) { - if (!responsesDto.contains(rDto)) { - responsesDto.add(rDto); - } + responsesDto.add(rDto); // on récupère la question correspondantes à la réponse - if (!questionsDto.contains(rDto.getQuestion())) { - questionsDto.add(rDto.getQuestion()); - } + questionsDto.add(rDto.getQuestion()); } } // ajout de la question, si celle çi n'a qu'une réponse libre this.questions.forEach((q) -> { - if (!questionsDto.contains(q) && otherTextMap.containsKey(q.getId())) { + if (otherTextMap.containsKey(q.getId())) { questionsDto.add(q); } }); // envoi au webservice - final SurveyResponseDTO data = new SurveyResponseDTO(questionsDto, responsesDto, otherTextMap); + final SurveyResponseDTO data = new SurveyResponseDTO( + new ArrayList<SurveyQuestionDTO>(questionsDto), + new ArrayList<SurveyOptionDTO>(responsesDto), + otherTextMap); + SurveyFormServiceFactory.INSTANCE.insertAllResponses(data) .onSuccess(view::displaySuccessLogin) .onFailed(view::failureNotification) diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java index 67e57b1..d8f86ec 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java @@ -129,12 +129,8 @@ public class SurveyFormResource implements SurveyFormService { @Produces(MediaType.APPLICATION_JSON) @Override public List<SurveyQuestionDTO> getQuestions() { - final List<Question> list = questionsDao.findAll(); - final List<SurveyQuestionDTO> questions = new ArrayList<>(); - for (Question q : list) { - questions.add(toDto(q)); - } - return questions; + return questionsDao.findAll().stream() + .map(SurveyFormResource::toDto).collect(Collectors.toList()); } @GET @Path(SurveyFormService.PATH_QUESTION_BY_CATEGORY) @@ -166,12 +162,8 @@ public class SurveyFormResource implements SurveyFormService { @Produces(MediaType.APPLICATION_JSON) @Override public List<SurveyOptionDTO> getResponses() { - final List<Response> list = responsesDao.findAll(); - final List<SurveyOptionDTO> responses = new ArrayList<>(); - for (final Response r : list) { - responses.add(toDto(r)); - } - return responses; + return responsesDao.findAll().stream() + .map(SurveyFormResource::toDto).collect(Collectors.toList()); } @POST @Path(SurveyFormService.PATH_INSERT_RESPONSE) diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java index 8982cea..57cc022 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java @@ -5,6 +5,7 @@ package fr.agrometinfo.www.shared.dto; import java.util.HashMap; import java.util.List; +import java.util.Map; /** @@ -26,7 +27,7 @@ public class SurveyResponseDTO { /** * Storage, for each response, the other text, if specified. */ - private HashMap<Long, String> otherTextMap = new HashMap<>(); + private Map<Long, String> otherTextMap = new HashMap<>(); /** * Default constructor. */ @@ -39,7 +40,7 @@ public class SurveyResponseDTO { * @param otherText otherText map */ public SurveyResponseDTO(final List<SurveyQuestionDTO> qList, - final List<SurveyOptionDTO> rList, final HashMap<Long, String> otherText) { + final List<SurveyOptionDTO> rList, final Map<Long, String> otherText) { this.questions = qList; this.responses = rList; this.otherTextMap = otherText; @@ -59,7 +60,7 @@ public class SurveyResponseDTO { /** * @return the otherTextMap */ - public HashMap<Long, String> getOtherTextMap() { + public Map<Long, String> getOtherTextMap() { return otherTextMap; } /** -- GitLab From a6be7ad9ef80b1293424d1fc7f0e0065cebf0a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Tue, 28 May 2024 11:14:50 +0200 Subject: [PATCH 16/30] =?UTF-8?q?Modifier=20la=20fa=C3=A7on=20d'=C3=A9crir?= =?UTF-8?q?e=20la=20date=20et=20l'heure=20pour=20la=20colonne=20user2respo?= =?UTF-8?q?nses.datetime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../www/server/dao/UserResponsesDaoHibernate.java | 5 ----- .../java/fr/agrometinfo/www/server/model/UserResponse.java | 6 +++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java index 8d147b9..3ebd4c7 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java @@ -3,9 +3,6 @@ */ package fr.agrometinfo.www.server.dao; -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; @@ -38,8 +35,6 @@ public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implem @Override public void insertResponse(final Question q, final Response r, final String otherText) { final UserResponse ur = new UserResponse(); - ur.setDateTime(Timestamp.valueOf(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") - .format(LocalDateTime.now()))); ur.setQuestion(q); ur.setResponse(r); ur.setOtherText(otherText); diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java index a143f06..1666da5 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java @@ -3,7 +3,7 @@ */ package fr.agrometinfo.www.server.model; -import java.sql.Timestamp; +import java.time.LocalDateTime; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -28,9 +28,9 @@ public class UserResponse { @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private long id; - /** Date time of user responses. */ + /** Date time of user responses (creation date). */ @Column(name = "datetime") - private Timestamp dateTime; + private LocalDateTime dateTime = LocalDateTime.now(); /** Related question. */ @OneToOne @JoinColumn(name = "question") -- GitLab From dfe04f2ae9dc45dc60ec61a9ab7e4dbee8b4fb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Tue, 28 May 2024 11:21:38 +0200 Subject: [PATCH 17/30] correction contenu mail --- .../java/fr/agrometinfo/www/server/service/MailServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java index 2a2933f..4f614ef 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java @@ -351,7 +351,7 @@ public class MailServiceImpl implements MailService { final StringBuilder builder = new StringBuilder(); builder.append("Bonjour,\n"); - builder.append("Un utilisateur vient de remplir le formulaire d'enquête d'AgroMetInfo à l'instant.\\n\\n"); + builder.append("Un utilisateur vient de remplir le formulaire d'enquête d'AgroMetInfo à l'instant.\n\n"); builder.append("Il a répondu à " + data.getQuestions().size() + " question(s) :\n"); data.getQuestions().forEach((q) -> { -- GitLab From ddcbb285f08452fb8a36a490045cb1df03634b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Tue, 28 May 2024 11:37:07 +0200 Subject: [PATCH 18/30] =?UTF-8?q?Tri=20des=20cl=C3=A9s=20i18n=20par=20ordr?= =?UTF-8?q?e=20alphab=C3=A9tique=20et=20modification=20des=20cl=C3=A9s=20p?= =?UTF-8?q?our=20le=20formulaire?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../www/client/i18n/AppConstants.java | 79 ++++++++++++------- .../www/client/view/SurveyView.java | 14 ++-- .../client/i18n/AppConstants_fr.properties | 21 +++-- 3 files changed, 69 insertions(+), 45 deletions(-) diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java index 0c09cec..5c89b9a 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java @@ -183,6 +183,12 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo @DefaultStringValue("HTTP status text:") String failureStatusText(); + /** + * @return translation + */ + @DefaultStringValue("Ignorer") + String ignore(); + /** * @return translation */ @@ -314,8 +320,8 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo /** * @return translation */ - @DefaultStringValue("Toggle right panel") - String toggleRightPanel(); + @DefaultStringValue("Formulaire d'enquête") + String surveyFormTitle(); /** * @return translation @@ -327,6 +333,18 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo + "or use the contact form.") String welcomeBody(); + /** + * @return + */ + @DefaultStringValue("Welcome to the new version of AgroMetInfo !<br/>" + + "To help us improve the application and make it as responsive as possible to your needs, " + + "<b>please fill in the short survey below</b> (it will take 2 minutes maximum).<br/>" + + "All information is anonymous, but will help us to better understand how you use the application." + + "<br/><b>Don't hesitate to give us your email address</b> " + + "so that we can keep you informed of all developments in the coming months and years." + + "<br/><br/>The AgroMetInfo development team") + String surveyFormDescription(); + /** * @return translation */ @@ -334,56 +352,57 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo String welcomeTitle(); /** - * @return translation + * @return */ - @DefaultStringValue("Yes") - String yes(); + @DefaultStringValue("Other") + String surveyFormOtherTextCheckbox(); - // Formulaire d'enquête - #5 /** * @return translation */ - @DefaultStringValue("Valider") - String validate(); + @DefaultStringValue("You must click on checkbox above for activate this input field.") + String surveyFormOtherTextTooltip(); + /** - * @return translation - */ - @DefaultStringValue("Ignorer") - String ignore(); + * @return translation + */ + @DefaultStringValue("Your responses have been recorded.") + String surveyFormSuccess(); + /** * @return translation */ - @DefaultStringValue("Formulaire d'enquête") - String loginFormTitle(); + @DefaultStringValue("Your responses cannot been recorded, but you can use AgroMetInfo application.") + String surveyFormFail(); + /** * @return translation */ - @DefaultStringValue("Welcome to the new version of AgroMetInfo !<br/>" - + "To help us improve the application and make it as responsive as possible to your needs, " - + "<b>please fill in the short survey below</b> (it will take 2 minutes maximum).<br/>" - + "All information is anonymous, but will help us to better understand how you use the application." - + "<br/><b>Don't hesitate to give us your email address</b> " - + "so that we can keep you informed of all developments in the coming months and years." - + "<br/><br/>The AgroMetInfo development team") - String loginFormDescription(); + @DefaultStringValue("Toggle right panel") + String toggleRightPanel(); + /** * @return translation */ - @DefaultStringValue("Other") - String loginFormOtherTextCheckbox(); + @DefaultStringValue("Profile and settings") + String userProfile(); + /** * @return translation */ - @DefaultStringValue("You must click on checkbox above for activate this input field.") - String loginFormOtherTextTooltip(); + @DefaultStringValue("Valider") + String validate(); + /** * @return translation */ - @DefaultStringValue("Your responses have been recorded.") - String loginFormSuccess(); + @DefaultStringValue("You must be identified to access AgroMetInfo due to Meteo-France agreements related to " + + "SAFRAN data exchanges with AgroClim.") + String whyConnectionIsRequired(); + /** * @return translation */ - @DefaultStringValue("Your responses cannot been recorded, but you can use AgroMetInfo application.") - String loginFormFail(); + @DefaultStringValue("Yes") + String yes(); } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java index adc2e38..5580d64 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java @@ -71,10 +71,10 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen final Map<Long, TextArea> otherTextArea = new HashMap<>(); - this.modal = ModalDialog.create(CSTS.loginFormTitle()).large().setAutoClose(true); + this.modal = ModalDialog.create(CSTS.surveyFormTitle()).large().setAutoClose(true); this.modal .appendChild(Elements.p() - .innerHtml(new SafeHtmlBuilder().appendHtmlConstant(CSTS.loginFormDescription()).toSafeHtml()) + .innerHtml(new SafeHtmlBuilder().appendHtmlConstant(CSTS.surveyFormDescription()).toSafeHtml()) ); for (Map.Entry<SurveyQuestionDTO, List<SurveyOptionDTO>> entry : this.availableResponses.entrySet()) { @@ -92,12 +92,12 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen }); // on affiche le champ pour la réponse libre - final CheckBox otherCb = CheckBox.create(CSTS.loginFormOtherTextCheckbox()) + final CheckBox otherCb = CheckBox.create(CSTS.surveyFormOtherTextCheckbox()) .id(k.getCategory() + "_other") .css("login-checkbox"); final TextArea otherText = TextArea.create().setId(k.getCategory() + "_other_text") .setDisabled(true) - .setTooltip(CSTS.loginFormOtherTextTooltip()) + .setTooltip(CSTS.surveyFormOtherTextTooltip()) .setRows(2) .css("login-textarea"); @@ -106,7 +106,7 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen if (!otherText.isDisabled()) { otherText.removeTooltip(); } else { - otherText.setTooltip(CSTS.loginFormOtherTextTooltip()); + otherText.setTooltip(CSTS.surveyFormOtherTextTooltip()); } }); this.checkBoxList.add(otherCb); @@ -159,7 +159,7 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen @Override public void failureNotification(final FailedResponseBean failedResponse) { - this.notification(CSTS.loginFormFail()); + this.notification(CSTS.surveyFormFail()); } @Override @@ -169,7 +169,7 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen @Override public void displaySuccessLogin(final String msg) { - this.notification(CSTS.loginFormSuccess()); + this.notification(CSTS.surveyFormSuccess()); } /** * Enable or disable validate button depending of checkbox status. diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties index fe21225..917d271 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties @@ -33,6 +33,10 @@ invalidEmailAddress = Adresse courriel invalide legalNotice = Mentions légales legalNoticePath = legal-notice.html messageSent = Votre message a bien été envoyé à l’équipe d’AgroMetInfo. +ignore = Ignorer +login = Se connecter +loginOrSignIn = ou s’inscrire avec +logout = Se déconnecter metropolitanFrance = France métropolitaine no = Non normalComparison= Comparaison à la normale @@ -43,6 +47,13 @@ releaseNotes = Notes de version releaseNotesPath = release-notes.html reloadingApplication = Rechargement de l'application pour une nouvelle version\u2026 seePrivacyPolicy = Consultez le paragraphe « Données personnelles » dans les mentions légales. +selectPrompt = -- sélectionner -- +surveyFormTitle = Formulaire d'enquête +surveyFormDescription = Bienvenu.e.s à la nouvelle version d'AgroMetInfo !<br/>Afin de nous aider à la faire évoluer et l'adapter le plus possible à vos besoins, <b>merci de renseigner</b> la petite enquête çi dessous (cela prendra 2 minutes maximum). L'ensemble des informations est anonyme, mais nous aidera à mieux comprendre l'utilisation de l'application. N'hésitez pas à <b>nous laisser votre adresse courriel</b> pour vous tenir informés de toutes les évolutions dans les mois et années à venir.<br/><br/>L'équipe AgroMetInfo. +surveyFormOtherTextCheckbox = Autre, à préciser +surveyFormOtherTextTooltip = Vous devez cliquer sur la case à cocher çi dessus pour activer ce champ de saisie. +surveyFormSuccess = Vos réponses au formulaire d'enquête ont bien été enregistrées. +surveyFormFail = Vos réponses au formulaire n'ont pas pu être enregistrées, mais vous pouvez tout de même utiliser AgroMetInfo. toggleRightPanel = Afficher / masquer le panneau de droite welcomeBody = AgroMetInfo est en cours de refonte.<br/>\ Pour rester au courant des évolutions, vous pouvez nous envoyer un message à \ @@ -50,12 +61,6 @@ Pour rester au courant des évolutions, vous pouvez nous envoyer un message à \ welcomeTitle = Bienvenue sur AgroMetInfo yes = Oui userProfile = Compte et paramètres -whyConnectionIsRequired = Vous devez vous identifier pour accéder à AgroMetInfo en raison des accords avec Météo-France relatifs aux échanges de données SAFRAN avec AgroClim. validate = Valider -ignore = Ignorer -loginFormTitle = Formulaire d'enquête -loginFormDescription = Bienvenu.e.s à la nouvelle version d'AgroMetInfo !<br/>Afin de nous aider à la faire évoluer et l'adapter le plus possible à vos besoins, <b>merci de renseigner</b> la petite enquête çi dessous (cela prendra 2 minutes maximum). L'ensemble des informations est anonyme, mais nous aidera à mieux comprendre l'utilisation de l'application. N'hésitez pas à <b>nous laisser votre adresse courriel</b> pour vous tenir informés de toutes les évolutions dans les mois et années à venir.<br/><br/>L'équipe AgroMetInfo. -loginFormOtherTextCheckbox = Autre, à préciser -loginFormOtherTextTooltip = Vous devez cliquer sur la case à cocher çi dessus pour activer ce champ de saisie. -loginFormSuccess = Vos réponses au formulaire d'enquête ont bien été enregistrées. -loginFormFail = Vos réponses au formulaire n'ont pas pu être enregistrées, mais vous pouvez tout de même utiliser AgroMetInfo. \ No newline at end of file +whyConnectionIsRequired = Vous devez vous identifier pour accéder à AgroMetInfo en raison des accords avec Météo-France relatifs aux échanges de données SAFRAN avec AgroClim. +yes= Oui \ No newline at end of file -- GitLab From 2b14753463bba92dfc90fab008b2574e8a5acd8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Thu, 30 May 2024 14:22:22 +0200 Subject: [PATCH 19/30] =?UTF-8?q?Corrections=20suite=20revue=20de=20code?= =?UTF-8?q?=20(libell=C3=A9s=20des=20options=20aux=20questions,=20commenta?= =?UTF-8?q?ires=20code)=20Ajout=20de=20l'adresse=20mail=20dans=20le=20form?= =?UTF-8?q?ulaire=20d'enqu=C3=AAte?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/responses.csv | 2 +- sql/schema.tables.sql | 7 ++ .../www/client/i18n/AppConstants.java | 6 ++ .../www/client/presenter/SurveyPresenter.java | 11 +++- .../www/client/view/SurveyView.java | 10 ++- .../client/i18n/AppConstants_fr.properties | 1 + .../www/server/dao/UserEmailDao.java | 25 +++++++ .../www/server/dao/UserEmailDaoHibernate.java | 31 +++++++++ .../www/server/dao/UserResponsesDao.java | 29 +++++++- .../server/dao/UserResponsesDaoHibernate.java | 25 +++++-- .../www/server/model/Question.java | 2 +- .../www/server/model/Response.java | 2 +- .../www/server/model/UserEmail.java | 39 +++++++++++ .../www/server/model/UserResponse.java | 2 +- .../www/server/rs/SurveyFormResource.java | 25 +++++-- .../www/server/util/EmailUtils.java | 25 +++++++ .../www/server/SurveyFormHibernateTest.java | 19 +++++- .../www/server/rs/SurveyFormResourceTest.java | 66 ++++++++++++++----- .../test/resources/META-INF/persistence.xml | 1 + .../www/shared/dto/SurveyResponseDTO.java | 19 +++++- 20 files changed, 309 insertions(+), 38 deletions(-) create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDaoHibernate.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/util/EmailUtils.java diff --git a/sql/responses.csv b/sql/responses.csv index 930e6f7..97e9914 100644 --- a/sql/responses.csv +++ b/sql/responses.csv @@ -10,7 +10,7 @@ question;description 2;Via le site internet d'AgroClim 2;Via le site internet INRAE 2;Média (TV, journaux, radio) -2;Réseaux sociaux (Linkedin, Facebook, X, ...) +2;Réseaux sociaux (Linkedin, Facebook, X…) 2;Bouche à oreilles 3;S'informer 3;Enseigner diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql index c4a57a7..79f133e 100644 --- a/sql/schema.tables.sql +++ b/sql/schema.tables.sql @@ -244,6 +244,13 @@ CREATE TABLE IF NOT EXISTS user2response ( ); COMMENT ON TABLE user2response IS 'Responses of user to questions, and other text if present'; +CREATE TABLE IF NOT EXISTS user_email ( + id SERIAL NOT NULL, + datetime TIMESTAMP NOT NULL, + email VARCHAR NOT NULL, + CONSTRAINT PK_user_email PRIMARY KEY (id) +); +COMMENT ON TABLE user_email IS 'Simple table for register email of user, when he fills out survey'; CREATE OR REPLACE VIEW v_i18n AS SELECT l.languagetag, diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java index 5c89b9a..8d5c483 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java @@ -345,6 +345,12 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo + "<br/><br/>The AgroMetInfo development team") String surveyFormDescription(); + /** + * @return translation + */ + @DefaultStringValue("Your e-mail address (optional) :") + String surveyFromEmailDescription(); + /** * @return translation */ diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java index eb295e7..85ebcdd 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java @@ -91,7 +91,10 @@ public final class SurveyPresenter implements Presenter { .onFailed(view::failureNotification) .send(); } - public void insertUserResponses(final List<Long> responsesRef, final Map<Long, String> otherTextMap) { + public void insertUserResponses( + final List<Long> responsesRef, + final Map<Long, String> otherTextMap, + final String email) { GWT.log("Insère les réponses de l'utilisateur"); // traitement des réponses prédéfinies @@ -115,13 +118,17 @@ public final class SurveyPresenter implements Presenter { } }); - // envoi au webservice final SurveyResponseDTO data = new SurveyResponseDTO( new ArrayList<SurveyQuestionDTO>(questionsDto), new ArrayList<SurveyOptionDTO>(responsesDto), otherTextMap); + // traitement de l'adresse e-mail + if (!email.isEmpty()) { + data.setEmail(email); + } + SurveyFormServiceFactory.INSTANCE.insertAllResponses(data) .onSuccess(view::displaySuccessLogin) .onFailed(view::failureNotification) diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java index 5580d64..2dfc9c9 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java @@ -9,6 +9,7 @@ import java.util.HashMap; import org.dominokit.domino.ui.button.Button; import org.dominokit.domino.ui.forms.CheckBox; import org.dominokit.domino.ui.forms.TextArea; +import org.dominokit.domino.ui.forms.TextBox; import org.dominokit.domino.ui.modals.ModalDialog; import org.dominokit.rest.shared.request.FailedResponseBean; import org.gwtproject.safehtml.shared.SafeHtmlBuilder; @@ -53,6 +54,10 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen private Button validate; /** List of all checkbox on modal. */ private List<CheckBox> checkBoxList = new ArrayList<>(); + /** + * E-mail field. + */ + private TextBox email; @Override public void close() { @@ -119,6 +124,9 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen }); // E-mail de l'utilisateur + this.modal.appendChild(Elements.p().textContent(CSTS.surveyFromEmailDescription())); + this.email = TextBox.create().setType("email"); + this.modal.appendChild(this.email); // Boutons de la fenêtre modale this.validate = Button.create(CSTS.validate()).linkify(); @@ -139,7 +147,7 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen } }); - this.getPresenter().insertUserResponses(selectedResponsesRef, otherTextMap); + this.getPresenter().insertUserResponses(selectedResponsesRef, otherTextMap, this.email.getValue()); ls.setItem(IS_VALIDATED_KEY, "true"); this.modal.close(); diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties index 917d271..fc13d99 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties @@ -50,6 +50,7 @@ seePrivacyPolicy = Consultez le paragraphe « Données personnelles » dans les selectPrompt = -- sélectionner -- surveyFormTitle = Formulaire d'enquête surveyFormDescription = Bienvenu.e.s à la nouvelle version d'AgroMetInfo !<br/>Afin de nous aider à la faire évoluer et l'adapter le plus possible à vos besoins, <b>merci de renseigner</b> la petite enquête çi dessous (cela prendra 2 minutes maximum). L'ensemble des informations est anonyme, mais nous aidera à mieux comprendre l'utilisation de l'application. N'hésitez pas à <b>nous laisser votre adresse courriel</b> pour vous tenir informés de toutes les évolutions dans les mois et années à venir.<br/><br/>L'équipe AgroMetInfo. +surveyFromEmailDescription = Votre adresse courriel (facultatif) : surveyFormOtherTextCheckbox = Autre, à préciser surveyFormOtherTextTooltip = Vous devez cliquer sur la case à cocher çi dessus pour activer ce champ de saisie. surveyFormSuccess = Vos réponses au formulaire d'enquête ont bien été enregistrées. diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java new file mode 100644 index 0000000..1c3503a --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java @@ -0,0 +1,25 @@ +package fr.agrometinfo.www.server.dao; + +import java.time.LocalDateTime; +import java.util.List; + +import fr.agrometinfo.www.server.model.UserEmail; + +/** + * DAO for {@link UserEmail}. + * @author jdecome + * + */ +public interface UserEmailDao { + /** + * Insert e-mail address in table. + * @param email + * @param datetime provided localdatetime + */ + void insertEmailUserAddress(String email, LocalDateTime datetime); + /** + * Getting all email address in database. + * @return list of email address + */ + List<UserEmail> getEmailAddressList(); +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDaoHibernate.java new file mode 100644 index 0000000..80388d2 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDaoHibernate.java @@ -0,0 +1,31 @@ +package fr.agrometinfo.www.server.dao; + +import java.time.LocalDateTime; +import java.util.List; + +import fr.agrometinfo.www.server.model.UserEmail; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * @author jdecome + * + */ +@ApplicationScoped +public final class UserEmailDaoHibernate extends DaoHibernate<UserEmail> implements UserEmailDao { + /** Default constructor. */ + public UserEmailDaoHibernate() { + super(UserEmail.class); + } + @Override + public void insertEmailUserAddress(final String email, final LocalDateTime datetime) { + final UserEmail um = new UserEmail(); + um.setEmail(email); + um.setDatetime(datetime); + this.save(um); + } + @Override + public List<UserEmail> getEmailAddressList() { + return super.findAll(); + } + +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java index 06260f1..2531e58 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java @@ -1,12 +1,13 @@ package fr.agrometinfo.www.server.dao; +import java.time.LocalDateTime; import java.util.List; import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; import fr.agrometinfo.www.server.model.UserResponse; /** - * DAO for {@link UserResponsesDao}. + * DAO for {@link UserResponse}. * @author jdecome */ public interface UserResponsesDao { @@ -19,21 +20,43 @@ public interface UserResponsesDao { /** * Insert response or text for specified question.<br> * If r is provided, {@code otherText} must be null.<br> - * If otherText is provided, {@code r} must be null. + * If otherText is provided, {@code r} must be null.<br> + * datetime is defined by {@link LocalDateTime#now} in this method. * @param q question to answer * @param r response * @param otherText text if response is other */ void insertResponse(Question q, Response r, String otherText); + /** + * Insert response or text for specified question.<br> + * If r is provided, {@code otherText} must be null.<br> + * If otherText is provided, {@code r} must be null. + * @param q question to answer + * @param r response + * @param otherText text if response is other + * @param datetime provided localdatetime + */ + void insertResponse(Question q, Response r, String otherText, LocalDateTime datetime); /** * Insert response or text for specified question, identified by reference.<br> * If responseRef is provided, {@code otherText} must be null.<br> - * If otherText is provided, {@code responseRef} must be null. + * If otherText is provided, {@code responseRef} must be null.<br> + * datetime is defined by {@link LocalDateTime#now} in this method. * @param questionRef reference of question to answer * @param responseRef reference of response * @param otherText text if response is other */ void insertResponse(Long questionRef, Long responseRef, String otherText); + /** + * Insert response or text for specified question, identified by reference.<br> + * If responseRef is provided, {@code otherText} must be null.<br> + * If otherText is provided, {@code responseRef} must be null. + * @param questionRef reference of question to answer + * @param responseRef reference of response + * @param otherText text if response is other + * @param datetime provided datetime + */ + void insertResponse(Long questionRef, Long responseRef, String otherText, LocalDateTime datetime); /** * Get all user responses. * @return number of responses diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java index 3ebd4c7..5f9aea3 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java @@ -3,6 +3,7 @@ */ package fr.agrometinfo.www.server.dao; +import java.time.LocalDateTime; import java.util.List; import java.util.Map; @@ -33,31 +34,45 @@ public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implem } /** */ @Override - public void insertResponse(final Question q, final Response r, final String otherText) { + public void insertResponse( + final Question q, final Response r, + final String otherText, final LocalDateTime datetime) { final UserResponse ur = new UserResponse(); + ur.setDateTime(datetime); ur.setQuestion(q); ur.setResponse(r); ur.setOtherText(otherText); this.save(ur); - } /** */ @Override - public void insertResponse(final Long questionRef, final Long responseRef, final String otherText) { + public void insertResponse(final Question q, final Response r, final String otherText) { + this.insertResponse(q, r, otherText, LocalDateTime.now()); + } + /** */ + @Override + public void insertResponse( + final Long questionRef, final Long responseRef, + final String otherText, final LocalDateTime datetime) { // recherche de la question final Question q = questionsDao.findByRef(questionRef); if (q != null) { if (responseRef != null) { // insertion d'une réponse prédéfinie, on recherche de la réponse final Response r = responsesDao.findByRef(responseRef); - this.insertResponse(q, r, null); + this.insertResponse(q, r, null, datetime); } else { // insertion d'une réponse libre - this.insertResponse(q, null, otherText); + this.insertResponse(q, null, otherText, datetime); } } } /** */ @Override + public void insertResponse(final Long questionRef, final Long responseRef, final String otherText) { + this.insertResponse(questionRef, responseRef, otherText, LocalDateTime.now()); + } + /** */ + @Override public int getNbUserResponses() { return super.findAll().size(); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java index 8f26872..3621392 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java @@ -12,7 +12,7 @@ import jakarta.persistence.Table; import lombok.Data; /** - * Questions for survey login modal. + * Questions for survey modal. * @author jdecome * */ diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java index 8e132f9..9ed8eba 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java @@ -14,7 +14,7 @@ import jakarta.persistence.Table; import lombok.Data; /** - * Available response. + * Options for questions. * @author jdecome * */ diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java new file mode 100644 index 0000000..015174c --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java @@ -0,0 +1,39 @@ +package fr.agrometinfo.www.server.model; + +import java.time.LocalDateTime; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; + +/** + * Table for storage email adress.<br> + * @author jdecome + * + */ +@Data +@Entity +@Table(name = "user_email") +public class UserEmail { + /** + * Primary key. + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + /** + * Date time of user response (creation date). + */ + @Column(name = "datetime") + private LocalDateTime datetime; + /** + * E-mail address. + */ + @Column(name = "email") + private String email; +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java index 1666da5..2b68c16 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java @@ -30,7 +30,7 @@ public class UserResponse { private long id; /** Date time of user responses (creation date). */ @Column(name = "datetime") - private LocalDateTime dateTime = LocalDateTime.now(); + private LocalDateTime dateTime; /** Related question. */ @OneToOne @JoinColumn(name = "question") diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java index d8f86ec..e964f86 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java @@ -3,17 +3,19 @@ */ package fr.agrometinfo.www.server.rs; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; - import fr.agrometinfo.www.server.dao.QuestionsDao; import fr.agrometinfo.www.server.dao.ResponsesDao; +import fr.agrometinfo.www.server.dao.UserEmailDao; import fr.agrometinfo.www.server.dao.UserResponsesDao; import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; import fr.agrometinfo.www.server.service.MailService; +import fr.agrometinfo.www.server.util.EmailUtils; import fr.agrometinfo.www.shared.dto.ErrorResponseDTO; import fr.agrometinfo.www.shared.dto.SurveyResponseDTO; import fr.agrometinfo.www.shared.dto.SurveyQuestionDTO; @@ -102,6 +104,11 @@ public class SurveyFormResource implements SurveyFormService { */ @Inject private UserResponsesDao userResponsesDao; + /** + * DAO for user email {@link UserEmailDao}. + */ + @Inject + private UserEmailDao userEmailDao; /** * Mail service. */ @@ -178,9 +185,9 @@ public class SurveyFormResource implements SurveyFormService { final boolean otherTextIsNull = otherText == null || otherText.equals("null"); if (this.checkIfQuestionExist(questionRef)) { if (!responseRefIsNull && otherTextIsNull) { // réponse prédéfinie - this.userResponsesDao.insertResponse(questionRef, Long.valueOf(responseRef), null); + this.userResponsesDao.insertResponse(questionRef, Long.valueOf(responseRef), null, LocalDateTime.now()); } else if (responseRefIsNull && !otherTextIsNull) { // réponse libre - this.userResponsesDao.insertResponse(questionRef, null, otherText); + this.userResponsesDao.insertResponse(questionRef, null, otherText, LocalDateTime.now()); } } } @@ -203,6 +210,9 @@ public class SurveyFormResource implements SurveyFormService { @Produces(MediaType.APPLICATION_JSON) @Override public String insertAllResponses(final SurveyResponseDTO data) { + // datetime commun à tous les enregistrements (des réponses et de l'email) + final LocalDateTime datetime = LocalDateTime.now(); + // traitement des réponses prédéfinies for (final SurveyQuestionDTO dto : data.getQuestions()) { // Pour chaque question répondue // Insérer les réponses associés @@ -215,16 +225,21 @@ public class SurveyFormResource implements SurveyFormService { // On insère les réponses prédéfinies for (final SurveyOptionDTO rDto : associatedResponses) { final Response r = toEntity(rDto); - this.userResponsesDao.insertResponse(q, r, null); + this.userResponsesDao.insertResponse(q, r, null, datetime); } // Si il existe une réponse libre, l'insérer if (data.getOtherTextMap().containsKey(dto.getId()) && data.getOtherTextMap().get(dto.getId()) != null) { - this.userResponsesDao.insertResponse(q, null, data.getOtherTextMap().get(q.getId())); + this.userResponsesDao.insertResponse(q, null, data.getOtherTextMap().get(q.getId()), datetime); } } + // Si l'utilisateur a fourni son adresse e-mail + if (EmailUtils.isEmailAddressValid(data.getEmail())) { + this.userEmailDao.insertEmailUserAddress(data.getEmail(), datetime); + } + // une fois que tout est inséré, on envoi un mail au support this.mailService.sendLoginFilled(data); return "0"; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/util/EmailUtils.java b/www-server/src/main/java/fr/agrometinfo/www/server/util/EmailUtils.java new file mode 100644 index 0000000..855de26 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/util/EmailUtils.java @@ -0,0 +1,25 @@ +package fr.agrometinfo.www.server.util; + +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; + +/** + * @author jdecome + * + */ +public class EmailUtils extends StringUtils { + /** + * Check if email address provided is a valid address.<br> + * Verification by not null and regex + * @param email address + * @return {@code true} or {@code false} + */ + public static final boolean isEmailAddressValid(final String email) { + if (email == null) { + return false; + } + final String emailPattern = "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"; + return Pattern.matches(emailPattern, email); + } +} diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index 93a8c1b..c4ecae8 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -9,6 +9,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -20,10 +21,13 @@ import fr.agrometinfo.www.server.dao.QuestionsDao; import fr.agrometinfo.www.server.dao.QuestionsDaoHibernate; import fr.agrometinfo.www.server.dao.ResponsesDao; import fr.agrometinfo.www.server.dao.ResponsesDaoHibernate; +import fr.agrometinfo.www.server.dao.UserEmailDao; +import fr.agrometinfo.www.server.dao.UserEmailDaoHibernate; import fr.agrometinfo.www.server.dao.UserResponsesDao; import fr.agrometinfo.www.server.dao.UserResponsesDaoHibernate; import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.UserEmail; import fr.agrometinfo.www.server.model.UserResponse; /** @@ -38,6 +42,8 @@ public class SurveyFormHibernateTest { private QuestionsDao questionsDao = new QuestionsDaoHibernate(); /** DAO for responses. */ private ResponsesDao responsesDao = new ResponsesDaoHibernate(); + /** DAO for email address of user. */ + private UserEmailDao userEmailDao = new UserEmailDaoHibernate(); @Test public void getQuestion() { @@ -171,8 +177,19 @@ public class SurveyFormHibernateTest { assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); } } + } + @Test + public void setUserResponsesWithEmail() { + // just testing insertion of email user, without insertion of responses (already tested) + final String email = "john.doe@inrae.fr"; + List<UserEmail> list = this.userEmailDao.getEmailAddressList(); + assertNotNull(list, "La liste des e-mail n'est pas initialisée"); + assertEquals(list.size(), 0, "La liste des e-mail est vide"); + this.userEmailDao.insertEmailUserAddress(email, LocalDateTime.now()); - + list = this.userEmailDao.getEmailAddressList(); + assertEquals(list.size(), 1, "La liste des e-mail doit contenir au moins un élément"); + assertEquals(list.get(0).getEmail(), email, "L'élément enregistré ne correspond pas avec le mail inséré « " + email + " »"); } /** * Return randomly responses list diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java index 5ffca0c..362b8d4 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java @@ -10,6 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -30,11 +31,14 @@ import fr.agrometinfo.www.server.dao.QuestionsDao; import fr.agrometinfo.www.server.dao.QuestionsDaoHibernate; import fr.agrometinfo.www.server.dao.ResponsesDao; import fr.agrometinfo.www.server.dao.ResponsesDaoHibernate; +import fr.agrometinfo.www.server.dao.UserEmailDao; +import fr.agrometinfo.www.server.dao.UserEmailDaoHibernate; import fr.agrometinfo.www.server.dao.UserResponsesDao; import fr.agrometinfo.www.server.dao.UserResponsesDaoHibernate; import fr.agrometinfo.www.server.exception.AgroMetInfoException; import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.UserEmail; import fr.agrometinfo.www.server.model.UserResponse; import fr.agrometinfo.www.server.service.MailService; import fr.agrometinfo.www.server.service.MailServiceImpl; @@ -92,6 +96,8 @@ public class SurveyFormResourceTest extends JerseyTest { private final ResponsesDao responsesDao = new ResponsesDaoHibernate(); /** DAO for UserResponses. */ private final UserResponsesDao userResponsesDao = new UserResponsesDaoHibernate(); + /** DAO for UserMail */ + private final UserEmailDao userEmailDao = new UserEmailDaoHibernate(); /** Mail service. */ private final MailService mailService = new MailServiceTest(); @@ -103,6 +109,7 @@ public class SurveyFormResourceTest extends JerseyTest { bind(questionsDao).to(QuestionsDao.class); bind(responsesDao).to(ResponsesDao.class); bind(userResponsesDao).to(UserResponsesDao.class); + bind(userEmailDao).to(UserEmailDao.class); bind(mailService).to(MailService.class); } }); @@ -310,35 +317,62 @@ public class SurveyFormResourceTest extends JerseyTest { final List<SurveyOptionDTO> responsesDTO = responsesList.stream().map(SurveyFormResource::toDto).toList(); final SurveyResponseDTO data = new SurveyResponseDTO(questionsDTO, responsesDTO, otherTextMap); + data.setEmail("john.doe@inrae.fr"); assertEquals(data.getQuestions(), questionsDTO, "La liste de questions dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); assertEquals(data.getResponses(), responsesDTO, "La liste de réponses dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); assertEquals(data.getOtherTextMap(), otherTextMap, "La liste de réponses libre dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); - jakarta.ws.rs.core.Response ret = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE_WITH_JSON) .request(MediaType.APPLICATION_JSON).post(Entity.entity(data, MediaType.APPLICATION_JSON)); assertEquals(ret.getStatus(), jakarta.ws.rs.core.Response.Status.OK.getStatusCode(), "Le point d'entrée d'insertion doit retourner le code status 200 (OK)"); - // Pour le test, vérifier, pour chaque question, les réponses via le DAO + // Récupère toutes les réponses pour toutes les questions + List<UserResponse> list = new ArrayList<>(); for (final Question q : questionsDao.findAll()) { - final List<UserResponse> list = userResponsesDao.findAllByQuestion(q.getId()); - assertNotNull(list, "La liste de réponses de l'utilisateur ne doit pas être null"); - for (final UserResponse ur : list) { - assertNotNull(ur.getDateTime(), "Le timestamp de la réponse ne doit pas être null"); + final List<UserResponse> responsesByQuestion = userResponsesDao.findAllByQuestion(q.getId()); + assertNotNull(responsesByQuestion, "La liste de réponses de l'utilisateur pour la question « " + q.getId() + " » ne doit pas être null"); + responsesByQuestion.forEach((ur) -> { assertEquals(ur.getQuestion(), q, "La question contenue dans la réponse ne correspond pas avec la question d'origine « " + q.getDescription() + " »"); - assertTrue(ur.getId() > 0, "la référence de la réponse de l'utilisateur doit être supérieur à 0"); - if (ur.getResponse() != null) { - assertNotNull(ur.getResponse(), "La réponse de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); - assertNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, doit être null"); - } else { - assertNull(ur.getResponse(), "La réponse de l'utilisateur, pour une réponse libre, doit être null"); - assertNotNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); - } - } + }); + list.addAll(responsesByQuestion); } - // on vérifie le mail + // Test sur toutes les réponses + list.forEach((ur) -> { + assertNotNull(ur.getDateTime(), "Le timestamp de la réponse ne doit pas être null"); + assertTrue(ur.getId() > 0, "la référence de la réponse de l'utilisateur doit être supérieur à 0"); + if (ur.getResponse() != null) { + assertNotNull(ur.getResponse(), "La réponse de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); + assertNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, doit être null"); + } else { + assertNull(ur.getResponse(), "La réponse de l'utilisateur, pour une réponse libre, doit être null"); + assertNotNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); + } + }); + + // on vérifie que tous les enregistrements ont le même datetime + assertEquals(list.stream().map((u) -> u.getDateTime()).distinct().count(), 1, "Toutes les réponses n'ont pas le même datetime"); + final LocalDateTime datetimeResponse = list.stream().map((u) -> u.getDateTime()).distinct().findFirst().get(); + assertNotNull(datetimeResponse, "Le datetime lue dans les réponses est null"); + + // dans ce cas de test, on a inséré l'adresse mail de l'utilisateur + final List<UserEmail> emails = this.userEmailDao.getEmailAddressList(); + assertNotNull(emails, "La liste des emails n'est pas initialisée"); + assertNotEquals(emails.size(), 0, "La liste des emails est vide"); + + emails.forEach((e) -> { + assertTrue((e.getId() > 0), "L'id de l'objet doit être supérieur à 0"); + assertNotNull(e.getDatetime(), "Le timestamp de la question ne doit pas être null"); + assertNotNull(e.getEmail(), "L'adresse mail contenue dans l'objet ne doit pas être null"); + }); + assertEquals(emails.stream().map((e) -> e.getDatetime()).distinct().count(), 1, "Toutes les adresses mails n'ont pas le même datetime"); + final LocalDateTime datetimeEmail = emails.stream().map((e) -> e.getDatetime()).distinct().findFirst().get(); + assertNotNull(datetimeEmail, "Le datetime lue dans les emails est null"); + + assertEquals(datetimeResponse, datetimeEmail, "Les deux datetime ne sont pas identique"); + + // on vérifie le mail envoyé au support, lorsqu'un utilisateur a rempli le formulaire final Mail mail = ((MailServiceTest) this.mailService).getMail(); assertNotNull(mail, "L'objet mail ne doit pas être null"); assertNotNull(mail.getContent(), "Le corps du message n'est pas défini (= null)"); diff --git a/www-server/src/test/resources/META-INF/persistence.xml b/www-server/src/test/resources/META-INF/persistence.xml index d790ccb..9f6b455 100644 --- a/www-server/src/test/resources/META-INF/persistence.xml +++ b/www-server/src/test/resources/META-INF/persistence.xml @@ -21,6 +21,7 @@ <class>fr.agrometinfo.www.server.model.Question</class> <class>fr.agrometinfo.www.server.model.Response</class> <class>fr.agrometinfo.www.server.model.UserResponse</class> + <class>fr.agrometinfo.www.server.model.UserEmail</class> <properties> <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:agrometinfo;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM '../sql/schema.types.h2.sql'\;RUNSCRIPT FROM '../sql/schema.tables.sql'\;RUNSCRIPT FROM '../sql/init_data.h2.sql';" /> <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver" /> diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java index 57cc022..f8ad80b 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java @@ -9,7 +9,7 @@ import java.util.Map; /** - * Class contains all data of login form. + * Class contains all data of survey form. * @author jdecome * */ @@ -28,6 +28,11 @@ public class SurveyResponseDTO { * Storage, for each response, the other text, if specified. */ private Map<Long, String> otherTextMap = new HashMap<>(); + /** + * Email user.<br> + * Can be null if user don't provide it (by called {@link SurveyResponseDTO#setEmail(String)} method only). + */ + private String email = null; /** * Default constructor. */ @@ -81,4 +86,16 @@ public class SurveyResponseDTO { public void setOtherTextMap(final HashMap<Long, String> map) { this.otherTextMap = map; } + /** + * @return the email + */ + public String getEmail() { + return email; + } + /** + * @param value the email to set + */ + public void setEmail(final String value) { + this.email = value; + } } -- GitLab From 292d3652008aee62c1672e0133e48d07e57024f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Thu, 30 May 2024 15:07:47 +0200 Subject: [PATCH 20/30] corrections test 7f5f8cdc --- .../main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java | 4 ++++ .../fr/agrometinfo/www/server/SurveyFormHibernateTest.java | 2 +- .../fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java index 1c3503a..4ab9254 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java @@ -22,4 +22,8 @@ public interface UserEmailDao { * @return list of email address */ List<UserEmail> getEmailAddressList(); + /** + * + */ + void deleteAll(); } diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index c4ecae8..9986f3c 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -181,7 +181,7 @@ public class SurveyFormHibernateTest { @Test public void setUserResponsesWithEmail() { // just testing insertion of email user, without insertion of responses (already tested) - final String email = "john.doe@inrae.fr"; + final String email = "jane.doe@inrae.fr"; List<UserEmail> list = this.userEmailDao.getEmailAddressList(); assertNotNull(list, "La liste des e-mail n'est pas initialisée"); assertEquals(list.size(), 0, "La liste des e-mail est vide"); diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java index 362b8d4..0f13c86 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java @@ -366,6 +366,7 @@ public class SurveyFormResourceTest extends JerseyTest { assertNotNull(e.getDatetime(), "Le timestamp de la question ne doit pas être null"); assertNotNull(e.getEmail(), "L'adresse mail contenue dans l'objet ne doit pas être null"); }); + assertEquals(emails.stream().map((e) -> e.getDatetime()).distinct().count(), 1, "Toutes les adresses mails n'ont pas le même datetime"); final LocalDateTime datetimeEmail = emails.stream().map((e) -> e.getDatetime()).distinct().findFirst().get(); assertNotNull(datetimeEmail, "Le datetime lue dans les emails est null"); @@ -394,9 +395,10 @@ public class SurveyFormResourceTest extends JerseyTest { } } /** - * Reset user2responses table. + * Reset tables. */ private void resetUserResponses() { this.userResponsesDao.deleteAll(); + this.userEmailDao.deleteAll(); } } -- GitLab From 5acdab10f726252ace70596f90aaf92519617a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Thu, 30 May 2024 16:05:45 +0200 Subject: [PATCH 21/30] Suppression de la colonne question.category car inutile --- sql/init_data.h2.sql | 2 +- sql/init_data.postgresql.sql | 2 +- sql/questions.csv | 8 +- sql/schema.tables.sql | 1 - .../www/client/view/SurveyView.java | 3 +- .../www/server/dao/QuestionsDao.java | 6 - .../www/server/dao/QuestionsDaoHibernate.java | 9 -- .../www/server/model/Question.java | 5 - .../www/server/rs/SurveyFormResource.java | 11 -- .../www/server/SurveyFormHibernateTest.java | 32 ++--- .../www/server/rs/SurveyFormResourceTest.java | 121 ------------------ .../www/shared/dto/SurveyQuestionDTO.java | 20 +-- .../www/shared/service/SurveyFormService.java | 10 -- 13 files changed, 21 insertions(+), 209 deletions(-) diff --git a/sql/init_data.h2.sql b/sql/init_data.h2.sql index 74219fe..4de57ed 100644 --- a/sql/init_data.h2.sql +++ b/sql/init_data.h2.sql @@ -127,7 +127,7 @@ INSERT INTO simulation (date, simulationid, started, ended) VALUES -- REFRESH MATERIALIZED VIEW v_pra_dailyvalue; -INSERT INTO question(id, category, description) +INSERT INTO question(id, description) SELECT * FROM CSVREAD('../sql/questions.csv'); INSERT INTO response(question, description) diff --git a/sql/init_data.postgresql.sql b/sql/init_data.postgresql.sql index d53ac68..bf1b5d5 100644 --- a/sql/init_data.postgresql.sql +++ b/sql/init_data.postgresql.sql @@ -170,7 +170,7 @@ INSERT INTO normalvalue (indicator, cell, doy, medianvalue, q5, q95) ON CONFLICT ON CONSTRAINT "UK_normalvalue" DO NOTHING; -- questions -\COPY question(id, category, description) FROM questions.csv WITH DELIMITER ',' HEADER CSV; +\COPY question(id, description) FROM questions.csv WITH DELIMITER ',' HEADER CSV; -- responses -- WARNING : responses CSV file use semicolon (« ; ») as separator !! diff --git a/sql/questions.csv b/sql/questions.csv index 927f34e..f851766 100644 --- a/sql/questions.csv +++ b/sql/questions.csv @@ -1,4 +1,4 @@ -id,category,description -1,profession,Quelle est votre profession ? -2,origin,Comment avez-vous connu AgroMetInfo ? -3,useCase,Dans quel but voulez-vous utiliser cette application ? +id,description +1,Quelle est votre profession ? +2,Comment avez-vous connu AgroMetInfo ? +3,Dans quel but voulez-vous utiliser cette application ? diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql index 79f133e..681b22d 100644 --- a/sql/schema.tables.sql +++ b/sql/schema.tables.sql @@ -217,7 +217,6 @@ COMMENT ON TABLE dailyvisit IS 'Number of visits per day.'; -- Tables for survey form - #5 CREATE TABLE IF NOT EXISTS question ( id SERIAL NOT NULL, - category VARCHAR(20) NOT NULL, description VARCHAR(255) NULL, CONSTRAINT PK_question PRIMARY KEY (id) ); diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java index 2dfc9c9..63b0c02 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java @@ -98,9 +98,8 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen // on affiche le champ pour la réponse libre final CheckBox otherCb = CheckBox.create(CSTS.surveyFormOtherTextCheckbox()) - .id(k.getCategory() + "_other") .css("login-checkbox"); - final TextArea otherText = TextArea.create().setId(k.getCategory() + "_other_text") + final TextArea otherText = TextArea.create() .setDisabled(true) .setTooltip(CSTS.surveyFormOtherTextTooltip()) .setRows(2) diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java index 7e65a6d..b0893c9 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java @@ -23,10 +23,4 @@ public interface QuestionsDao { * @return Question object */ Question findByRef(long questionRef); - /** - * Find question object by category. - * @param category of question - * @return Question object - */ - Question findByCategory(String category); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java index e243e48..3803ea4 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java @@ -3,8 +3,6 @@ */ package fr.agrometinfo.www.server.dao; -import java.util.Map; - import fr.agrometinfo.www.server.model.Question; import jakarta.enterprise.context.ApplicationScoped; @@ -25,11 +23,4 @@ public class QuestionsDaoHibernate extends DaoHibernate<Question> implements Que public Question findByRef(final long ref) { return super.find(ref); } - /** */ - @Override - public Question findByCategory(final String category) { - final String jpql = "SELECT q FROM Question q WHERE q.category = :cat"; - return super.findOneByJPQL(jpql, Map.of("cat", category), Question.class); - } - } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java index 3621392..f618b1e 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java @@ -28,11 +28,6 @@ public class Question { @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private long id; - /** - * Catogory of question. - */ - @Column(name = "category") - private String category; /** * Label of question. */ diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java index e964f86..37e6b19 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java @@ -49,7 +49,6 @@ public class SurveyFormResource implements SurveyFormService { static SurveyQuestionDTO toDto(final Question question) { final SurveyQuestionDTO dto = new SurveyQuestionDTO(); dto.setId(question.getId()); - dto.setCategory(question.getCategory()); dto.setDescription(question.getDescription()); return dto; } @@ -73,7 +72,6 @@ public class SurveyFormResource implements SurveyFormService { private static Question toEntity(final SurveyQuestionDTO dto) { final Question question = new Question(); question.setId(dto.getId()); - question.setCategory(dto.getCategory()); question.setDescription(dto.getDescription()); return question; } @@ -140,15 +138,6 @@ public class SurveyFormResource implements SurveyFormService { .map(SurveyFormResource::toDto).collect(Collectors.toList()); } @GET - @Path(SurveyFormService.PATH_QUESTION_BY_CATEGORY) - @Produces(MediaType.APPLICATION_JSON) - @Override - public SurveyQuestionDTO getQuestionByCategory(@QueryParam(value = "category") final String category) { - this.checkRequired(category, "category"); - final Question question = questionsDao.findByCategory(category); - return toDto(question); - } - @GET @Path(SurveyFormService.PATH_RESPONSES_BY_QUESTION_LIST) @Produces(MediaType.APPLICATION_JSON) @Override diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index 9986f3c..4f85011 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -54,11 +54,6 @@ public class SurveyFormHibernateTest { final Question foundedByRef = questionsDao.findByRef(q.getId()); assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getId() + " est null"); assertEquals(foundedByRef, q, "L'objet correspondant à la question " + q.getId() + " ne correspond pas"); - - // recherche de la question par sa catégorie - final Question foundedByCategory = questionsDao.findByCategory(q.getCategory()); - assertNotNull(foundedByCategory, "La question correspondante à la catégorie « " + q.getCategory() + " » est null"); - assertEquals(foundedByCategory, q, "La question correspondante à la catégorie « " + q.getCategory() + " » est vide"); } } @@ -78,10 +73,6 @@ public class SurveyFormHibernateTest { assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getId() + " est null"); assertEquals(foundedByRef, r.getQuestion(), "L'objet correspondant à la question " + q.getId() + " ne correspond pas"); - final Question foundedByCategory = questionsDao.findByCategory(q.getCategory()); - assertNotNull(foundedByCategory, "La question correspondante à la catégorie « " + q.getCategory() + " » est null"); - assertEquals(foundedByCategory, q, "La question correspondante à la catégorie « " + q.getCategory() + " » est vide"); - // recherche de la réponse par sa référence final Response responseByRef = responsesDao.findByRef(r.getId()); assertNotNull(responseByRef, "La réponse correspondante à la réponse " + r.getId() + " est null"); @@ -91,11 +82,12 @@ public class SurveyFormHibernateTest { @Test public void setUserResponses() { - final Question profession = questionsDao.findByCategory("profession"); - assertNotNull(profession, "Aucune question ne correspond à la catégorie « profession »"); + final List<Question> questions = questionsDao.findAll(); + final Question profession = questions.stream().filter((q) -> q.getDescription().contains("profession")).findFirst().get(); + assertNotNull(profession, "Aucune question ne correspond à la profession"); List<Response> responses = responsesDao.findAllByQuestion(profession.getId()); - assertNotNull(responses, "Aucune réponse ne correspond à la catégorie « profession »"); - assertNotEquals(responses.size(), 0, "La liste de réponses pour la catégorie « profession » est vide"); + assertNotNull(responses, "Aucune réponse ne correspond à la profession"); + assertNotEquals(responses.size(), 0, "La liste de réponses pour la profession est vide"); for (final Response r : responses) { assertEquals(r.getQuestion(), profession, "La question de la réponse ne correspond pas avec la question d'origine"); } @@ -147,26 +139,26 @@ public class SurveyFormHibernateTest { } // Essai de l'insertion par les références, avec une autre question - final Question useCase = questionsDao.findByCategory("useCase"); - assertNotNull(useCase, "Aucune question ne correspond à la catégorie « useCase »"); + final Question useCase = questions.stream().filter((q) -> q.getId() == 3).findFirst().get(); + assertNotNull(useCase, "Aucune question ne correspond aux cas d'utilisation"); responses = responsesDao.findAllByQuestion(useCase.getId()); - assertNotNull(responses, "Aucune réponse ne correspond à la catégorie « useCase »"); - assertNotEquals(responses.size(), 0, "La liste de réponses pour la catégorie « useCase » est vide"); + assertNotNull(responses, "Aucune réponse ne correspond à la question des cas d'utilisation"); + assertNotEquals(responses.size(), 0, "La liste de réponses pour la la question des cas d'utilisation est vide"); r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); userResponsesDao.insertResponse(useCase.getId(), r.getId(), null); list = userResponsesDao.findAllByQuestion(useCase.getId()); - assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur pour la question « useCase » doit contenir un élément"); + assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur pour la question des cas d'utilisation doit contenir un élément"); assertEquals(list.get(0).getQuestion(), useCase, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); assertEquals(list.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); assertNull(list.get(0).getOtherText(), "Le texte libre doit être null"); - other = other.concat(" pour la question « useCase »"); + other = other.concat(" pour la question des cas d'utilisation"); userResponsesDao.insertResponse(useCase.getId(), null, other); list = userResponsesDao.findAllByQuestion(useCase.getId()); - assertEquals(list.size(), 2, "La liste de réponses de l'utilisateur pour la question « useCase » doit contenir deux éléments"); + assertEquals(list.size(), 2, "La liste de réponses de l'utilisateur pour la question des cas d'utilisation doit contenir deux éléments"); for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); if (ur.getOtherText() != null) { // on est sur une réponse libre diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java index 0f13c86..12d1bc2 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java @@ -141,23 +141,6 @@ public class SurveyFormResourceTest extends JerseyTest { // Pour chaque question, for (final Question q : questions) { - // on vérifie que la question est retrouvable par la catégorie, via le webservice - final String jsonCategory = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_QUESTION_BY_CATEGORY) - .queryParam("category", q.getCategory()) - .request().get(String.class); - - assertNotNull(jsonCategory, "Impossible de récupérer la ressource (objet null) de la catégorie pour la question n°" + q.getId()); - assertFalse(jsonCategory.isEmpty(), "La chaine de caractère JSON de la catégorie pour la question n° " + q.getId() + " est vide"); - - final Question questionByCategory = objectMapper.readValue(jsonCategory, new TypeReference<Question>() {}); - assertNotNull(questionByCategory, "La conversion du JSON de la catégorie pour la question n° " + q.getId() + " n'a pas fonctionnée"); - assertEquals(questionByCategory, q, "La question lue par la catégorie ne correspond pas avec la question n° " + q.getId() + "d'origine"); - - // On vérifie, via le DAO - final Question questionByDao = questionsDao.findByCategory(q.getCategory()); - assertNotNull(questionByDao, "La lecture de la question n° " + q.getId() + " via le DAO n'a pas fonctionnée"); - assertEquals(questionByDao, q, "La question lue par le DAO ne correspond pas avec la question n° " + q.getId() + "d'origine"); - // on récupère les réponses associées via le webservice final String jsonResponses = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_RESPONSES_BY_QUESTION_LIST) .queryParam("questionRef", String.valueOf(q.getId())) @@ -187,110 +170,6 @@ public class SurveyFormResourceTest extends JerseyTest { log.info(e.getMessage()); } } - /** Test de l'écriture en base. */ - @Test - public void setUserResponses() { - this.resetUserResponses(); - final String category = "origin"; - // Question - final String jsonOrigins = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_QUESTION_BY_CATEGORY) - .queryParam("category", category) - .request().get(String.class); - assertNotNull(jsonOrigins, "Impossible de récupérer la ressource (objet null) de la catégorie pour la question de l'origine"); - assertFalse(jsonOrigins.isEmpty(), "La chaine de caractère JSON pour la question de catégorie « " + category + " » est vide"); - try { - final Question origin = objectMapper.readValue(jsonOrigins, new TypeReference<Question>() {}); - assertEquals(origin, questionsDao.findByCategory(category), "La question lue dans le webservice ne correspond pas avec la question via le DAO"); - - // on récupère les réponses de la question - final List<Response> responses = objectMapper.readValue(target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_RESPONSES_BY_QUESTION_LIST) - .queryParam("questionRef", String.valueOf(origin.getId())) - .request() - .get(String.class), new TypeReference<List<Response>>() {}); - - assertNotNull(responses, "La conversion du JSON des réponses de la question « " + origin.getCategory() + " » n'a pas fonctionnée"); - assertNotEquals(responses.size(), " La liste de réponses pour la question " + origin.getCategory() + " est vide"); - for (final Response r : responses) { - assertEquals(r.getQuestion(), origin, "La question de la réponse ne correspond pas avec la question d'origine"); - } - - final List<Response> listOfResponses = new ArrayList<>(); // liste des réponses insérées - // Insertion d'une réponse prédéfénie - Response r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); - final Form form = new Form(); - form.param("questionRef", String.valueOf(origin.getId())); - form.param("responseRef", String.valueOf(r.getId())); - form.param("otherText", "null"); - - target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE) - .request(MediaType.TEXT_PLAIN) - .post(Entity.form(form)); - listOfResponses.add(r); - - // On lit la réponse insérée, via le DAO - List<UserResponse> userResponsesList = userResponsesDao.findAllByQuestion(origin.getId()); - assertEquals(userResponsesList.size(), 1, "La liste de réponses de l'utilisateur doit contenir un élément"); - assertEquals(userResponsesList.get(0).getQuestion(), origin, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); - assertEquals(userResponsesList.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); - assertNull(userResponsesList.get(0).getOtherText(), "Le texte libre doit être null"); - - // insertion de plusieurs réponses - final int nbToInsert = 3; - final List<Response> randoms = this.pickNRandom(responses, nbToInsert); - for (final Response res : randoms) { - final Form f = new Form(); - f.param("questionRef", String.valueOf(origin.getId())); - f.param("responseRef", String.valueOf(res.getId())); - f.param("otherText", "null"); - - target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE) - .request(MediaType.TEXT_PLAIN) - .post(Entity.form(f)); - - listOfResponses.add(res); - } - - // Vérification via le DAO - userResponsesList = userResponsesDao.findAllByQuestion(origin.getId()); - assertEquals(userResponsesList.size(), (1 + nbToInsert), "La liste de réponses de l'utilisateur doit contenir la réponse précédente + " - + nbToInsert + " réponses supplémentaires"); - for (final UserResponse ur : userResponsesList) { - assertEquals(ur.getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question"); - assertTrue(listOfResponses.contains(ur.getResponse()), "La réponse contenue dans la réponse de l'utilisateur n'est pas dans la liste des réponses insérées"); - assertEquals(ur.getResponse().getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); - assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); - } - - final int newNbResponses = 1 + nbToInsert; - - // insertion d'une réponse à choix libre - final String other = "Ceci est une réponse libre"; - final Form formOther = new Form(); - formOther.param("questionRef", String.valueOf(origin.getId())); - formOther.param("responseRef", "null"); - formOther.param("otherText", other); - - target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE) - .request(MediaType.TEXT_PLAIN) - .post(Entity.form(formOther)); - - userResponsesList = userResponsesDao.findAllByQuestion(origin.getId()); - assertEquals(userResponsesList.size(), (newNbResponses + 1), "La liste de réponses de l'utilisateur doit contenir les " - + newNbResponses + " réponses + la réponse libre"); - for (final UserResponse ur : userResponsesList) { - assertEquals(ur.getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); - if (ur.getOtherText() != null) { // on est sur une réponse libre - assertNull(ur.getResponse(), "L'objet response doit être null si il s'agit d'une réponse libre"); - assertEquals(ur.getOtherText(), other, "Le texte ne correspond pas à ce qui a été inséré en base"); - } else { - assertEquals(ur.getResponse().getQuestion(), origin, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); - assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); - } - } - } catch (JsonProcessingException e) { - log.info(e.getMessage()); - } - } /** Test en définissant les réponses pour les questions. */ @Test public void testWithJsonResponses() { diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java index 78ceb88..49b5545 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java @@ -18,10 +18,6 @@ public class SurveyQuestionDTO { * Ref of question. */ private long id; - /** - * Category of question. - */ - private String category; /** * Label of question. */ @@ -32,12 +28,6 @@ public class SurveyQuestionDTO { public long getId() { return id; } - /** - * @return the category - */ - public String getCategory() { - return category; - } /** * @return the fullName */ @@ -50,12 +40,6 @@ public class SurveyQuestionDTO { public void setId(final long value) { this.id = value; } - /** - * @param value the category to set - */ - public void setCategory(final String value) { - this.category = value; - } /** * @param value the fullName to set */ @@ -65,7 +49,7 @@ public class SurveyQuestionDTO { /** */ @Override public int hashCode() { - return Objects.hash(category, description, id); + return Objects.hash(description, id); } /** */ @Override @@ -80,7 +64,7 @@ public class SurveyQuestionDTO { return false; } SurveyQuestionDTO other = (SurveyQuestionDTO) obj; - return Objects.equals(category, other.category) && Objects.equals(description, other.description) + return Objects.equals(description, other.description) && id == other.id; } } diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java index a253ead..4475dc5 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java @@ -30,8 +30,6 @@ public interface SurveyFormService { String PATH = "login"; /** Path for {@link SurveyFormService#getQuestions()}. */ String PATH_QUESTIONS_LIST = "questions"; - /**Path for {@link SurveyFormService#getQuestionByCategory(String)}. */ - String PATH_QUESTION_BY_CATEGORY = "question"; /** Path for {@link SurveyFormService#getResponses}. */ String PATH_RESPONSES_LIST = "responses"; /** Path for {@link SurveyFormService#getResponsesByQuestion(long)}. */ @@ -49,14 +47,6 @@ public interface SurveyFormService { @GET @Path(PATH_RESPONSES_LIST) List<SurveyOptionDTO> getResponses(); - /** - * Get question by his category. - * @param category of the question - * @return question - */ - @GET - @Path(PATH_QUESTION_BY_CATEGORY) - SurveyQuestionDTO getQuestionByCategory(@QueryParam(value = "category") String category); /** * Returning the list of possible response for one question. * @param questionRef ref of question -- GitLab From 28e47a9a4f30b744824e121f5c3fc5a5d8530caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Fri, 31 May 2024 08:36:18 +0200 Subject: [PATCH 22/30] correction test commit 03208350 --- .../fr/agrometinfo/www/server/SurveyFormHibernateTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index 4f85011..6b1c3cd 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -29,12 +29,14 @@ import fr.agrometinfo.www.server.model.Question; import fr.agrometinfo.www.server.model.Response; import fr.agrometinfo.www.server.model.UserEmail; import fr.agrometinfo.www.server.model.UserResponse; +import lombok.extern.log4j.Log4j2; /** * Test of UserResponsesDaoHibernate. * @author jdecome * */ +@Log4j2 public class SurveyFormHibernateTest { /** DAO for user's responses. */ private UserResponsesDao userResponsesDao = new UserResponsesDaoHibernate(); @@ -82,6 +84,7 @@ public class SurveyFormHibernateTest { @Test public void setUserResponses() { + this.resetUserResponses(); final List<Question> questions = questionsDao.findAll(); final Question profession = questions.stream().filter((q) -> q.getDescription().contains("profession")).findFirst().get(); assertNotNull(profession, "Aucune question ne correspond à la profession"); @@ -198,4 +201,8 @@ public class SurveyFormHibernateTest { return copy.subList(0, nbElements); } } + private void resetUserResponses() { + this.userResponsesDao.deleteAll(); + this.userEmailDao.deleteAll(); + } } -- GitLab From 844bcc8e835b29c16a5de050a990e1ed481be491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Fri, 31 May 2024 14:47:05 +0200 Subject: [PATCH 23/30] Modification des noms des tables SQL --- sql/drop.sql | 7 +- sql/init_data.h2.sql | 4 +- sql/init_data.postgresql.sql | 8 +-- sql/responses.csv | 2 +- sql/schema.tables.sql | 38 +++++----- .../www/client/presenter/SurveyPresenter.java | 2 + .../www/server/dao/QuestionsDaoHibernate.java | 26 ------- .../www/server/dao/ResponsesDaoHibernate.java | 35 --------- ...ResponsesDao.java => SurveyOptionDao.java} | 12 ++-- .../server/dao/SurveyOptionDaoHibernate.java | 35 +++++++++ ...estionsDao.java => SurveyQuestionDao.java} | 12 ++-- .../dao/SurveyQuestionDaoHibernate.java | 26 +++++++ .../www/server/dao/UserResponsesDao.java | 8 +-- .../server/dao/UserResponsesDaoHibernate.java | 18 ++--- .../{Response.java => SurveyOption.java} | 16 ++--- .../{Question.java => SurveyQuestion.java} | 4 +- .../www/server/model/UserEmail.java | 2 +- .../www/server/model/UserResponse.java | 14 ++-- .../www/server/rs/SurveyFormResource.java | 42 +++++------ .../www/server/SurveyFormHibernateTest.java | 72 +++++++++---------- .../www/server/rs/SurveyFormResourceTest.java | 56 +++++++-------- .../test/resources/META-INF/persistence.xml | 4 +- 22 files changed, 223 insertions(+), 220 deletions(-) delete mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java delete mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java rename www-server/src/main/java/fr/agrometinfo/www/server/dao/{ResponsesDao.java => SurveyOptionDao.java} (60%) create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDaoHibernate.java rename www-server/src/main/java/fr/agrometinfo/www/server/dao/{QuestionsDao.java => SurveyQuestionDao.java} (50%) create mode 100644 www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDaoHibernate.java rename www-server/src/main/java/fr/agrometinfo/www/server/model/{Response.java => SurveyOption.java} (71%) rename www-server/src/main/java/fr/agrometinfo/www/server/model/{Question.java => SurveyQuestion.java} (91%) diff --git a/sql/drop.sql b/sql/drop.sql index 324c3c5..24a5942 100644 --- a/sql/drop.sql +++ b/sql/drop.sql @@ -10,6 +10,7 @@ DROP TABLE period; DROP TABLE i18n; DROP TABLE i18nkey; DROP TABLE locale; -DROP TABLE user2responses; -DROP TABLE responses; -DROP TABLE questions; +DROP TABLE userresponse; +DROP TABLE surveyoption; +DROP TABLE surveyquestion; +DROP TABLE useremail; diff --git a/sql/init_data.h2.sql b/sql/init_data.h2.sql index 4de57ed..c40a7c0 100644 --- a/sql/init_data.h2.sql +++ b/sql/init_data.h2.sql @@ -127,9 +127,9 @@ INSERT INTO simulation (date, simulationid, started, ended) VALUES -- REFRESH MATERIALIZED VIEW v_pra_dailyvalue; -INSERT INTO question(id, description) +INSERT INTO surveyquestion(id, description) SELECT * FROM CSVREAD('../sql/questions.csv'); -INSERT INTO response(question, description) +INSERT INTO surveyoption(surveyquestion, description) SELECT * FROM CSVREAD('../sql/responses.csv', null, 'fieldSeparator=;'); diff --git a/sql/init_data.postgresql.sql b/sql/init_data.postgresql.sql index bf1b5d5..4a60713 100644 --- a/sql/init_data.postgresql.sql +++ b/sql/init_data.postgresql.sql @@ -11,8 +11,8 @@ DELETE FROM period; DELETE FROM i18n; DELETE FROM i18nkey; DELETE FROM locale; -DELETE FROM question; -DELETE FROM response; +DELETE FROM surveyquestion; +DELETE FROM surveyoption; -- translations CREATE TEMPORARY TABLE IF NOT EXISTS tmp_translation ( @@ -170,9 +170,9 @@ INSERT INTO normalvalue (indicator, cell, doy, medianvalue, q5, q95) ON CONFLICT ON CONSTRAINT "UK_normalvalue" DO NOTHING; -- questions -\COPY question(id, description) FROM questions.csv WITH DELIMITER ',' HEADER CSV; +\COPY surveyquestion(id, description) FROM questions.csv WITH DELIMITER ',' HEADER CSV; -- responses -- WARNING : responses CSV file use semicolon (« ; ») as separator !! -\COPY response(question, description) FROM responses.csv WITH DELIMITER ';' HEADER CSV; +\COPY surveyoption(surveyquestion, description) FROM responses.csv WITH DELIMITER ';' HEADER CSV; diff --git a/sql/responses.csv b/sql/responses.csv index 97e9914..173c16e 100644 --- a/sql/responses.csv +++ b/sql/responses.csv @@ -1,4 +1,4 @@ -question;description +surveyquestion;description 1;Agriculteur 1;Conseiller agricole (Chambre d'agriculture, Entreprise de service) 1;Scientifique diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql index 681b22d..47eab0f 100644 --- a/sql/schema.tables.sql +++ b/sql/schema.tables.sql @@ -215,41 +215,41 @@ CREATE TABLE IF NOT EXISTS dailyvisit( COMMENT ON TABLE dailyvisit IS 'Number of visits per day.'; -- Tables for survey form - #5 -CREATE TABLE IF NOT EXISTS question ( +CREATE TABLE IF NOT EXISTS surveyquestion ( id SERIAL NOT NULL, description VARCHAR(255) NULL, - CONSTRAINT PK_question PRIMARY KEY (id) + CONSTRAINT PK_surveyquestion PRIMARY KEY (id) ); -COMMENT ON TABLE question IS 'Questions for survey form'; +COMMENT ON TABLE surveyquestion IS 'Questions for survey form'; -CREATE TABLE IF NOT EXISTS response ( +CREATE TABLE IF NOT EXISTS surveyoption ( id SERIAL NOT NULL, - question INT4 NOT NULL, + surveyquestion INT4 NOT NULL, description VARCHAR NULL, - CONSTRAINT PK_response PRIMARY KEY (id), - CONSTRAINT FK_response_question FOREIGN KEY (question) REFERENCES question(id) + CONSTRAINT PK_surveyoption PRIMARY KEY (id), + CONSTRAINT FK_surveyoption_surveyquestion FOREIGN KEY (surveyquestion) REFERENCES surveyquestion(id) ); -COMMENT ON TABLE response IS 'Options responses for questions.'; +COMMENT ON TABLE surveyoption IS 'Options responses for questions.'; -CREATE TABLE IF NOT EXISTS user2response ( +CREATE TABLE IF NOT EXISTS userresponse ( id SERIAL NOT NULL, datetime TIMESTAMP NOT NULL, - question INT4 NOT NULL, - response INT4 NULL, - other_text VARCHAR NULL, - CONSTRAINT PK_user2response PRIMARY KEY (id), - CONSTRAINT FK_user2response_question FOREIGN KEY (question) REFERENCES question(id), - CONSTRAINT FK_user2response_response FOREIGN KEY (response) REFERENCES response(id) + surveyquestion INT4 NOT NULL, + surveyoption INT4 NULL, + othertext VARCHAR NULL, + CONSTRAINT PK_userresponse PRIMARY KEY (id), + CONSTRAINT FK_userresponse_surveyquestion FOREIGN KEY (surveyquestion) REFERENCES surveyquestion(id), + CONSTRAINT FK_userresponse_surveyoption FOREIGN KEY (surveyoption) REFERENCES surveyoption(id) ); -COMMENT ON TABLE user2response IS 'Responses of user to questions, and other text if present'; +COMMENT ON TABLE userresponse IS 'Responses of user to questions, and other text if present'; -CREATE TABLE IF NOT EXISTS user_email ( +CREATE TABLE IF NOT EXISTS useremail ( id SERIAL NOT NULL, datetime TIMESTAMP NOT NULL, email VARCHAR NOT NULL, - CONSTRAINT PK_user_email PRIMARY KEY (id) + CONSTRAINT PK_useremail PRIMARY KEY (id) ); -COMMENT ON TABLE user_email IS 'Simple table for register email of user, when he fills out survey'; +COMMENT ON TABLE useremail IS 'Simple table for register email of user, when he fills out survey'; CREATE OR REPLACE VIEW v_i18n AS SELECT l.languagetag, diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java index 85ebcdd..b40371f 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java @@ -66,6 +66,7 @@ public final class SurveyPresenter implements Presenter { * @param list list of responses */ private void setResponses(final List<SurveyOptionDTO> list) { + GWT.log("SurveyPresenter.setResponses(" + list.size() + ") enter"); this.responses = list; final Map<SurveyQuestionDTO, List<SurveyOptionDTO>> responsesMap = new HashMap<>(); @@ -81,6 +82,7 @@ public final class SurveyPresenter implements Presenter { view.setResponses(responsesMap); view.init(); + GWT.log("SurveyPresenter.setResponses() end"); } @Override public void start() { diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java deleted file mode 100644 index 3803ea4..0000000 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDaoHibernate.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * - */ -package fr.agrometinfo.www.server.dao; - -import fr.agrometinfo.www.server.model.Question; -import jakarta.enterprise.context.ApplicationScoped; - -/** - * @author jdecome - * - */ -@ApplicationScoped -public class QuestionsDaoHibernate extends DaoHibernate<Question> implements QuestionsDao { - /** - * Constructor. - */ - public QuestionsDaoHibernate() { - super(Question.class); - } - /** */ - @Override - public Question findByRef(final long ref) { - return super.find(ref); - } -} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java deleted file mode 100644 index ed2ad39..0000000 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDaoHibernate.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * - */ -package fr.agrometinfo.www.server.dao; - -import java.util.List; -import java.util.Map; - -import fr.agrometinfo.www.server.model.Response; -import jakarta.enterprise.context.ApplicationScoped; - -/** - * @author jdecome - * - */ -@ApplicationScoped -public class ResponsesDaoHibernate extends DaoHibernate<Response> implements ResponsesDao { - /** - * Constructor. - */ - public ResponsesDaoHibernate() { - super(Response.class); - } - /** */ - @Override - public List<Response> findAllByQuestion(final long questionRef) { - final String jpql = "SELECT r FROM Response r WHERE r.question.id = :ref"; - return super.findAllByJPQL(jpql, Map.of("ref", questionRef), Response.class); - } - /** */ - @Override - public Response findByRef(final long responseRef) { - return super.find(responseRef); - } -} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDao.java similarity index 60% rename from www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java rename to www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDao.java index acd4cb9..52dab0b 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/ResponsesDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDao.java @@ -3,30 +3,30 @@ */ package fr.agrometinfo.www.server.dao; -import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.SurveyOption; import java.util.List; /** - * DAO for {@link Response}. + * DAO for {@link SurveyOption}. * @author jdecome */ -public interface ResponsesDao { +public interface SurveyOptionDao { /** * Find all responses in database. * @return all responses */ - List<Response> findAll(); + List<SurveyOption> findAll(); /** * Find all responses by question. * @param questionRef * @return list of responses */ - List<Response> findAllByQuestion(long questionRef); + List<SurveyOption> findAllByQuestion(long questionRef); /** * Get response with reference. * @param responseRef * @return response */ - Response findByRef(long responseRef); + SurveyOption findByRef(long responseRef); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDaoHibernate.java new file mode 100644 index 0000000..d107e16 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDaoHibernate.java @@ -0,0 +1,35 @@ +/** + * + */ +package fr.agrometinfo.www.server.dao; + +import java.util.List; +import java.util.Map; + +import fr.agrometinfo.www.server.model.SurveyOption; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * @author jdecome + * + */ +@ApplicationScoped +public class SurveyOptionDaoHibernate extends DaoHibernate<SurveyOption> implements SurveyOptionDao { + /** + * Constructor. + */ + public SurveyOptionDaoHibernate() { + super(SurveyOption.class); + } + /** */ + @Override + public List<SurveyOption> findAllByQuestion(final long questionRef) { + final String jpql = "SELECT r FROM SurveyOption r WHERE r.question.id = :ref"; + return super.findAllByJPQL(jpql, Map.of("ref", questionRef), SurveyOption.class); + } + /** */ + @Override + public SurveyOption findByRef(final long responseRef) { + return super.find(responseRef); + } +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDao.java similarity index 50% rename from www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java rename to www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDao.java index b0893c9..ef2d5e2 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/QuestionsDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDao.java @@ -5,22 +5,22 @@ package fr.agrometinfo.www.server.dao; import java.util.List; -import fr.agrometinfo.www.server.model.Question; +import fr.agrometinfo.www.server.model.SurveyQuestion; /** - * DAO for {@link Question}. + * DAO for {@link SurveyQuestion}. * @author jdecome * */ -public interface QuestionsDao { +public interface SurveyQuestionDao { /** * @return all of Questions */ - List<Question> findAll(); + List<SurveyQuestion> findAll(); /** * Find question object by reference. * @param questionRef question_ref - * @return Question object + * @return SurveyQuestion object */ - Question findByRef(long questionRef); + SurveyQuestion findByRef(long questionRef); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDaoHibernate.java new file mode 100644 index 0000000..cddc768 --- /dev/null +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDaoHibernate.java @@ -0,0 +1,26 @@ +/** + * + */ +package fr.agrometinfo.www.server.dao; + +import fr.agrometinfo.www.server.model.SurveyQuestion; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * @author jdecome + * + */ +@ApplicationScoped +public class SurveyQuestionDaoHibernate extends DaoHibernate<SurveyQuestion> implements SurveyQuestionDao { + /** + * Constructor. + */ + public SurveyQuestionDaoHibernate() { + super(SurveyQuestion.class); + } + /** */ + @Override + public SurveyQuestion findByRef(final long ref) { + return super.find(ref); + } +} diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java index 2531e58..9880b59 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java @@ -3,8 +3,8 @@ package fr.agrometinfo.www.server.dao; import java.time.LocalDateTime; import java.util.List; -import fr.agrometinfo.www.server.model.Question; -import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.SurveyQuestion; +import fr.agrometinfo.www.server.model.SurveyOption; import fr.agrometinfo.www.server.model.UserResponse; /** * DAO for {@link UserResponse}. @@ -26,7 +26,7 @@ public interface UserResponsesDao { * @param r response * @param otherText text if response is other */ - void insertResponse(Question q, Response r, String otherText); + void insertResponse(SurveyQuestion q, SurveyOption r, String otherText); /** * Insert response or text for specified question.<br> * If r is provided, {@code otherText} must be null.<br> @@ -36,7 +36,7 @@ public interface UserResponsesDao { * @param otherText text if response is other * @param datetime provided localdatetime */ - void insertResponse(Question q, Response r, String otherText, LocalDateTime datetime); + void insertResponse(SurveyQuestion q, SurveyOption r, String otherText, LocalDateTime datetime); /** * Insert response or text for specified question, identified by reference.<br> * If responseRef is provided, {@code otherText} must be null.<br> diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java index 5f9aea3..0e17273 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java @@ -7,8 +7,8 @@ import java.time.LocalDateTime; import java.util.List; import java.util.Map; -import fr.agrometinfo.www.server.model.Question; -import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.SurveyQuestion; +import fr.agrometinfo.www.server.model.SurveyOption; import fr.agrometinfo.www.server.model.UserResponse; import jakarta.enterprise.context.ApplicationScoped; @@ -19,9 +19,9 @@ import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implements UserResponsesDao { /** DAO for questions. */ - private QuestionsDao questionsDao = new QuestionsDaoHibernate(); + private SurveyQuestionDao questionsDao = new SurveyQuestionDaoHibernate(); /** DAO for responses. */ - private ResponsesDao responsesDao = new ResponsesDaoHibernate(); + private SurveyOptionDao responsesDao = new SurveyOptionDaoHibernate(); /** Default constructor. */ public UserResponsesDaoHibernate() { super(UserResponse.class); @@ -35,19 +35,19 @@ public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implem /** */ @Override public void insertResponse( - final Question q, final Response r, + final SurveyQuestion q, final SurveyOption r, final String otherText, final LocalDateTime datetime) { final UserResponse ur = new UserResponse(); ur.setDateTime(datetime); ur.setQuestion(q); - ur.setResponse(r); + ur.setOption(r); ur.setOtherText(otherText); this.save(ur); } /** */ @Override - public void insertResponse(final Question q, final Response r, final String otherText) { + public void insertResponse(final SurveyQuestion q, final SurveyOption r, final String otherText) { this.insertResponse(q, r, otherText, LocalDateTime.now()); } /** */ @@ -56,10 +56,10 @@ public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implem final Long questionRef, final Long responseRef, final String otherText, final LocalDateTime datetime) { // recherche de la question - final Question q = questionsDao.findByRef(questionRef); + final SurveyQuestion q = questionsDao.findByRef(questionRef); if (q != null) { if (responseRef != null) { // insertion d'une réponse prédéfinie, on recherche de la réponse - final Response r = responsesDao.findByRef(responseRef); + final SurveyOption r = responsesDao.findByRef(responseRef); this.insertResponse(q, r, null, datetime); } else { // insertion d'une réponse libre this.insertResponse(q, null, otherText, datetime); diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyOption.java similarity index 71% rename from www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java rename to www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyOption.java index 9ed8eba..8496c48 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Response.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyOption.java @@ -14,16 +14,16 @@ import jakarta.persistence.Table; import lombok.Data; /** - * Options for questions. + * Option (response) for questions. * @author jdecome * */ @Data @Entity -@Table(name = "response") -public class Response { +@Table(name = "surveyoption") +public class SurveyOption { /** - * Reference of response.<br> + * Reference of options.<br> * Primary key. */ @Id @@ -31,13 +31,13 @@ public class Response { @Column(name = "id") private long id; /** - * Question related to response. + * Question related to option. */ @OneToOne - @JoinColumn(name = "question") - private Question question; + @JoinColumn(name = "surveyquestion") + private SurveyQuestion question; /** - * Label of the response. + * Label of the option. */ @Column(name = "description") private String description; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyQuestion.java similarity index 91% rename from www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java rename to www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyQuestion.java index f618b1e..9b26589 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/Question.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyQuestion.java @@ -18,8 +18,8 @@ import lombok.Data; */ @Data @Entity -@Table(name = "question") -public class Question { +@Table(name = "surveyquestion") +public class SurveyQuestion { /** * Reference of question.<br> * Primary key. diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java index 015174c..7aa74d3 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java @@ -17,7 +17,7 @@ import lombok.Data; */ @Data @Entity -@Table(name = "user_email") +@Table(name = "useremail") public class UserEmail { /** * Primary key. diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java index 2b68c16..0ab9c08 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java @@ -21,7 +21,7 @@ import lombok.Data; */ @Data @Entity -@Table(name = "user2response") +@Table(name = "userresponse") public class UserResponse { /** Primary key. */ @Id @@ -33,19 +33,19 @@ public class UserResponse { private LocalDateTime dateTime; /** Related question. */ @OneToOne - @JoinColumn(name = "question") - private Question question; + @JoinColumn(name = "surveyquestion") + private SurveyQuestion question; /** - * Related response.<br> + * Related option.<br> * Can be null if it's a other response. */ @OneToOne - @JoinColumn(name = "response") - private Response response; + @JoinColumn(name = "surveyoption") + private SurveyOption option; /** * Other text response.<br> * Can be null if it's a related response. */ - @Column(name = "other_text") + @Column(name = "othertext") private String otherText; } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java index 37e6b19..d612dfd 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java @@ -8,12 +8,12 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import fr.agrometinfo.www.server.dao.QuestionsDao; -import fr.agrometinfo.www.server.dao.ResponsesDao; +import fr.agrometinfo.www.server.dao.SurveyQuestionDao; +import fr.agrometinfo.www.server.dao.SurveyOptionDao; import fr.agrometinfo.www.server.dao.UserEmailDao; import fr.agrometinfo.www.server.dao.UserResponsesDao; -import fr.agrometinfo.www.server.model.Question; -import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.SurveyQuestion; +import fr.agrometinfo.www.server.model.SurveyOption; import fr.agrometinfo.www.server.service.MailService; import fr.agrometinfo.www.server.util.EmailUtils; import fr.agrometinfo.www.shared.dto.ErrorResponseDTO; @@ -42,22 +42,22 @@ import jakarta.ws.rs.core.MediaType; @RequestScoped public class SurveyFormResource implements SurveyFormService { /** - * Convert {@link Question} entity to dto. + * Convert {@link SurveyQuestion} entity to dto. * @param question entity * @return dto */ - static SurveyQuestionDTO toDto(final Question question) { + static SurveyQuestionDTO toDto(final SurveyQuestion question) { final SurveyQuestionDTO dto = new SurveyQuestionDTO(); dto.setId(question.getId()); dto.setDescription(question.getDescription()); return dto; } /** - * Convert {@link Response} entity to dto. + * Convert {@link SurveyOption} entity to dto. * @param response entity * @return dto */ - static SurveyOptionDTO toDto(final Response response) { + static SurveyOptionDTO toDto(final SurveyOption response) { final SurveyOptionDTO dto = new SurveyOptionDTO(); dto.setId(response.getId()); dto.setQuestion(toDto(response.getQuestion())); @@ -69,8 +69,8 @@ public class SurveyFormResource implements SurveyFormService { * @param dto question * @return entity */ - private static Question toEntity(final SurveyQuestionDTO dto) { - final Question question = new Question(); + private static SurveyQuestion toEntity(final SurveyQuestionDTO dto) { + final SurveyQuestion question = new SurveyQuestion(); question.setId(dto.getId()); question.setDescription(dto.getDescription()); return question; @@ -80,23 +80,23 @@ public class SurveyFormResource implements SurveyFormService { * @param dto response * @return entity */ - private static Response toEntity(final SurveyOptionDTO dto) { - final Response response = new Response(); + private static SurveyOption toEntity(final SurveyOptionDTO dto) { + final SurveyOption response = new SurveyOption(); response.setId(dto.getId()); response.setQuestion(toEntity(dto.getQuestion())); response.setDescription(dto.getDescription()); return response; } /** - * DAO for questions ({@link QuestionsDao}). + * DAO for questions ({@link SurveyQuestionDao}). */ @Inject - private QuestionsDao questionsDao; + private SurveyQuestionDao questionsDao; /** - * DAO for responses ({@link ResponsesDao}). + * DAO for responses ({@link SurveyOptionDao}). */ @Inject - private ResponsesDao responsesDao; + private SurveyOptionDao responsesDao; /** * DAO for user responses ({@link UserResponsesDao}. */ @@ -144,9 +144,9 @@ public class SurveyFormResource implements SurveyFormService { public List<SurveyOptionDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") final Long questionRef) { this.checkRequired(questionRef, "questionRef"); if (this.checkIfQuestionExist(questionRef)) { - final List<Response> list = responsesDao.findAllByQuestion(questionRef); + final List<SurveyOption> list = responsesDao.findAllByQuestion(questionRef); final List<SurveyOptionDTO> responses = new ArrayList<>(); - for (final Response r : list) { + for (final SurveyOption r : list) { responses.add(toDto(r)); } return responses; @@ -188,7 +188,7 @@ public class SurveyFormResource implements SurveyFormService { private boolean checkIfQuestionExist(final Long questionRef) { if (questionRef != null) { // on cherche dans le DAO - final Question q = questionsDao.findByRef(questionRef); + final SurveyQuestion q = questionsDao.findByRef(questionRef); return q != null; } return false; @@ -205,7 +205,7 @@ public class SurveyFormResource implements SurveyFormService { // traitement des réponses prédéfinies for (final SurveyQuestionDTO dto : data.getQuestions()) { // Pour chaque question répondue // Insérer les réponses associés - final Question q = toEntity(dto); + final SurveyQuestion q = toEntity(dto); final Long qRef = dto.getId(); List<SurveyOptionDTO> associatedResponses = data.getResponses() .stream().filter(f -> f.getQuestion().getId() == qRef) @@ -213,7 +213,7 @@ public class SurveyFormResource implements SurveyFormService { // On insère les réponses prédéfinies for (final SurveyOptionDTO rDto : associatedResponses) { - final Response r = toEntity(rDto); + final SurveyOption r = toEntity(rDto); this.userResponsesDao.insertResponse(q, r, null, datetime); } diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index 6b1c3cd..7a161be 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -17,16 +17,16 @@ import java.util.concurrent.ThreadLocalRandom; import org.junit.jupiter.api.Test; -import fr.agrometinfo.www.server.dao.QuestionsDao; -import fr.agrometinfo.www.server.dao.QuestionsDaoHibernate; -import fr.agrometinfo.www.server.dao.ResponsesDao; -import fr.agrometinfo.www.server.dao.ResponsesDaoHibernate; +import fr.agrometinfo.www.server.dao.SurveyQuestionDao; +import fr.agrometinfo.www.server.dao.SurveyQuestionDaoHibernate; +import fr.agrometinfo.www.server.dao.SurveyOptionDao; +import fr.agrometinfo.www.server.dao.SurveyOptionDaoHibernate; import fr.agrometinfo.www.server.dao.UserEmailDao; import fr.agrometinfo.www.server.dao.UserEmailDaoHibernate; import fr.agrometinfo.www.server.dao.UserResponsesDao; import fr.agrometinfo.www.server.dao.UserResponsesDaoHibernate; -import fr.agrometinfo.www.server.model.Question; -import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.SurveyQuestion; +import fr.agrometinfo.www.server.model.SurveyOption; import fr.agrometinfo.www.server.model.UserEmail; import fr.agrometinfo.www.server.model.UserResponse; import lombok.extern.log4j.Log4j2; @@ -41,19 +41,19 @@ public class SurveyFormHibernateTest { /** DAO for user's responses. */ private UserResponsesDao userResponsesDao = new UserResponsesDaoHibernate(); /** DAO for questions. */ - private QuestionsDao questionsDao = new QuestionsDaoHibernate(); + private SurveyQuestionDao questionsDao = new SurveyQuestionDaoHibernate(); /** DAO for responses. */ - private ResponsesDao responsesDao = new ResponsesDaoHibernate(); + private SurveyOptionDao responsesDao = new SurveyOptionDaoHibernate(); /** DAO for email address of user. */ private UserEmailDao userEmailDao = new UserEmailDaoHibernate(); @Test public void getQuestion() { - final List<Question> list = questionsDao.findAll(); + final List<SurveyQuestion> list = questionsDao.findAll(); assertNotEquals(list.size(), 0, "La liste de questions est vide"); - for (final Question q : list) { + for (final SurveyQuestion q : list) { // recherche de la question par sa référence - final Question foundedByRef = questionsDao.findByRef(q.getId()); + final SurveyQuestion foundedByRef = questionsDao.findByRef(q.getId()); assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getId() + " est null"); assertEquals(foundedByRef, q, "L'objet correspondant à la question " + q.getId() + " ne correspond pas"); } @@ -61,22 +61,22 @@ public class SurveyFormHibernateTest { @Test public void getResponses() { - final List<Question> questions = questionsDao.findAll(); - final List<Response> responses = responsesDao.findAll(); + final List<SurveyQuestion> questions = questionsDao.findAll(); + final List<SurveyOption> responses = responsesDao.findAll(); assertNotEquals(responses.size(), 0, "La liste de réponses est vide"); - for (final Response r : responses) { + for (final SurveyOption r : responses) { assertTrue(questions.contains(r.getQuestion()), "La liste de questions ne contient pas la question " + r.getQuestion().getId()); // Test à partir de la question correspondante à la réponse - final Question q = r.getQuestion(); + final SurveyQuestion q = r.getQuestion(); assertNotNull(q, "La question correspondante à la réponse " + r.getId() + " est null"); - final Question foundedByRef = questionsDao.findByRef(q.getId()); + final SurveyQuestion foundedByRef = questionsDao.findByRef(q.getId()); assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getId() + " est null"); assertEquals(foundedByRef, r.getQuestion(), "L'objet correspondant à la question " + q.getId() + " ne correspond pas"); // recherche de la réponse par sa référence - final Response responseByRef = responsesDao.findByRef(r.getId()); + final SurveyOption responseByRef = responsesDao.findByRef(r.getId()); assertNotNull(responseByRef, "La réponse correspondante à la réponse " + r.getId() + " est null"); assertEquals(responseByRef, r, "La réponse correspondante à la réponse " + r.getId() + " est vide"); } @@ -85,31 +85,31 @@ public class SurveyFormHibernateTest { @Test public void setUserResponses() { this.resetUserResponses(); - final List<Question> questions = questionsDao.findAll(); - final Question profession = questions.stream().filter((q) -> q.getDescription().contains("profession")).findFirst().get(); + final List<SurveyQuestion> questions = questionsDao.findAll(); + final SurveyQuestion profession = questions.stream().filter((q) -> q.getDescription().contains("profession")).findFirst().get(); assertNotNull(profession, "Aucune question ne correspond à la profession"); - List<Response> responses = responsesDao.findAllByQuestion(profession.getId()); + List<SurveyOption> responses = responsesDao.findAllByQuestion(profession.getId()); assertNotNull(responses, "Aucune réponse ne correspond à la profession"); assertNotEquals(responses.size(), 0, "La liste de réponses pour la profession est vide"); - for (final Response r : responses) { + for (final SurveyOption r : responses) { assertEquals(r.getQuestion(), profession, "La question de la réponse ne correspond pas avec la question d'origine"); } // Insertion d'une réponse - final List<Response> listOfResponses = new ArrayList<>(); // liste des réponses insérées - Response r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); + final List<SurveyOption> listOfResponses = new ArrayList<>(); // liste des réponses insérées + SurveyOption r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); userResponsesDao.insertResponse(profession, r, null); listOfResponses.add(r); List<UserResponse> list = userResponsesDao.findAllByQuestion(profession.getId()); assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur doit contenir un élément"); assertEquals(list.get(0).getQuestion(), profession, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); - assertEquals(list.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); + assertEquals(list.get(0).getOption(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); assertNull(list.get(0).getOtherText(), "Le texte libre doit être null"); // Insertion de plusieurs réponses final int nbToInsert = 3; - for (final Response res : pickNRandom(responses, nbToInsert)) { + for (final SurveyOption res : pickNRandom(responses, nbToInsert)) { userResponsesDao.insertResponse(profession, res, null); listOfResponses.add(res); } @@ -117,8 +117,8 @@ public class SurveyFormHibernateTest { assertEquals(list.size(), (1 + nbToInsert), "La liste de réponses de l'utilisateur doit contenir la réponse précédente + " + nbToInsert + " réponses supplémentaires"); for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question"); - assertTrue(listOfResponses.contains(ur.getResponse()), "La réponse contenue dans la réponse de l'utilisateur n'est pas dans la liste des réponses insérées"); - assertEquals(ur.getResponse().getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); + assertTrue(listOfResponses.contains(ur.getOption()), "La réponse contenue dans la réponse de l'utilisateur n'est pas dans la liste des réponses insérées"); + assertEquals(ur.getOption().getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); } @@ -133,16 +133,16 @@ public class SurveyFormHibernateTest { for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); if (ur.getOtherText() != null) { // on est sur une réponse libre - assertNull(ur.getResponse(), "L'objet response doit être null si il s'agit d'une réponse libre"); + assertNull(ur.getOption(), "L'objet response doit être null si il s'agit d'une réponse libre"); assertEquals(ur.getOtherText(), other, "Le texte ne correspond pas à ce qui a été inséré en base"); } else { - assertEquals(ur.getResponse().getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); + assertEquals(ur.getOption().getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); } } // Essai de l'insertion par les références, avec une autre question - final Question useCase = questions.stream().filter((q) -> q.getId() == 3).findFirst().get(); + final SurveyQuestion useCase = questions.stream().filter((q) -> q.getId() == 3).findFirst().get(); assertNotNull(useCase, "Aucune question ne correspond aux cas d'utilisation"); responses = responsesDao.findAllByQuestion(useCase.getId()); assertNotNull(responses, "Aucune réponse ne correspond à la question des cas d'utilisation"); @@ -154,7 +154,7 @@ public class SurveyFormHibernateTest { list = userResponsesDao.findAllByQuestion(useCase.getId()); assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur pour la question des cas d'utilisation doit contenir un élément"); assertEquals(list.get(0).getQuestion(), useCase, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); - assertEquals(list.get(0).getResponse(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); + assertEquals(list.get(0).getOption(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); assertNull(list.get(0).getOtherText(), "Le texte libre doit être null"); other = other.concat(" pour la question des cas d'utilisation"); @@ -165,10 +165,10 @@ public class SurveyFormHibernateTest { for (final UserResponse ur : list) { assertEquals(ur.getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); if (ur.getOtherText() != null) { // on est sur une réponse libre - assertNull(ur.getResponse(), "L'objet response doit être null si il s'agit d'une réponse libre"); + assertNull(ur.getOption(), "L'objet response doit être null si il s'agit d'une réponse libre"); assertEquals(ur.getOtherText(), other, "Le texte ne correspond pas à ce qui a été inséré en base"); } else { - assertEquals(ur.getResponse().getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); + assertEquals(ur.getOption().getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); } } @@ -179,7 +179,7 @@ public class SurveyFormHibernateTest { final String email = "jane.doe@inrae.fr"; List<UserEmail> list = this.userEmailDao.getEmailAddressList(); assertNotNull(list, "La liste des e-mail n'est pas initialisée"); - assertEquals(list.size(), 0, "La liste des e-mail est vide"); + assertEquals(list.size(), 0, "La liste des e-mail doit être vide"); this.userEmailDao.insertEmailUserAddress(email, LocalDateTime.now()); list = this.userEmailDao.getEmailAddressList(); @@ -192,8 +192,8 @@ public class SurveyFormHibernateTest { * @param nbElements to pick * @return */ - private List<Response> pickNRandom(final List<Response> list, final int nbElements) { - final List<Response> copy = new ArrayList<Response>(list); + private List<SurveyOption> pickNRandom(final List<SurveyOption> list, final int nbElements) { + final List<SurveyOption> copy = new ArrayList<SurveyOption>(list); Collections.shuffle(copy); if (nbElements > copy.size()) { return copy.subList(0, copy.size()); diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java index 12d1bc2..1797782 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java @@ -27,17 +27,17 @@ import org.glassfish.jersey.test.JerseyTest; import org.junit.jupiter.api.Test; -import fr.agrometinfo.www.server.dao.QuestionsDao; -import fr.agrometinfo.www.server.dao.QuestionsDaoHibernate; -import fr.agrometinfo.www.server.dao.ResponsesDao; -import fr.agrometinfo.www.server.dao.ResponsesDaoHibernate; +import fr.agrometinfo.www.server.dao.SurveyQuestionDao; +import fr.agrometinfo.www.server.dao.SurveyQuestionDaoHibernate; +import fr.agrometinfo.www.server.dao.SurveyOptionDao; +import fr.agrometinfo.www.server.dao.SurveyOptionDaoHibernate; import fr.agrometinfo.www.server.dao.UserEmailDao; import fr.agrometinfo.www.server.dao.UserEmailDaoHibernate; import fr.agrometinfo.www.server.dao.UserResponsesDao; import fr.agrometinfo.www.server.dao.UserResponsesDaoHibernate; import fr.agrometinfo.www.server.exception.AgroMetInfoException; -import fr.agrometinfo.www.server.model.Question; -import fr.agrometinfo.www.server.model.Response; +import fr.agrometinfo.www.server.model.SurveyQuestion; +import fr.agrometinfo.www.server.model.SurveyOption; import fr.agrometinfo.www.server.model.UserEmail; import fr.agrometinfo.www.server.model.UserResponse; import fr.agrometinfo.www.server.service.MailService; @@ -91,9 +91,9 @@ public class SurveyFormResourceTest extends JerseyTest { /** Parsing JSON to object. */ private final ObjectMapper objectMapper = new ObjectMapper(); /** DAO for Questions. */ - private final QuestionsDao questionsDao = new QuestionsDaoHibernate(); + private final SurveyQuestionDao questionsDao = new SurveyQuestionDaoHibernate(); /** DAO for Responses. */ - private final ResponsesDao responsesDao = new ResponsesDaoHibernate(); + private final SurveyOptionDao responsesDao = new SurveyOptionDaoHibernate(); /** DAO for UserResponses. */ private final UserResponsesDao userResponsesDao = new UserResponsesDaoHibernate(); /** DAO for UserMail */ @@ -106,8 +106,8 @@ public class SurveyFormResourceTest extends JerseyTest { return new ResourceConfig(SurveyFormResource.class).register(new AbstractBinder() { @Override protected void configure() { - bind(questionsDao).to(QuestionsDao.class); - bind(responsesDao).to(ResponsesDao.class); + bind(questionsDao).to(SurveyQuestionDao.class); + bind(responsesDao).to(SurveyOptionDao.class); bind(userResponsesDao).to(UserResponsesDao.class); bind(userEmailDao).to(UserEmailDao.class); bind(mailService).to(MailService.class); @@ -122,7 +122,7 @@ public class SurveyFormResourceTest extends JerseyTest { assertNotNull(jsonQuestions, "Impossible de récupérer la ressource (objet null) pour les questions"); assertFalse(jsonQuestions.isEmpty(), "La chaine de caractère JSON des questions est vide"); try { - final List<Question> questions = objectMapper.readValue(jsonQuestions, new TypeReference<List<Question>>(){}); + final List<SurveyQuestion> questions = objectMapper.readValue(jsonQuestions, new TypeReference<List<SurveyQuestion>>(){}); assertNotNull(questions, "La conversion du JSON des questions en liste a échoué"); assertNotEquals(questions.size(), 0, "La liste de questions est vide"); @@ -131,16 +131,16 @@ public class SurveyFormResourceTest extends JerseyTest { assertNotNull(jsonAllResponses, "Impossible de récupérer la ressource (objet null) des réponses"); assertFalse(jsonAllResponses.isEmpty(), "La chaine de caractère JSON des réponses est vide"); - final List<Response> allResponses = objectMapper.readValue(jsonAllResponses, new TypeReference<List<Response>>() {}); + final List<SurveyOption> allResponses = objectMapper.readValue(jsonAllResponses, new TypeReference<List<SurveyOption>>() {}); assertNotNull(allResponses, "La conversion du JSON des réponses en liste a échoué"); assertNotEquals(allResponses.size(), 0, "La liste de réponses est vide"); - for (final Response r : allResponses) { + for (final SurveyOption r : allResponses) { assertTrue(questions.contains(r.getQuestion()), "La question de la réponse « " + r.getDescription() + " » n'est pas contenue dans la liste des questions"); } // Pour chaque question, - for (final Question q : questions) { + for (final SurveyQuestion q : questions) { // on récupère les réponses associées via le webservice final String jsonResponses = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_RESPONSES_BY_QUESTION_LIST) .queryParam("questionRef", String.valueOf(q.getId())) @@ -150,16 +150,16 @@ public class SurveyFormResourceTest extends JerseyTest { assertNotNull(jsonResponses, "Impossible de récupérer la ressource (objet null) pour la question n° " + q.getId() + " est vide"); assertFalse(jsonResponses.isEmpty(), "La chaine de caractère JSON pour la question n° " + q.getId() + " est vide"); - final List<Response> responses = objectMapper.readValue(jsonResponses, new TypeReference<List<Response>>() {}); + final List<SurveyOption> responses = objectMapper.readValue(jsonResponses, new TypeReference<List<SurveyOption>>() {}); assertNotNull(responses, "La conversion du JSON des réponses de la question n° " + q.getId() + " n'a pas fonctionnée"); assertNotEquals(responses.size(), 0, " La liste de réponses pour la question n° " + q.getId() + " est vide"); - final List<Response> responsesByDao = responsesDao.findAllByQuestion(q.getId()); + final List<SurveyOption> responsesByDao = responsesDao.findAllByQuestion(q.getId()); assertNotNull(responsesByDao, " La lecture des réponses pour la question n° " + q.getId() + " via le DAO n'a pas fonctionné"); assertNotEquals(responsesByDao.size(), 0, " La liste de réponses via le DAO pour la question n° " + q.getId() + " est vide"); assertEquals(responses, responsesByDao, "La liste de réponses via le webservice n'est pas identique avec la liste via le DAO"); - for (final Response r : responses) { + for (final SurveyOption r : responses) { assertNotNull(r.getQuestion(), "La question de la réponse n° " + r.getId() + " est null"); assertEquals(r.getQuestion(), q, "La question de la réponse n° " + r.getId() + " ne correspond pas à la question"); assertTrue(responsesByDao.contains(r), "La liste via le DAO ne contient pas la réponse n° " + r.getId()); @@ -174,17 +174,17 @@ public class SurveyFormResourceTest extends JerseyTest { @Test public void testWithJsonResponses() { this.resetUserResponses(); - final List<Question> questionsList = questionsDao.findAll(); + final List<SurveyQuestion> questionsList = questionsDao.findAll(); final List<SurveyQuestionDTO> questionsDTO = questionsList.stream().map(SurveyFormResource::toDto).toList(); - final List<Response> responsesList = new ArrayList<>(); + final List<SurveyOption> responsesList = new ArrayList<>(); final HashMap<Long, String> otherTextMap = new HashMap<>(); - for (final Question q : questionsList) { - final List<Response> responsesListForQuestion = responsesDao.findAllByQuestion(q.getId()); + for (final SurveyQuestion q : questionsList) { + final List<SurveyOption> responsesListForQuestion = responsesDao.findAllByQuestion(q.getId()); // on récupère un nombre aléatoire de réponse - final List<Response> randomList = this.pickNRandom(responsesListForQuestion, ThreadLocalRandom.current().nextInt(0, responsesListForQuestion.size() - 1)); + final List<SurveyOption> randomList = this.pickNRandom(responsesListForQuestion, ThreadLocalRandom.current().nextInt(0, responsesListForQuestion.size() - 1)); // si il y a au moins une réponse récupérée aléatoirement if (randomList.size() > 0) { @@ -208,7 +208,7 @@ public class SurveyFormResourceTest extends JerseyTest { // Récupère toutes les réponses pour toutes les questions List<UserResponse> list = new ArrayList<>(); - for (final Question q : questionsDao.findAll()) { + for (final SurveyQuestion q : questionsDao.findAll()) { final List<UserResponse> responsesByQuestion = userResponsesDao.findAllByQuestion(q.getId()); assertNotNull(responsesByQuestion, "La liste de réponses de l'utilisateur pour la question « " + q.getId() + " » ne doit pas être null"); responsesByQuestion.forEach((ur) -> { @@ -221,11 +221,11 @@ public class SurveyFormResourceTest extends JerseyTest { list.forEach((ur) -> { assertNotNull(ur.getDateTime(), "Le timestamp de la réponse ne doit pas être null"); assertTrue(ur.getId() > 0, "la référence de la réponse de l'utilisateur doit être supérieur à 0"); - if (ur.getResponse() != null) { - assertNotNull(ur.getResponse(), "La réponse de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); + if (ur.getOption() != null) { + assertNotNull(ur.getOption(), "La réponse de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); assertNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, doit être null"); } else { - assertNull(ur.getResponse(), "La réponse de l'utilisateur, pour une réponse libre, doit être null"); + assertNull(ur.getOption(), "La réponse de l'utilisateur, pour une réponse libre, doit être null"); assertNotNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); } }); @@ -264,8 +264,8 @@ public class SurveyFormResourceTest extends JerseyTest { * @param nbElements to pick in list * @return randomized list with nbElements */ - private List<Response> pickNRandom(final List<Response> list, final int nbElements) { - final List<Response> copy = new ArrayList<Response>(list); + private List<SurveyOption> pickNRandom(final List<SurveyOption> list, final int nbElements) { + final List<SurveyOption> copy = new ArrayList<SurveyOption>(list); Collections.shuffle(copy); if (nbElements > copy.size()) { return copy.subList(0, copy.size()); diff --git a/www-server/src/test/resources/META-INF/persistence.xml b/www-server/src/test/resources/META-INF/persistence.xml index 9f6b455..3a55dd0 100644 --- a/www-server/src/test/resources/META-INF/persistence.xml +++ b/www-server/src/test/resources/META-INF/persistence.xml @@ -18,8 +18,8 @@ <class>fr.agrometinfo.www.server.model.PraDailyValue</class> <class>fr.agrometinfo.www.server.model.Region</class> <class>fr.agrometinfo.www.server.model.Simulation</class> - <class>fr.agrometinfo.www.server.model.Question</class> - <class>fr.agrometinfo.www.server.model.Response</class> + <class>fr.agrometinfo.www.server.model.SurveyQuestion</class> + <class>fr.agrometinfo.www.server.model.SurveyOption</class> <class>fr.agrometinfo.www.server.model.UserResponse</class> <class>fr.agrometinfo.www.server.model.UserEmail</class> <properties> -- GitLab From 5d21693e40f55726c46003ac6ee58e3c8e52cb06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Fri, 31 May 2024 16:06:40 +0200 Subject: [PATCH 24/30] =?UTF-8?q?Suppression=20de=20la=20m=C3=A9thode=20d'?= =?UTF-8?q?insertion=20des=20r=C3=A9ponses,=20via=20le=20DAO,=20par=20les?= =?UTF-8?q?=20r=C3=A9f=C3=A9rences?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../www/server/dao/UserResponsesDao.java | 20 --------------- .../server/dao/UserResponsesDaoHibernate.java | 25 ------------------- .../www/server/rs/SurveyFormResource.java | 14 ++++++----- .../www/server/SurveyFormHibernateTest.java | 5 ++-- 4 files changed, 10 insertions(+), 54 deletions(-) diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java index 9880b59..3a364db 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDao.java @@ -37,26 +37,6 @@ public interface UserResponsesDao { * @param datetime provided localdatetime */ void insertResponse(SurveyQuestion q, SurveyOption r, String otherText, LocalDateTime datetime); - /** - * Insert response or text for specified question, identified by reference.<br> - * If responseRef is provided, {@code otherText} must be null.<br> - * If otherText is provided, {@code responseRef} must be null.<br> - * datetime is defined by {@link LocalDateTime#now} in this method. - * @param questionRef reference of question to answer - * @param responseRef reference of response - * @param otherText text if response is other - */ - void insertResponse(Long questionRef, Long responseRef, String otherText); - /** - * Insert response or text for specified question, identified by reference.<br> - * If responseRef is provided, {@code otherText} must be null.<br> - * If otherText is provided, {@code responseRef} must be null. - * @param questionRef reference of question to answer - * @param responseRef reference of response - * @param otherText text if response is other - * @param datetime provided datetime - */ - void insertResponse(Long questionRef, Long responseRef, String otherText, LocalDateTime datetime); /** * Get all user responses. * @return number of responses diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java index 0e17273..0e8b457 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java @@ -18,10 +18,6 @@ import jakarta.enterprise.context.ApplicationScoped; */ @ApplicationScoped public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implements UserResponsesDao { - /** DAO for questions. */ - private SurveyQuestionDao questionsDao = new SurveyQuestionDaoHibernate(); - /** DAO for responses. */ - private SurveyOptionDao responsesDao = new SurveyOptionDaoHibernate(); /** Default constructor. */ public UserResponsesDaoHibernate() { super(UserResponse.class); @@ -52,27 +48,6 @@ public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implem } /** */ @Override - public void insertResponse( - final Long questionRef, final Long responseRef, - final String otherText, final LocalDateTime datetime) { - // recherche de la question - final SurveyQuestion q = questionsDao.findByRef(questionRef); - if (q != null) { - if (responseRef != null) { // insertion d'une réponse prédéfinie, on recherche de la réponse - final SurveyOption r = responsesDao.findByRef(responseRef); - this.insertResponse(q, r, null, datetime); - } else { // insertion d'une réponse libre - this.insertResponse(q, null, otherText, datetime); - } - } - } - /** */ - @Override - public void insertResponse(final Long questionRef, final Long responseRef, final String otherText) { - this.insertResponse(questionRef, responseRef, otherText, LocalDateTime.now()); - } - /** */ - @Override public int getNbUserResponses() { return super.findAll().size(); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java index d612dfd..8af54fc 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java @@ -172,24 +172,26 @@ public class SurveyFormResource implements SurveyFormService { this.checkRequired(questionRef, "questionRef"); final boolean responseRefIsNull = responseRef == null || responseRef.equals("null"); final boolean otherTextIsNull = otherText == null || otherText.equals("null"); - if (this.checkIfQuestionExist(questionRef)) { + + final SurveyQuestion q = questionsDao.findByRef(questionRef); + if (q != null) { if (!responseRefIsNull && otherTextIsNull) { // réponse prédéfinie - this.userResponsesDao.insertResponse(questionRef, Long.valueOf(responseRef), null, LocalDateTime.now()); + final SurveyOption r = responsesDao.findByRef(Long.valueOf(responseRef)); + this.userResponsesDao.insertResponse(q, r, null, LocalDateTime.now()); } else if (responseRefIsNull && !otherTextIsNull) { // réponse libre - this.userResponsesDao.insertResponse(questionRef, null, otherText, LocalDateTime.now()); + this.userResponsesDao.insertResponse(q, null, otherText, LocalDateTime.now()); } } } /** * Check on database if reference of question exists. * @param questionRef - * @return {@code true} if question exists or {@code false} otherwise + * @return {@code true} if question exists or {@code false} value otherwise */ private boolean checkIfQuestionExist(final Long questionRef) { if (questionRef != null) { // on cherche dans le DAO - final SurveyQuestion q = questionsDao.findByRef(questionRef); - return q != null; + return questionsDao.findByRef(questionRef) != null; } return false; } diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index 7a161be..d38049e 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -141,7 +141,6 @@ public class SurveyFormHibernateTest { } } - // Essai de l'insertion par les références, avec une autre question final SurveyQuestion useCase = questions.stream().filter((q) -> q.getId() == 3).findFirst().get(); assertNotNull(useCase, "Aucune question ne correspond aux cas d'utilisation"); responses = responsesDao.findAllByQuestion(useCase.getId()); @@ -149,7 +148,7 @@ public class SurveyFormHibernateTest { assertNotEquals(responses.size(), 0, "La liste de réponses pour la la question des cas d'utilisation est vide"); r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); - userResponsesDao.insertResponse(useCase.getId(), r.getId(), null); + userResponsesDao.insertResponse(useCase, r, null); list = userResponsesDao.findAllByQuestion(useCase.getId()); assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur pour la question des cas d'utilisation doit contenir un élément"); @@ -158,7 +157,7 @@ public class SurveyFormHibernateTest { assertNull(list.get(0).getOtherText(), "Le texte libre doit être null"); other = other.concat(" pour la question des cas d'utilisation"); - userResponsesDao.insertResponse(useCase.getId(), null, other); + userResponsesDao.insertResponse(useCase, null, other); list = userResponsesDao.findAllByQuestion(useCase.getId()); assertEquals(list.size(), 2, "La liste de réponses de l'utilisateur pour la question des cas d'utilisation doit contenir deux éléments"); -- GitLab From e0743d9816040b1eb8f0e191e68933b4d7380395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Tue, 4 Jun 2024 11:08:44 +0200 Subject: [PATCH 25/30] =?UTF-8?q?Retrait=20des=20points=20d'entr=C3=A9es?= =?UTF-8?q?=20inutiles=20du=20webservice=20Commentaires=20en=20anglais=20M?= =?UTF-8?q?essages=20des=20tests=20en=20anglais=20Nettoyage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/fr/agrometinfo/www/client/App.java | 2 +- .../www/client/presenter/SurveyPresenter.java | 18 ++- .../www/client/view/SurveyView.java | 26 ++-- .../www/server/dao/SurveyOptionDao.java | 3 - .../server/dao/SurveyOptionDaoHibernate.java | 8 +- .../www/server/dao/SurveyQuestionDao.java | 3 - .../dao/SurveyQuestionDaoHibernate.java | 7 +- .../www/server/dao/UserEmailDao.java | 2 +- .../www/server/dao/UserEmailDaoHibernate.java | 1 + .../server/dao/UserResponsesDaoHibernate.java | 10 +- .../www/server/model/SurveyOption.java | 10 +- .../www/server/model/SurveyQuestion.java | 10 +- .../www/server/model/UserEmail.java | 1 - .../www/server/model/UserResponse.java | 17 ++- .../www/server/rs/SurveyFormResource.java | 88 +++---------- .../www/server/util/EmailUtils.java | 12 +- .../www/server/SurveyFormHibernateTest.java | 123 +++++++++-------- .../www/server/rs/SurveyFormResourceTest.java | 124 +++++++----------- .../www/shared/dto/SurveyOptionDTO.java | 7 +- .../www/shared/dto/SurveyQuestionDTO.java | 7 +- .../www/shared/dto/SurveyResponseDTO.java | 4 - .../www/shared/service/SurveyFormService.java | 52 +------- 22 files changed, 183 insertions(+), 352 deletions(-) diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/App.java b/www-client/src/main/java/fr/agrometinfo/www/client/App.java index 2de0783..542e4c0 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/App.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/App.java @@ -101,7 +101,7 @@ public class App implements EntryPoint { new LayoutPresenter().start(); - // formulaire d'enquête + // display survey form new SurveyPresenter().start(); } } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java index b40371f..00b81aa 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/presenter/SurveyPresenter.java @@ -70,10 +70,9 @@ public final class SurveyPresenter implements Presenter { this.responses = list; final Map<SurveyQuestionDTO, List<SurveyOptionDTO>> responsesMap = new HashMap<>(); - // extraction des questions, à partir des réponses retournées par le webservice + // extract questions from responses via webservice for (final SurveyOptionDTO dto : list) { - if (!responsesMap.containsKey(dto.getQuestion())) { // la map ne contient pas la question - // on crée l'entrée, avec une liste vide + if (!responsesMap.containsKey(dto.getQuestion())) { responsesMap.put(dto.getQuestion(), new ArrayList<SurveyOptionDTO>()); } responsesMap.get(dto.getQuestion()).add(dto); @@ -97,36 +96,35 @@ public final class SurveyPresenter implements Presenter { final List<Long> responsesRef, final Map<Long, String> otherTextMap, final String email) { - GWT.log("Insère les réponses de l'utilisateur"); - // traitement des réponses prédéfinies + // processing of predefined responses final Set<SurveyQuestionDTO> questionsDto = new LinkedHashSet<>(); final Set<SurveyOptionDTO> responsesDto = new LinkedHashSet<>(); for (final Long ref : responsesRef) { - // on récupère la réponse correspondante à la référence + // getting response by reference final SurveyOptionDTO rDto = this.responses.stream().filter(r -> r.getId() == ref).findFirst().get(); if (rDto != null) { responsesDto.add(rDto); - // on récupère la question correspondantes à la réponse + // getting question corresponding of response questionsDto.add(rDto.getQuestion()); } } - // ajout de la question, si celle çi n'a qu'une réponse libre + // addition of the question, if it only has a free answer this.questions.forEach((q) -> { if (otherTextMap.containsKey(q.getId())) { questionsDto.add(q); } }); - // envoi au webservice + // call to webservice for inserting data final SurveyResponseDTO data = new SurveyResponseDTO( new ArrayList<SurveyQuestionDTO>(questionsDto), new ArrayList<SurveyOptionDTO>(responsesDto), otherTextMap); - // traitement de l'adresse e-mail + // if user has entered their email address, it is added to object if (!email.isEmpty()) { data.setEmail(email); } diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java index 63b0c02..b98369a 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/SurveyView.java @@ -67,7 +67,7 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen @Override public void init() { GWT.log("LoginView.init()"); - // on vérifie que le formulaire n'a pas déjà été rempli par l'utilisateur, via le LocalStorage du navigateur + // check if survey form has not already been completed by user, via the browser's LocalStorage final Storage ls = Storage.getLocalStorageIfSupported(); if (ls != null && ls.getItem(IS_VALIDATED_KEY) != null && ls.getItem(IS_VALIDATED_KEY).equals("true")) { GWT.log("Survey was already validated for this user, don't showing again"); @@ -83,12 +83,12 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen ); for (Map.Entry<SurveyQuestionDTO, List<SurveyOptionDTO>> entry : this.availableResponses.entrySet()) { - final SurveyQuestionDTO k = entry.getKey(); // Pour chaque question + final SurveyQuestionDTO k = entry.getKey(); // For each question ... - // on affiche le libellé + // displaying label this.modal.appendChild(Elements.h(SECTION_TITLE_LEVEL, "• " + k.getDescription())); - // on affiche les réponses possibles + // displaying availables responses entry.getValue().forEach((r) -> { final CheckBox cb = CheckBox.create(r.getDescription()).id(Long.toString(r.getId())) .css("login-checkbox"); @@ -96,7 +96,7 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen this.checkBoxList.add(cb); }); - // on affiche le champ pour la réponse libre + // displaying free response field final CheckBox otherCb = CheckBox.create(CSTS.surveyFormOtherTextCheckbox()) .css("login-checkbox"); final TextArea otherText = TextArea.create() @@ -117,30 +117,30 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen this.modal.appendChild(otherCb).appendChild(otherText); otherTextArea.put(k.getId(), otherText); } - // active le bouton Valider si au moins une case a été cochée + // Validate button is activ if if at least one answer is checked this.checkBoxList.forEach((c) -> { c.addChangeHandler((v) -> this.activateValidateButton()); }); - // E-mail de l'utilisateur + // User's e-mail address this.modal.appendChild(Elements.p().textContent(CSTS.surveyFromEmailDescription())); this.email = TextBox.create().setType("email"); this.modal.appendChild(this.email); - // Boutons de la fenêtre modale + // Window's button this.validate = Button.create(CSTS.validate()).linkify(); this.validate.addClickListener((evt) -> { final HashMap<Long, String> otherTextMap = new HashMap<>(); - // on traite les réponses prédéfinies (récupération des références des réponses), - // en excluant les cases à cocher pour les réponses libre + // process the predefined responses (retrieval of response references), + // excluding checkbox for free responses final List<Long> selectedResponsesRef = this.checkBoxList.stream() .filter((v) -> v.getValue() && v.getId().matches("[0-9]+")) .map(v -> Long.parseLong(v.getId())).collect(Collectors.toList()); - // traitement des réponses libre de la question + // process the free responses otherTextArea.forEach((k, v) -> { - // si le champ est actif, c'est qu'il y a (potentiellement) une réponse et si le champ n'est pas vide + // if textarea is activ, there is (potentially) a response and if textarea is not empty if (!v.isDisabled() && !v.getValue().equals("")) { otherTextMap.put(k, v.getValue()); } @@ -151,7 +151,7 @@ public final class SurveyView extends AbstractBaseView<SurveyPresenter> implemen ls.setItem(IS_VALIDATED_KEY, "true"); this.modal.close(); }); - this.validate.setDisabled(true); // le bouton Valider est désactivé par défaut + this.validate.setDisabled(true); // Validate button is disable by default this.modal.appendFooterChild(validate); final Button ignore = Button.create(CSTS.ignore()).linkify(); diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDao.java index 52dab0b..214e608 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDao.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.server.dao; import fr.agrometinfo.www.server.model.SurveyOption; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDaoHibernate.java index d107e16..6b98c99 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyOptionDaoHibernate.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.server.dao; import java.util.List; @@ -10,24 +7,23 @@ import fr.agrometinfo.www.server.model.SurveyOption; import jakarta.enterprise.context.ApplicationScoped; /** + * Implementation of {@link SurveyOptionDao}. * @author jdecome * */ @ApplicationScoped -public class SurveyOptionDaoHibernate extends DaoHibernate<SurveyOption> implements SurveyOptionDao { +public final class SurveyOptionDaoHibernate extends DaoHibernate<SurveyOption> implements SurveyOptionDao { /** * Constructor. */ public SurveyOptionDaoHibernate() { super(SurveyOption.class); } - /** */ @Override public List<SurveyOption> findAllByQuestion(final long questionRef) { final String jpql = "SELECT r FROM SurveyOption r WHERE r.question.id = :ref"; return super.findAllByJPQL(jpql, Map.of("ref", questionRef), SurveyOption.class); } - /** */ @Override public SurveyOption findByRef(final long responseRef) { return super.find(responseRef); diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDao.java index ef2d5e2..6a73dc5 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDao.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.server.dao; import java.util.List; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDaoHibernate.java index cddc768..0ef2956 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/SurveyQuestionDaoHibernate.java @@ -1,24 +1,21 @@ -/** - * - */ package fr.agrometinfo.www.server.dao; import fr.agrometinfo.www.server.model.SurveyQuestion; import jakarta.enterprise.context.ApplicationScoped; /** + * Implementation of {@link SurveyQuestionDao}. * @author jdecome * */ @ApplicationScoped -public class SurveyQuestionDaoHibernate extends DaoHibernate<SurveyQuestion> implements SurveyQuestionDao { +public final class SurveyQuestionDaoHibernate extends DaoHibernate<SurveyQuestion> implements SurveyQuestionDao { /** * Constructor. */ public SurveyQuestionDaoHibernate() { super(SurveyQuestion.class); } - /** */ @Override public SurveyQuestion findByRef(final long ref) { return super.find(ref); diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java index 4ab9254..e38e5b7 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDao.java @@ -23,7 +23,7 @@ public interface UserEmailDao { */ List<UserEmail> getEmailAddressList(); /** - * + * Delete all rows in table. */ void deleteAll(); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDaoHibernate.java index 80388d2..e45b99c 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserEmailDaoHibernate.java @@ -7,6 +7,7 @@ import fr.agrometinfo.www.server.model.UserEmail; import jakarta.enterprise.context.ApplicationScoped; /** + * Implementation of {@link UserEmailDao}. * @author jdecome * */ diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java index 0e8b457..01cd1ff 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/UserResponsesDaoHibernate.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.server.dao; import java.time.LocalDateTime; @@ -13,22 +10,21 @@ import fr.agrometinfo.www.server.model.UserResponse; import jakarta.enterprise.context.ApplicationScoped; /** + * Implementation of {@link UserResponsesDao}. * @author jdecome * */ @ApplicationScoped -public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implements UserResponsesDao { +public final class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implements UserResponsesDao { /** Default constructor. */ public UserResponsesDaoHibernate() { super(UserResponse.class); } - /** */ @Override public List<UserResponse> findAllByQuestion(final long questionRef) { final String jpql = "SELECT u FROM UserResponse u WHERE u.question.id = :ref"; return super.findAllByJPQL(jpql, Map.of("ref", questionRef), UserResponse.class); } - /** */ @Override public void insertResponse( final SurveyQuestion q, final SurveyOption r, @@ -41,12 +37,10 @@ public class UserResponsesDaoHibernate extends DaoHibernate<UserResponse> implem this.save(ur); } - /** */ @Override public void insertResponse(final SurveyQuestion q, final SurveyOption r, final String otherText) { this.insertResponse(q, r, otherText, LocalDateTime.now()); } - /** */ @Override public int getNbUserResponses() { return super.findAll().size(); diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyOption.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyOption.java index 8496c48..ddc5fe7 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyOption.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyOption.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.server.model; import jakarta.persistence.Column; @@ -14,16 +11,15 @@ import jakarta.persistence.Table; import lombok.Data; /** - * Option (response) for questions. + * Option (response) for questions of survey form. * @author jdecome - * */ @Data @Entity @Table(name = "surveyoption") public class SurveyOption { /** - * Reference of options.<br> + * Reference of the option.<br> * Primary key. */ @Id @@ -31,7 +27,7 @@ public class SurveyOption { @Column(name = "id") private long id; /** - * Question related to option. + * Question related to the option. */ @OneToOne @JoinColumn(name = "surveyquestion") diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyQuestion.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyQuestion.java index 9b26589..6596c6d 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyQuestion.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/SurveyQuestion.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.server.model; import jakarta.persistence.Column; @@ -12,16 +9,15 @@ import jakarta.persistence.Table; import lombok.Data; /** - * Questions for survey modal. + * Questions for survey form. * @author jdecome - * */ @Data @Entity @Table(name = "surveyquestion") public class SurveyQuestion { /** - * Reference of question.<br> + * Reference of the question.<br> * Primary key. */ @Id @@ -29,7 +25,7 @@ public class SurveyQuestion { @Column(name = "id") private long id; /** - * Label of question. + * Label of the question. */ @Column(name = "description") private String description; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java index 7aa74d3..8c54efc 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserEmail.java @@ -13,7 +13,6 @@ import lombok.Data; /** * Table for storage email adress.<br> * @author jdecome - * */ @Data @Entity diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java index 0ab9c08..b6e6147 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/UserResponse.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.server.model; import java.time.LocalDateTime; @@ -16,22 +13,28 @@ import jakarta.persistence.Table; import lombok.Data; /** - * User's responses values. + * User's responses values of survey form. * @author jdecome */ @Data @Entity @Table(name = "userresponse") public class UserResponse { - /** Primary key. */ + /** + * Primary key. + */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private long id; - /** Date time of user responses (creation date). */ + /** + * Date time of user responses (creation date). + */ @Column(name = "datetime") private LocalDateTime dateTime; - /** Related question. */ + /** + * Related question. + */ @OneToOne @JoinColumn(name = "surveyquestion") private SurveyQuestion question; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java index 8af54fc..1aec97d 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java @@ -1,10 +1,6 @@ -/** - * - */ package fr.agrometinfo.www.server.rs; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -28,8 +24,6 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.FormParam; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; @@ -93,7 +87,7 @@ public class SurveyFormResource implements SurveyFormService { @Inject private SurveyQuestionDao questionsDao; /** - * DAO for responses ({@link SurveyOptionDao}). + * DAO for options ({@link SurveyOptionDao}). */ @Inject private SurveyOptionDao responsesDao; @@ -130,30 +124,6 @@ public class SurveyFormResource implements SurveyFormService { } } @GET - @Path(SurveyFormService.PATH_QUESTIONS_LIST) - @Produces(MediaType.APPLICATION_JSON) - @Override - public List<SurveyQuestionDTO> getQuestions() { - return questionsDao.findAll().stream() - .map(SurveyFormResource::toDto).collect(Collectors.toList()); - } - @GET - @Path(SurveyFormService.PATH_RESPONSES_BY_QUESTION_LIST) - @Produces(MediaType.APPLICATION_JSON) - @Override - public List<SurveyOptionDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") final Long questionRef) { - this.checkRequired(questionRef, "questionRef"); - if (this.checkIfQuestionExist(questionRef)) { - final List<SurveyOption> list = responsesDao.findAllByQuestion(questionRef); - final List<SurveyOptionDTO> responses = new ArrayList<>(); - for (final SurveyOption r : list) { - responses.add(toDto(r)); - } - return responses; - } - return null; - } - @GET @Path(SurveyFormService.PATH_RESPONSES_LIST) @Produces(MediaType.APPLICATION_JSON) @Override @@ -163,75 +133,47 @@ public class SurveyFormResource implements SurveyFormService { } @POST @Path(SurveyFormService.PATH_INSERT_RESPONSE) - @Produces(MediaType.TEXT_PLAIN) - @Override - public void insertResponse( - @FormParam(value = "questionRef") final Long questionRef, - @FormParam(value = "responseRef") final String responseRef, - @FormParam(value = "otherText") final String otherText) { - this.checkRequired(questionRef, "questionRef"); - final boolean responseRefIsNull = responseRef == null || responseRef.equals("null"); - final boolean otherTextIsNull = otherText == null || otherText.equals("null"); - - final SurveyQuestion q = questionsDao.findByRef(questionRef); - if (q != null) { - if (!responseRefIsNull && otherTextIsNull) { // réponse prédéfinie - final SurveyOption r = responsesDao.findByRef(Long.valueOf(responseRef)); - this.userResponsesDao.insertResponse(q, r, null, LocalDateTime.now()); - } else if (responseRefIsNull && !otherTextIsNull) { // réponse libre - this.userResponsesDao.insertResponse(q, null, otherText, LocalDateTime.now()); - } - } - } - /** - * Check on database if reference of question exists. - * @param questionRef - * @return {@code true} if question exists or {@code false} value otherwise - */ - private boolean checkIfQuestionExist(final Long questionRef) { - if (questionRef != null) { - // on cherche dans le DAO - return questionsDao.findByRef(questionRef) != null; - } - return false; - } - @POST - @Path(SurveyFormService.PATH_INSERT_RESPONSE_WITH_JSON) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Override public String insertAllResponses(final SurveyResponseDTO data) { - // datetime commun à tous les enregistrements (des réponses et de l'email) + this.checkRequired(data, "data"); + // common datetime to all records (user responses and user email) final LocalDateTime datetime = LocalDateTime.now(); - // traitement des réponses prédéfinies - for (final SurveyQuestionDTO dto : data.getQuestions()) { // Pour chaque question répondue - // Insérer les réponses associés + final List<SurveyQuestion> questions = questionsDao.findAll(); + + // proccessing of predefined responses + for (final SurveyQuestionDTO dto : data.getQuestions()) { final SurveyQuestion q = toEntity(dto); + // if question from survey doesn't exist, don't inserting response + if (!questions.contains(q)) { + continue; + } + final Long qRef = dto.getId(); List<SurveyOptionDTO> associatedResponses = data.getResponses() .stream().filter(f -> f.getQuestion().getId() == qRef) .collect(Collectors.toList()); - // On insère les réponses prédéfinies for (final SurveyOptionDTO rDto : associatedResponses) { final SurveyOption r = toEntity(rDto); this.userResponsesDao.insertResponse(q, r, null, datetime); } - // Si il existe une réponse libre, l'insérer + // if free response present, inserted on database if (data.getOtherTextMap().containsKey(dto.getId()) && data.getOtherTextMap().get(dto.getId()) != null) { this.userResponsesDao.insertResponse(q, null, data.getOtherTextMap().get(q.getId()), datetime); } } - // Si l'utilisateur a fourni son adresse e-mail + // if the user provided their email address and is vaild if (EmailUtils.isEmailAddressValid(data.getEmail())) { this.userEmailDao.insertEmailUserAddress(data.getEmail(), datetime); } - // une fois que tout est inséré, on envoi un mail au support + // once everything is inserted, send an email to support this.mailService.sendLoginFilled(data); return "0"; } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/util/EmailUtils.java b/www-server/src/main/java/fr/agrometinfo/www/server/util/EmailUtils.java index 855de26..1006b22 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/util/EmailUtils.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/util/EmailUtils.java @@ -2,20 +2,24 @@ package fr.agrometinfo.www.server.util; import java.util.regex.Pattern; -import org.apache.commons.lang3.StringUtils; - /** * @author jdecome * */ -public class EmailUtils extends StringUtils { +public final class EmailUtils { + /** + * Private default constructor. + */ + private EmailUtils() { + + } /** * Check if email address provided is a valid address.<br> * Verification by not null and regex * @param email address * @return {@code true} or {@code false} */ - public static final boolean isEmailAddressValid(final String email) { + public static boolean isEmailAddressValid(final String email) { if (email == null) { return false; } diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index d38049e..74ff21d 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.server; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -29,14 +26,12 @@ import fr.agrometinfo.www.server.model.SurveyQuestion; import fr.agrometinfo.www.server.model.SurveyOption; import fr.agrometinfo.www.server.model.UserEmail; import fr.agrometinfo.www.server.model.UserResponse; -import lombok.extern.log4j.Log4j2; /** * Test of UserResponsesDaoHibernate. * @author jdecome * */ -@Log4j2 public class SurveyFormHibernateTest { /** DAO for user's responses. */ private UserResponsesDao userResponsesDao = new UserResponsesDaoHibernate(); @@ -50,12 +45,12 @@ public class SurveyFormHibernateTest { @Test public void getQuestion() { final List<SurveyQuestion> list = questionsDao.findAll(); - assertNotEquals(list.size(), 0, "La liste de questions est vide"); + assertNotEquals(list.size(), 0, "Questions list is empty"); for (final SurveyQuestion q : list) { - // recherche de la question par sa référence + // search questio by reference. final SurveyQuestion foundedByRef = questionsDao.findByRef(q.getId()); - assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getId() + " est null"); - assertEquals(foundedByRef, q, "L'objet correspondant à la question " + q.getId() + " ne correspond pas"); + assertNotNull(foundedByRef, "Object for question « " + q.getId() + " » is null"); + assertEquals(foundedByRef, q, "Object corresponding to question « " + q.getId() + " » doesn't corresponding"); } } @@ -63,22 +58,22 @@ public class SurveyFormHibernateTest { public void getResponses() { final List<SurveyQuestion> questions = questionsDao.findAll(); final List<SurveyOption> responses = responsesDao.findAll(); - assertNotEquals(responses.size(), 0, "La liste de réponses est vide"); + assertNotEquals(responses.size(), 0, "Options list is empty"); for (final SurveyOption r : responses) { - assertTrue(questions.contains(r.getQuestion()), "La liste de questions ne contient pas la question " + r.getQuestion().getId()); + assertTrue(questions.contains(r.getQuestion()), "Questions list doesn't contains question " + r.getQuestion().getId()); - // Test à partir de la question correspondante à la réponse + // Test from question corresponding to response final SurveyQuestion q = r.getQuestion(); - assertNotNull(q, "La question correspondante à la réponse " + r.getId() + " est null"); + assertNotNull(q, "Question corresponding to response « " + r.getId() + " » is null"); final SurveyQuestion foundedByRef = questionsDao.findByRef(q.getId()); - assertNotNull(foundedByRef, "L'objet correspondant à la question " + q.getId() + " est null"); - assertEquals(foundedByRef, r.getQuestion(), "L'objet correspondant à la question " + q.getId() + " ne correspond pas"); + assertNotNull(foundedByRef, "Object corresponding to question « " + q.getId() + " » doesn't corresponding"); + assertEquals(foundedByRef, r.getQuestion(), "Object corresponding to question « " + q.getId() + " » doesn't corresponding"); - // recherche de la réponse par sa référence + // Search response by reference final SurveyOption responseByRef = responsesDao.findByRef(r.getId()); - assertNotNull(responseByRef, "La réponse correspondante à la réponse " + r.getId() + " est null"); - assertEquals(responseByRef, r, "La réponse correspondante à la réponse " + r.getId() + " est vide"); + assertNotNull(responseByRef, "Object corresponding to response " + r.getId() + " is null"); + assertEquals(responseByRef, r, "Object corresponding to response " + r.getId() + " is empty"); } } @@ -87,88 +82,88 @@ public class SurveyFormHibernateTest { this.resetUserResponses(); final List<SurveyQuestion> questions = questionsDao.findAll(); final SurveyQuestion profession = questions.stream().filter((q) -> q.getDescription().contains("profession")).findFirst().get(); - assertNotNull(profession, "Aucune question ne correspond à la profession"); + assertNotNull(profession, "No question object matching to question of question about profession"); List<SurveyOption> responses = responsesDao.findAllByQuestion(profession.getId()); - assertNotNull(responses, "Aucune réponse ne correspond à la profession"); - assertNotEquals(responses.size(), 0, "La liste de réponses pour la profession est vide"); + assertNotNull(responses, "No response object matching to question of question about profession"); + assertNotEquals(responses.size(), 0, "List of responses about profession question is empty"); for (final SurveyOption r : responses) { - assertEquals(r.getQuestion(), profession, "La question de la réponse ne correspond pas avec la question d'origine"); + assertEquals(r.getQuestion(), profession, "Question of responses doesn't corresponding to original question"); } - // Insertion d'une réponse - final List<SurveyOption> listOfResponses = new ArrayList<>(); // liste des réponses insérées + // Inserting a single response + final List<SurveyOption> listOfResponses = new ArrayList<>(); // list of inserted answers SurveyOption r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); userResponsesDao.insertResponse(profession, r, null); listOfResponses.add(r); List<UserResponse> list = userResponsesDao.findAllByQuestion(profession.getId()); - assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur doit contenir un élément"); - assertEquals(list.get(0).getQuestion(), profession, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); - assertEquals(list.get(0).getOption(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); - assertNull(list.get(0).getOtherText(), "Le texte libre doit être null"); + assertEquals(list.size(), 1, "The user's response list must contain an item"); + assertEquals(list.get(0).getQuestion(), profession, "The question in the user's response does not match the original question"); + assertEquals(list.get(0).getOption(), r, "The answer contained in the user's response does not match the inserted answer"); + assertNull(list.get(0).getOtherText(), "Free response must be null"); - // Insertion de plusieurs réponses + // Inserting of multiple responses final int nbToInsert = 3; for (final SurveyOption res : pickNRandom(responses, nbToInsert)) { userResponsesDao.insertResponse(profession, res, null); listOfResponses.add(res); } list = userResponsesDao.findAllByQuestion(profession.getId()); - assertEquals(list.size(), (1 + nbToInsert), "La liste de réponses de l'utilisateur doit contenir la réponse précédente + " + nbToInsert + " réponses supplémentaires"); + assertEquals(list.size(), (1 + nbToInsert), "The user's answer list must contain the previous answer + " + nbToInsert + " additional answers"); for (final UserResponse ur : list) { - assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question"); - assertTrue(listOfResponses.contains(ur.getOption()), "La réponse contenue dans la réponse de l'utilisateur n'est pas dans la liste des réponses insérées"); - assertEquals(ur.getOption().getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); - assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); + assertEquals(ur.getQuestion(), profession, "The original question doesn't match with the Question object"); + assertTrue(listOfResponses.contains(ur.getOption()), "The answer contained in the user's answer is not in the list of inserted answers"); + assertEquals(ur.getOption().getQuestion(), profession, "The original question does not match with the Question object present in the Option object"); + assertNull(ur.getOtherText(), "The text must be null if it is an answer from a choice"); } final int newNbResponses = 1 + nbToInsert; - // Insertion d'une réponse à choix libre - String other = "Ceci est une réponse libre"; + // Insertion of a free choice answer + String other = "This is a free answer"; userResponsesDao.insertResponse(profession, null, other); list = userResponsesDao.findAllByQuestion(profession.getId()); - assertEquals(list.size(), (newNbResponses + 1), "La liste de réponses de l'utilisateur doit contenir les " + newNbResponses + " + la réponse libre"); + assertEquals(list.size(), (newNbResponses + 1), "The user's response list must contain the " + newNbResponses + "+ the free answer"); for (final UserResponse ur : list) { - assertEquals(ur.getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); - if (ur.getOtherText() != null) { // on est sur une réponse libre - assertNull(ur.getOption(), "L'objet response doit être null si il s'agit d'une réponse libre"); - assertEquals(ur.getOtherText(), other, "Le texte ne correspond pas à ce qui a été inséré en base"); - } else { - assertEquals(ur.getOption().getQuestion(), profession, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); - assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); + assertEquals(ur.getQuestion(), profession, "The original question does not match with the Question object in the user's response"); + if (ur.getOtherText() != null) { // free response + assertNull(ur.getOption(), "The Option object must be null if it is a free response"); + assertEquals(ur.getOtherText(), other, "The text does not correspond to what was inserted in the base"); + } else { // predefined response + assertEquals(ur.getOption().getQuestion(), profession, "The original question does not match with the Question object present in the Option object"); + assertNull(ur.getOtherText(), "The text must be null if it is an answer from a choice"); } } final SurveyQuestion useCase = questions.stream().filter((q) -> q.getId() == 3).findFirst().get(); - assertNotNull(useCase, "Aucune question ne correspond aux cas d'utilisation"); + assertNotNull(useCase, "No object match the use cases question"); responses = responsesDao.findAllByQuestion(useCase.getId()); - assertNotNull(responses, "Aucune réponse ne correspond à la question des cas d'utilisation"); - assertNotEquals(responses.size(), 0, "La liste de réponses pour la la question des cas d'utilisation est vide"); + assertNotNull(responses, "No answer matches the use case question object"); + assertNotEquals(responses.size(), 0, "The answer list for the use case question object is empty"); r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); userResponsesDao.insertResponse(useCase, r, null); list = userResponsesDao.findAllByQuestion(useCase.getId()); - assertEquals(list.size(), 1, "La liste de réponses de l'utilisateur pour la question des cas d'utilisation doit contenir un élément"); - assertEquals(list.get(0).getQuestion(), useCase, "La question contenue dans la réponse de l'utilisateur ne correspond pas avec la question d'origine"); - assertEquals(list.get(0).getOption(), r, "La réponse contenue dans la réponse de l'utilisateur ne correspond pas avec la réponse insérée"); - assertNull(list.get(0).getOtherText(), "Le texte libre doit être null"); + assertEquals(list.size(), 1, "The user answer list for the use case question must contain an item"); + assertEquals(list.get(0).getQuestion(), useCase, "The question in the user's response does not match the original question"); + assertEquals(list.get(0).getOption(), r, "The answer contained in the user's response does not match the inserted answer"); + assertNull(list.get(0).getOtherText(), "Free text must be null"); - other = other.concat(" pour la question des cas d'utilisation"); + other = other.concat(" for the question of use cases"); userResponsesDao.insertResponse(useCase, null, other); list = userResponsesDao.findAllByQuestion(useCase.getId()); - assertEquals(list.size(), 2, "La liste de réponses de l'utilisateur pour la question des cas d'utilisation doit contenir deux éléments"); + assertEquals(list.size(), 2, "The user answer list for the use case question must contain two items"); for (final UserResponse ur : list) { - assertEquals(ur.getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question dans la réponse de l'utilisateur"); - if (ur.getOtherText() != null) { // on est sur une réponse libre - assertNull(ur.getOption(), "L'objet response doit être null si il s'agit d'une réponse libre"); - assertEquals(ur.getOtherText(), other, "Le texte ne correspond pas à ce qui a été inséré en base"); - } else { - assertEquals(ur.getOption().getQuestion(), useCase, "La question d'origine ne correspond pas avec l'objet Question présent dans l'objet Response"); - assertNull(ur.getOtherText(), "Le texte doit être null si il s'agit d'une réponse parmi un choix"); + assertEquals(ur.getQuestion(), useCase, "The original question does not match with the Question object in the user's response"); + if (ur.getOtherText() != null) { // free response + assertNull(ur.getOption(), "The response object must be null if it is a free response"); + assertEquals(ur.getOtherText(), other, "The text does not correspond to what was inserted in the base"); + } else { // predefined response + assertEquals(ur.getOption().getQuestion(), useCase, "The original question does not match with the Question object present in the Option object"); + assertNull(ur.getOtherText(), "The text must be null if it is an answer from a choice"); } } } @@ -177,13 +172,13 @@ public class SurveyFormHibernateTest { // just testing insertion of email user, without insertion of responses (already tested) final String email = "jane.doe@inrae.fr"; List<UserEmail> list = this.userEmailDao.getEmailAddressList(); - assertNotNull(list, "La liste des e-mail n'est pas initialisée"); - assertEquals(list.size(), 0, "La liste des e-mail doit être vide"); + assertNotNull(list, "The email list is not initialized"); + assertEquals(list.size(), 0, "The email list must be empty"); this.userEmailDao.insertEmailUserAddress(email, LocalDateTime.now()); list = this.userEmailDao.getEmailAddressList(); - assertEquals(list.size(), 1, "La liste des e-mail doit contenir au moins un élément"); - assertEquals(list.get(0).getEmail(), email, "L'élément enregistré ne correspond pas avec le mail inséré « " + email + " »"); + assertEquals(list.size(), 1, "The email list must contain an item"); + assertEquals(list.get(0).getEmail(), email, "The saved item does not match the inserted email « " + email + " »"); } /** * Return randomly responses list diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java index 1797782..e904187 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.server.rs; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -55,7 +52,7 @@ import lombok.Getter; import lombok.extern.log4j.Log4j2; /** - * Test login form webservice. + * Test survey form webservice. * @author jdecome * */ @@ -114,63 +111,31 @@ public class SurveyFormResourceTest extends JerseyTest { } }); } - /** Test de la récupération des réponses. */ + /** Testing response retrieval from webservice. */ @Test public void getResponses() { - // On récupère les questions via le webservice - final String jsonQuestions = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_QUESTIONS_LIST).request().get(String.class); - assertNotNull(jsonQuestions, "Impossible de récupérer la ressource (objet null) pour les questions"); - assertFalse(jsonQuestions.isEmpty(), "La chaine de caractère JSON des questions est vide"); try { - final List<SurveyQuestion> questions = objectMapper.readValue(jsonQuestions, new TypeReference<List<SurveyQuestion>>(){}); - assertNotNull(questions, "La conversion du JSON des questions en liste a échoué"); - assertNotEquals(questions.size(), 0, "La liste de questions est vide"); + // get all questions from DAO for verification. + final List<SurveyQuestion> questions = questionsDao.findAll(); + assertNotEquals(questions.size(), 0, "Question list is empty"); - // On récupère l'ensemble des réponses + // Get all responses (options) by webservice final String jsonAllResponses = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_RESPONSES_LIST).request().get(String.class); - assertNotNull(jsonAllResponses, "Impossible de récupérer la ressource (objet null) des réponses"); - assertFalse(jsonAllResponses.isEmpty(), "La chaine de caractère JSON des réponses est vide"); + assertNotNull(jsonAllResponses, "Unable to retrieve resource (null object) from responses"); + assertFalse(jsonAllResponses.isEmpty(), "The JSON character string of the responses is empty"); final List<SurveyOption> allResponses = objectMapper.readValue(jsonAllResponses, new TypeReference<List<SurveyOption>>() {}); - assertNotNull(allResponses, "La conversion du JSON des réponses en liste a échoué"); - assertNotEquals(allResponses.size(), 0, "La liste de réponses est vide"); + assertNotNull(allResponses, "Conversion of JSON from responses to list failed"); + assertNotEquals(allResponses.size(), 0, "The answer list is empty"); for (final SurveyOption r : allResponses) { - assertTrue(questions.contains(r.getQuestion()), "La question de la réponse « " + r.getDescription() + " » n'est pas contenue dans la liste des questions"); - } - - // Pour chaque question, - for (final SurveyQuestion q : questions) { - // on récupère les réponses associées via le webservice - final String jsonResponses = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_RESPONSES_BY_QUESTION_LIST) - .queryParam("questionRef", String.valueOf(q.getId())) - .request() - .get(String.class); - - assertNotNull(jsonResponses, "Impossible de récupérer la ressource (objet null) pour la question n° " + q.getId() + " est vide"); - assertFalse(jsonResponses.isEmpty(), "La chaine de caractère JSON pour la question n° " + q.getId() + " est vide"); - - final List<SurveyOption> responses = objectMapper.readValue(jsonResponses, new TypeReference<List<SurveyOption>>() {}); - assertNotNull(responses, "La conversion du JSON des réponses de la question n° " + q.getId() + " n'a pas fonctionnée"); - assertNotEquals(responses.size(), 0, " La liste de réponses pour la question n° " + q.getId() + " est vide"); - - final List<SurveyOption> responsesByDao = responsesDao.findAllByQuestion(q.getId()); - assertNotNull(responsesByDao, " La lecture des réponses pour la question n° " + q.getId() + " via le DAO n'a pas fonctionné"); - assertNotEquals(responsesByDao.size(), 0, " La liste de réponses via le DAO pour la question n° " + q.getId() + " est vide"); - assertEquals(responses, responsesByDao, "La liste de réponses via le webservice n'est pas identique avec la liste via le DAO"); - - for (final SurveyOption r : responses) { - assertNotNull(r.getQuestion(), "La question de la réponse n° " + r.getId() + " est null"); - assertEquals(r.getQuestion(), q, "La question de la réponse n° " + r.getId() + " ne correspond pas à la question"); - assertTrue(responsesByDao.contains(r), "La liste via le DAO ne contient pas la réponse n° " + r.getId()); - } - + assertTrue(questions.contains(r.getQuestion()), "Question of the answer « " + r.getDescription() + " » is not contained in the list of questions"); } } catch (final JsonProcessingException e) { log.info(e.getMessage()); } } - /** Test en définissant les réponses pour les questions. */ + /** Test by setting answers for questions. */ @Test public void testWithJsonResponses() { this.resetUserResponses(); @@ -183,80 +148,79 @@ public class SurveyFormResourceTest extends JerseyTest { for (final SurveyQuestion q : questionsList) { final List<SurveyOption> responsesListForQuestion = responsesDao.findAllByQuestion(q.getId()); - // on récupère un nombre aléatoire de réponse + // Getting a randomly list of response final List<SurveyOption> randomList = this.pickNRandom(responsesListForQuestion, ThreadLocalRandom.current().nextInt(0, responsesListForQuestion.size() - 1)); - // si il y a au moins une réponse récupérée aléatoirement if (randomList.size() > 0) { responsesList.addAll(randomList); } - otherTextMap.put(q.getId(), "Réponse libre pour la question « " + q.getDescription() + " »"); + otherTextMap.put(q.getId(), "Free answer for the question « " + q.getDescription() + " »"); } final List<SurveyOptionDTO> responsesDTO = responsesList.stream().map(SurveyFormResource::toDto).toList(); final SurveyResponseDTO data = new SurveyResponseDTO(questionsDTO, responsesDTO, otherTextMap); data.setEmail("john.doe@inrae.fr"); - assertEquals(data.getQuestions(), questionsDTO, "La liste de questions dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); - assertEquals(data.getResponses(), responsesDTO, "La liste de réponses dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); - assertEquals(data.getOtherTextMap(), otherTextMap, "La liste de réponses libre dans l'objet LoginFormData ne correspond pas avec la liste d'origine"); + assertEquals(data.getQuestions(), questionsDTO, "List of questions in LoginFormData object does not match with original list"); + assertEquals(data.getResponses(), responsesDTO, "List of responses in LoginFormData object does not match with the original list"); + assertEquals(data.getOtherTextMap(), otherTextMap, "List of free responses in LoginFormData object does not match with the original list"); - jakarta.ws.rs.core.Response ret = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE_WITH_JSON) + jakarta.ws.rs.core.Response ret = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_INSERT_RESPONSE) .request(MediaType.APPLICATION_JSON).post(Entity.entity(data, MediaType.APPLICATION_JSON)); - assertEquals(ret.getStatus(), jakarta.ws.rs.core.Response.Status.OK.getStatusCode(), "Le point d'entrée d'insertion doit retourner le code status 200 (OK)"); + assertEquals(ret.getStatus(), jakarta.ws.rs.core.Response.Status.OK.getStatusCode(), "The insert entry point should return status code 200 (OK)"); - // Récupère toutes les réponses pour toutes les questions + // Retrieves all answers for all questions List<UserResponse> list = new ArrayList<>(); for (final SurveyQuestion q : questionsDao.findAll()) { final List<UserResponse> responsesByQuestion = userResponsesDao.findAllByQuestion(q.getId()); - assertNotNull(responsesByQuestion, "La liste de réponses de l'utilisateur pour la question « " + q.getId() + " » ne doit pas être null"); + assertNotNull(responsesByQuestion, "The user's answer list for the question « " + q.getId() + " » must not be null"); responsesByQuestion.forEach((ur) -> { - assertEquals(ur.getQuestion(), q, "La question contenue dans la réponse ne correspond pas avec la question d'origine « " + q.getDescription() + " »"); + assertEquals(ur.getQuestion(), q, "The question in the answer does not match the original question « " + q.getDescription() + " »"); }); list.addAll(responsesByQuestion); } - // Test sur toutes les réponses + // Test on all answers list.forEach((ur) -> { - assertNotNull(ur.getDateTime(), "Le timestamp de la réponse ne doit pas être null"); - assertTrue(ur.getId() > 0, "la référence de la réponse de l'utilisateur doit être supérieur à 0"); + assertNotNull(ur.getDateTime(), "The response timestamp must not be null"); + assertTrue(ur.getId() > 0, "Reference of the user response must be greater than 0"); if (ur.getOption() != null) { - assertNotNull(ur.getOption(), "La réponse de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); - assertNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, doit être null"); + assertNotNull(ur.getOption(), "The user response, for a predefined response, must not be null"); + assertNull(ur.getOtherText(), "The user's free response, for a predefined response, must be null"); } else { - assertNull(ur.getOption(), "La réponse de l'utilisateur, pour une réponse libre, doit être null"); - assertNotNull(ur.getOtherText(), "La réponse libre de l'utilisateur, pour une réponse prédéfinie, ne doit pas être null"); + assertNull(ur.getOption(), "The user's response, for a free response, must be null"); + assertNotNull(ur.getOtherText(), "The user's free response, for a predefined response, must not be null"); } }); - // on vérifie que tous les enregistrements ont le même datetime - assertEquals(list.stream().map((u) -> u.getDateTime()).distinct().count(), 1, "Toutes les réponses n'ont pas le même datetime"); + // Check if all records has the same datetime + assertEquals(list.stream().map((u) -> u.getDateTime()).distinct().count(), 1, "Not all answers have the same datetime"); final LocalDateTime datetimeResponse = list.stream().map((u) -> u.getDateTime()).distinct().findFirst().get(); - assertNotNull(datetimeResponse, "Le datetime lue dans les réponses est null"); + assertNotNull(datetimeResponse, "The datetime read in the responses is null"); // dans ce cas de test, on a inséré l'adresse mail de l'utilisateur final List<UserEmail> emails = this.userEmailDao.getEmailAddressList(); - assertNotNull(emails, "La liste des emails n'est pas initialisée"); - assertNotEquals(emails.size(), 0, "La liste des emails est vide"); + assertNotNull(emails, "The email list is not initialized (= null)"); + assertNotEquals(emails.size(), 0, "Email list is empty"); emails.forEach((e) -> { - assertTrue((e.getId() > 0), "L'id de l'objet doit être supérieur à 0"); - assertNotNull(e.getDatetime(), "Le timestamp de la question ne doit pas être null"); - assertNotNull(e.getEmail(), "L'adresse mail contenue dans l'objet ne doit pas être null"); + assertTrue((e.getId() > 0), "The object id must be greater than 0"); + assertNotNull(e.getDatetime(), "The timestamp of the question must not be null"); + assertNotNull(e.getEmail(), "The email address contained in the subject must not be null"); }); - assertEquals(emails.stream().map((e) -> e.getDatetime()).distinct().count(), 1, "Toutes les adresses mails n'ont pas le même datetime"); + assertEquals(emails.stream().map((e) -> e.getDatetime()).distinct().count(), 1, "Not all email addresses have the same datetime"); final LocalDateTime datetimeEmail = emails.stream().map((e) -> e.getDatetime()).distinct().findFirst().get(); - assertNotNull(datetimeEmail, "Le datetime lue dans les emails est null"); + assertNotNull(datetimeEmail, "The datetime read in emails is null"); - assertEquals(datetimeResponse, datetimeEmail, "Les deux datetime ne sont pas identique"); + assertEquals(datetimeResponse, datetimeEmail, "The two datetimes are not identical"); - // on vérifie le mail envoyé au support, lorsqu'un utilisateur a rempli le formulaire + // Check mail sended to support, when user filled survey form final Mail mail = ((MailServiceTest) this.mailService).getMail(); - assertNotNull(mail, "L'objet mail ne doit pas être null"); - assertNotNull(mail.getContent(), "Le corps du message n'est pas défini (= null)"); - assertFalse(mail.getContent().isEmpty(), "Le corps du message est vide"); + assertNotNull(mail, "The mail object must not be null"); + assertNotNull(mail.getContent(), "Message body is not defined (= null)"); + assertFalse(mail.getContent().isEmpty(), "The message body is empty"); } /** * diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyOptionDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyOptionDTO.java index 438217d..029b6de 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyOptionDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyOptionDTO.java @@ -1,19 +1,16 @@ -/** - * - */ package fr.agrometinfo.www.shared.dto; import org.dominokit.jackson.annotation.JSONMapper; /** - * DTO for responses (as options) for survey form. + * DTO for options for survey form. * @author jdecome * */ @JSONMapper public class SurveyOptionDTO { /** - * Ref of this response. + * Reference of this response. */ private long id; /** diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java index 49b5545..265f2c5 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyQuestionDTO.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.shared.dto; import java.util.Objects; @@ -8,14 +5,14 @@ import java.util.Objects; import org.dominokit.jackson.annotation.JSONMapper; /** - * DTO for questions of login form. + * DTO for questions of survey form. * @author jdecome * */ @JSONMapper public class SurveyQuestionDTO { /** - * Ref of question. + * Reference of question. */ private long id; /** diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java index f8ad80b..67054b1 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/dto/SurveyResponseDTO.java @@ -1,13 +1,9 @@ -/** - * - */ package fr.agrometinfo.www.shared.dto; import java.util.HashMap; import java.util.List; import java.util.Map; - /** * Class contains all data of survey form. * @author jdecome diff --git a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java index 4475dc5..b41ab70 100644 --- a/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java +++ b/www-shared/src/main/java/fr/agrometinfo/www/shared/service/SurveyFormService.java @@ -1,6 +1,3 @@ -/** - * - */ package fr.agrometinfo.www.shared.service; import java.util.List; @@ -13,13 +10,10 @@ import org.dominokit.rest.shared.request.service.annotations.RequestFactory; import org.dominokit.rest.shared.request.service.annotations.RequestBody; import fr.agrometinfo.www.shared.dto.SurveyResponseDTO; -import fr.agrometinfo.www.shared.dto.SurveyQuestionDTO; import fr.agrometinfo.www.shared.dto.SurveyOptionDTO; -import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.FormParam; -import jakarta.ws.rs.QueryParam; /** + * Interface for survey form client server resource. * @author jdecome * */ @@ -27,55 +21,23 @@ import jakarta.ws.rs.QueryParam; @Path(SurveyFormService.PATH) public interface SurveyFormService { /** Service base path. */ - String PATH = "login"; - /** Path for {@link SurveyFormService#getQuestions()}. */ - String PATH_QUESTIONS_LIST = "questions"; + String PATH = "survey"; /** Path for {@link SurveyFormService#getResponses}. */ String PATH_RESPONSES_LIST = "responses"; - /** Path for {@link SurveyFormService#getResponsesByQuestion(long)}. */ - String PATH_RESPONSES_BY_QUESTION_LIST = "responsesByQuestion"; - /** Path for {@link SurveyFormService#getResponses()}. */ - String PATH_INSERT_RESPONSE = "insert"; - /** Path for {@link SurveyFormService#insertResponse(String)}. */ - String PATH_INSERT_RESPONSE_WITH_JSON = "insertMultipleValues"; + /** Path for {@link SurveyFormService#insertAllResponses(SurveyResponseDTO)}. */ + String PATH_INSERT_RESPONSE = "insertResponses"; /** - * @return list of questions. + * @return list of availables options for questions. */ @GET - @Path(PATH_QUESTIONS_LIST) - List<SurveyQuestionDTO> getQuestions(); - @GET @Path(PATH_RESPONSES_LIST) List<SurveyOptionDTO> getResponses(); /** - * Returning the list of possible response for one question. - * @param questionRef ref of question - * @return list of question's responses - */ - @GET - @Path(PATH_RESPONSES_BY_QUESTION_LIST) - List<SurveyOptionDTO> getResponsesByQuestion(@QueryParam(value = "questionRef") Long questionRef); - /** - * Insert response or text for specified question.<br> - * If responseRef is provided, {@code otherText} must be null.<br> - * If otherText is provided, {@code responseRef} must be null. - * @param questionRef ref of question - * @param responseRef ref of response or « null » String for null value - * @param otherText text if response is other - */ - @POST - @Path(PATH_INSERT_RESPONSE) - void insertResponse( - @FormParam(value = "questionRef") Long questionRef, - @FormParam(value = "responseRef") @DefaultValue("null") String responseRef, - @FormParam(value = "otherText") @DefaultValue("null") String otherText - ); - /** - * Insert all responses of login form. + * Insert all responses of survey form. * @param data object to insert * @return return code */ @POST - @Path(PATH_INSERT_RESPONSE_WITH_JSON) + @Path(PATH_INSERT_RESPONSE) String insertAllResponses(@RequestBody SurveyResponseDTO data); } -- GitLab From f1e061af1f4df2672dbd630934c6ee859c6b922b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Tue, 4 Jun 2024 11:49:19 +0200 Subject: [PATCH 26/30] corrections test commit c5094fd0 --- .../fr/agrometinfo/www/server/SurveyFormHibernateTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index 74ff21d..8a30ec2 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -169,11 +169,12 @@ public class SurveyFormHibernateTest { } @Test public void setUserResponsesWithEmail() { + this.resetUserResponses(); // just testing insertion of email user, without insertion of responses (already tested) final String email = "jane.doe@inrae.fr"; List<UserEmail> list = this.userEmailDao.getEmailAddressList(); assertNotNull(list, "The email list is not initialized"); - assertEquals(list.size(), 0, "The email list must be empty"); + assertTrue(list.isEmpty(), "The email list must be empty"); this.userEmailDao.insertEmailUserAddress(email, LocalDateTime.now()); list = this.userEmailDao.getEmailAddressList(); -- GitLab From 7fe92185c95205e831c2a593286bb5db129177a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Tue, 4 Jun 2024 15:12:59 +0200 Subject: [PATCH 27/30] Modification des cas de tests --- .../www/server/SurveyFormHibernateTest.java | 15 ++++++++------- .../www/server/rs/SurveyFormResourceTest.java | 8 ++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java index 8a30ec2..6e5f606 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/SurveyFormHibernateTest.java @@ -1,6 +1,7 @@ package fr.agrometinfo.www.server; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -45,9 +46,9 @@ public class SurveyFormHibernateTest { @Test public void getQuestion() { final List<SurveyQuestion> list = questionsDao.findAll(); - assertNotEquals(list.size(), 0, "Questions list is empty"); + assertFalse(list.isEmpty(), "Questions list is empty"); for (final SurveyQuestion q : list) { - // search questio by reference. + // search question by reference. final SurveyQuestion foundedByRef = questionsDao.findByRef(q.getId()); assertNotNull(foundedByRef, "Object for question « " + q.getId() + " » is null"); assertEquals(foundedByRef, q, "Object corresponding to question « " + q.getId() + " » doesn't corresponding"); @@ -58,7 +59,7 @@ public class SurveyFormHibernateTest { public void getResponses() { final List<SurveyQuestion> questions = questionsDao.findAll(); final List<SurveyOption> responses = responsesDao.findAll(); - assertNotEquals(responses.size(), 0, "Options list is empty"); + assertFalse(responses.isEmpty(), "Options list is empty"); for (final SurveyOption r : responses) { assertTrue(questions.contains(r.getQuestion()), "Questions list doesn't contains question " + r.getQuestion().getId()); @@ -85,7 +86,7 @@ public class SurveyFormHibernateTest { assertNotNull(profession, "No question object matching to question of question about profession"); List<SurveyOption> responses = responsesDao.findAllByQuestion(profession.getId()); assertNotNull(responses, "No response object matching to question of question about profession"); - assertNotEquals(responses.size(), 0, "List of responses about profession question is empty"); + assertFalse(responses.isEmpty(), "List of responses about profession question is empty"); for (final SurveyOption r : responses) { assertEquals(r.getQuestion(), profession, "Question of responses doesn't corresponding to original question"); } @@ -97,7 +98,7 @@ public class SurveyFormHibernateTest { listOfResponses.add(r); List<UserResponse> list = userResponsesDao.findAllByQuestion(profession.getId()); - assertEquals(list.size(), 1, "The user's response list must contain an item"); + assertEquals(list.size(), 1, "The user's response list must contain an item only"); assertEquals(list.get(0).getQuestion(), profession, "The question in the user's response does not match the original question"); assertEquals(list.get(0).getOption(), r, "The answer contained in the user's response does not match the inserted answer"); assertNull(list.get(0).getOtherText(), "Free response must be null"); @@ -140,13 +141,13 @@ public class SurveyFormHibernateTest { assertNotNull(useCase, "No object match the use cases question"); responses = responsesDao.findAllByQuestion(useCase.getId()); assertNotNull(responses, "No answer matches the use case question object"); - assertNotEquals(responses.size(), 0, "The answer list for the use case question object is empty"); + assertFalse(responses.isEmpty(), "The answer list for the use case question object is empty"); r = responses.get(ThreadLocalRandom.current().nextInt(0, responses.size() - 1)); userResponsesDao.insertResponse(useCase, r, null); list = userResponsesDao.findAllByQuestion(useCase.getId()); - assertEquals(list.size(), 1, "The user answer list for the use case question must contain an item"); + assertEquals(list.size(), 1, "The user answer list for the use case question must contain an item only"); assertEquals(list.get(0).getQuestion(), useCase, "The question in the user's response does not match the original question"); assertEquals(list.get(0).getOption(), r, "The answer contained in the user's response does not match the inserted answer"); assertNull(list.get(0).getOtherText(), "Free text must be null"); diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java index e904187..58c0c84 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java @@ -117,7 +117,7 @@ public class SurveyFormResourceTest extends JerseyTest { try { // get all questions from DAO for verification. final List<SurveyQuestion> questions = questionsDao.findAll(); - assertNotEquals(questions.size(), 0, "Question list is empty"); + assertFalse(questions.isEmpty(), "Question list is empty"); // Get all responses (options) by webservice final String jsonAllResponses = target(SurveyFormResource.PATH + SEP + SurveyFormResource.PATH_RESPONSES_LIST).request().get(String.class); @@ -126,7 +126,7 @@ public class SurveyFormResourceTest extends JerseyTest { final List<SurveyOption> allResponses = objectMapper.readValue(jsonAllResponses, new TypeReference<List<SurveyOption>>() {}); assertNotNull(allResponses, "Conversion of JSON from responses to list failed"); - assertNotEquals(allResponses.size(), 0, "The answer list is empty"); + assertFalse(allResponses.isEmpty(), "The answer list is empty"); for (final SurveyOption r : allResponses) { assertTrue(questions.contains(r.getQuestion()), "Question of the answer « " + r.getDescription() + " » is not contained in the list of questions"); @@ -199,10 +199,10 @@ public class SurveyFormResourceTest extends JerseyTest { final LocalDateTime datetimeResponse = list.stream().map((u) -> u.getDateTime()).distinct().findFirst().get(); assertNotNull(datetimeResponse, "The datetime read in the responses is null"); - // dans ce cas de test, on a inséré l'adresse mail de l'utilisateur + // in this case, email address has inserted final List<UserEmail> emails = this.userEmailDao.getEmailAddressList(); assertNotNull(emails, "The email list is not initialized (= null)"); - assertNotEquals(emails.size(), 0, "Email list is empty"); + assertFalse(emails.isEmpty(), "Email list is empty"); emails.forEach((e) -> { assertTrue((e.getId() > 0), "The object id must be greater than 0"); -- GitLab From 506a48b1704acc3f109a801cf1fb4ecd73b8bfc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Wed, 12 Jun 2024 09:41:34 +0200 Subject: [PATCH 28/30] modification suite rebase --- sql/migration.sql | 63 +------------------ .../www/client/view/LayoutView.java | 47 +------------- .../www/server/rs/ApplicationResource.java | 2 +- 3 files changed, 4 insertions(+), 108 deletions(-) diff --git a/sql/migration.sql b/sql/migration.sql index cc5cb5d..423dc0d 100644 --- a/sql/migration.sql +++ b/sql/migration.sql @@ -85,65 +85,6 @@ END $$ LANGUAGE plpgsql; COMMENT ON FUNCTION drop_applied_migration_functions() IS 'Purge database from applied migration functions.'; ---- ---- #8 ---- -CREATE OR REPLACE FUNCTION upgrade20231023() RETURNS boolean AS $BODY$ -BEGIN - ALTER TABLE indicator DROP COLUMN colorsequence; - DROP TABLE colorsequence; - ALTER TABLE indicator ADD COLUMN colorsequencename VARCHAR; - ALTER TABLE indicator ADD COLUMN nbofclasses INTEGER; - CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES'); - ALTER TABLE indicator ADD COLUMN quantiletype QUANTILETYPE; - UPDATE indicator SET quantiletype='QUINTILES'; - UPDATE indicator SET colorsequencename='Precipitation' WHERE code='rainsum'; - UPDATE indicator SET colorsequencename='Blues' WHERE code='frostdaystmin'; - UPDATE indicator SET colorsequencename='Temperature' WHERE code IN ('mint', 'meant', 'maxt'); - UPDATE indicator SET colorsequencename='YlOrRd' WHERE code IN ('hdaystmax', 'hdaystmax1'); - ALTER TABLE indicator ADD CONSTRAINT "CK_indicator_colorsequence" CHECK (nbofclasses IS NOT NULL OR quantiletype IS NOT NULL); - RETURN true; -END -$BODY$ -language plpgsql; - ---- ---- #8 ---- -CREATE OR REPLACE FUNCTION upgrade20231030() RETURNS boolean AS $BODY$ -BEGIN - ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE VARCHAR USING QUANTILETYPE::VARCHAR; - DROP TYPE QUANTILETYPE; - CREATE TYPE QUANTILETYPE AS ENUM('CENTILES_05', 'QUANTILES', 'DECILES', 'QUINTILES', 'QUARTILES', 'SEXTILES'); - ALTER TABLE "indicator" ALTER COLUMN quantiletype TYPE QUANTILETYPE USING quantiletype::quantiletype; - UPDATE indicator SET quantiletype='SEXTILES'; - --- #12 - CREATE TYPE AGGREGATIONTYPE AS ENUM('AVG', 'MAX'); - ALTER TABLE "indicator" ADD COLUMN aggregationtype AGGREGATIONTYPE; - UPDATE indicator SET unit='mm' WHERE code IN ('rainsum'); - UPDATE indicator SET unit='j' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1'); - UPDATE indicator SET unit='°C' WHERE code IN ('maxt', 'meant', 'mint'); - UPDATE indicator SET aggregationtype='MAX' WHERE code IN ('frostdaystmin', 'hdaystmax', 'hdaystmax1', 'rainsum'); - UPDATE indicator SET aggregationtype='AVG' WHERE code IN ('maxt', 'meant', 'mint'); - ALTER TABLE "indicator" ALTER COLUMN aggregationtype SET NOT NULL; - --- #8 - UPDATE indicator SET colorsequencename='TemperatureReversed' WHERE code IN ('mint', 'meant', 'maxt'); - RETURN true; -END -$BODY$ -language plpgsql; - --- --- 31 --- -CREATE OR REPLACE FUNCTION upgrade20231215() RETURNS boolean AS $BODY$ -BEGIN - INSERT INTO department (id, "name", region) VALUES(75, '75 - Paris', 75); - RETURN true; -END -$BODY$ -language plpgsql; - -- -- 47 -- @@ -232,8 +173,8 @@ language plpgsql; CREATE OR REPLACE FUNCTION upgrade20240513() RETURNS boolean AS $BODY$ BEGIN UPDATE dailyvalue AS d - FROM normalvalue AS n ON n.indicator=d.indicator AND n.cell=d.cell AND n.doy=EXTRACT(DOY FROM d.date) - SET d.comparedvalue=COALESCE(d.computedvalue - n."medianvalue", 0); + SET comparedvalue=COALESCE(d.computedvalue - n."medianvalue", 0) + FROM normalvalue AS n WHERE n.indicator=d.indicator AND n.cell=d.cell AND n.doy=EXTRACT(DOY FROM d.date); RETURN true; END; $BODY$ diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java index 4dcdfe4..4032e30 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java @@ -380,21 +380,6 @@ implements LayoutPresenter.View, LoadingHandler { return layout.isRightPanelVisible(); } - private void onChoiceChange() { - if (choice.isValid()) { - getPresenter().onChoiceChange(choice); - } - } - - private void onComparisonChange(final boolean newValue) { - choice.setComparison(newValue); - onChoiceChange(); - } - - private void onIndicatorChange(final String newValue) { - choice.setIndicator(newValue); - onChoiceChange(); - } @Override public void onLoading(final LoadingEvent event) { GWT.log("LayoutView.onLoading() " + event); @@ -418,37 +403,7 @@ implements LayoutPresenter.View, LoadingHandler { } GWT.log("LayoutView.onLoading() done"); } - private void onPeriodChange(final String newValue) { - choice.setPeriod(newValue); - choice.setIndicator(null); - - // fill indicators - List<IndicatorDTO> list = null; - for (final PeriodDTO p : this.periods) { - if (p.getCode().equals(newValue)) { - list = p.getIndicators(); - break; - } - } - if (list == null) { - return; - } - DomGlobal.console.info("Indicators : " + list); - new HTMLSelectElementBuilder<IndicatorDTO>() // - .setSelect(indicatorSelect) // - .setTextFunction(IndicatorDTO::getDescription) // - .setValueFunction(IndicatorDTO::getCode) // - .removeOptions() // - .addOptions(list) // - .build(); - // select "meant" - if (list.stream().map(IndicatorDTO::getCode).anyMatch(DEFAULT_INDICATOR::equals)) { - indicatorSelect.element().value = DEFAULT_INDICATOR; - onIndicatorChange(DEFAULT_INDICATOR); - } else { - onChoiceChange(); - } - } + /** * To display an OpenLayers map, a container with a fixed height CSS property is * needed. diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java index c843f96..6b9e2e3 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java @@ -11,7 +11,7 @@ import fr.agrometinfo.www.server.exception.AgroMetInfoException; import fr.agrometinfo.www.server.model.DailyVisit; import fr.agrometinfo.www.server.service.CacheService; import fr.agrometinfo.www.server.service.MailService; -import fr.agrometinfo.www.server.service.MailService.Mail; +import fr.agrometinfo.www.server.service.MailServiceImpl.Mail; import fr.agrometinfo.www.server.util.AppVersion; import fr.agrometinfo.www.server.util.ST; import fr.agrometinfo.www.server.util.ST.Key; -- GitLab From 99cc708d5de214e8939a01b9710b5b19f544df3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Wed, 12 Jun 2024 09:52:00 +0200 Subject: [PATCH 29/30] =?UTF-8?q?correction=20texte=20et=20modification=20?= =?UTF-8?q?nom=20m=C3=A9thode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fr/agrometinfo/www/client/i18n/AppConstants_fr.properties | 2 +- .../java/fr/agrometinfo/www/server/rs/SurveyFormResource.java | 2 +- .../java/fr/agrometinfo/www/server/service/MailService.java | 2 +- .../java/fr/agrometinfo/www/server/service/MailServiceImpl.java | 2 +- .../fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties index fc13d99..611ec51 100644 --- a/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties +++ b/www-client/src/main/resources/fr/agrometinfo/www/client/i18n/AppConstants_fr.properties @@ -52,7 +52,7 @@ surveyFormTitle = Formulaire d'enquête surveyFormDescription = Bienvenu.e.s à la nouvelle version d'AgroMetInfo !<br/>Afin de nous aider à la faire évoluer et l'adapter le plus possible à vos besoins, <b>merci de renseigner</b> la petite enquête çi dessous (cela prendra 2 minutes maximum). L'ensemble des informations est anonyme, mais nous aidera à mieux comprendre l'utilisation de l'application. N'hésitez pas à <b>nous laisser votre adresse courriel</b> pour vous tenir informés de toutes les évolutions dans les mois et années à venir.<br/><br/>L'équipe AgroMetInfo. surveyFromEmailDescription = Votre adresse courriel (facultatif) : surveyFormOtherTextCheckbox = Autre, à préciser -surveyFormOtherTextTooltip = Vous devez cliquer sur la case à cocher çi dessus pour activer ce champ de saisie. +surveyFormOtherTextTooltip = Vous devez cliquer sur la case à cocher ci-dessus pour activer ce champ de saisie. surveyFormSuccess = Vos réponses au formulaire d'enquête ont bien été enregistrées. surveyFormFail = Vos réponses au formulaire n'ont pas pu être enregistrées, mais vous pouvez tout de même utiliser AgroMetInfo. toggleRightPanel = Afficher / masquer le panneau de droite diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java index 1aec97d..9ac3ddc 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/SurveyFormResource.java @@ -174,7 +174,7 @@ public class SurveyFormResource implements SurveyFormService { } // once everything is inserted, send an email to support - this.mailService.sendLoginFilled(data); + this.mailService.sendSurveyFilled(data); return "0"; } } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java index a472586..e85fe40 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailService.java @@ -19,5 +19,5 @@ public interface MailService { * Send mail when user fill login form, with questions and responses. * @param data */ - void sendLoginFilled(SurveyResponseDTO data); + void sendSurveyFilled(SurveyResponseDTO data); } diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java index 4f614ef..a6c2c42 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/service/MailServiceImpl.java @@ -329,7 +329,7 @@ public class MailServiceImpl implements MailService { * Send an e-mail when user filled survey form. * @param data data of survey */ - public void sendLoginFilled(final SurveyResponseDTO data) { + public void sendSurveyFilled(final SurveyResponseDTO data) { final Mail mail = createContentFromData(data); mail.setSubject("Un utilisateur a rempli le formulaire d'enquête"); mail.setFromAddress(configuration.get(ConfigurationKey.APP_EMAIL)); diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java index 58c0c84..6c3a7f4 100644 --- a/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java +++ b/www-server/src/test/java/fr/agrometinfo/www/server/rs/SurveyFormResourceTest.java @@ -68,7 +68,7 @@ public class SurveyFormResourceTest extends JerseyTest { @Getter private Mail mail = null; @Override - public void sendLoginFilled(SurveyResponseDTO data) { + public void sendSurveyFilled(SurveyResponseDTO data) { this.mail = MailServiceImpl.createContentFromData(data); } -- GitLab From 49daa6ec34d8d127b89511c18bf71ce37aadac87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DECOME=20J=C3=A9r=C3=A9mie?= <jeremie.decome@inrae.fr> Date: Wed, 12 Jun 2024 10:32:49 +0200 Subject: [PATCH 30/30] corrections checkstyle --- .../java/fr/agrometinfo/www/client/i18n/AppConstants.java | 4 ++-- .../main/java/fr/agrometinfo/www/client/view/LayoutView.java | 4 ---- .../java/fr/agrometinfo/www/server/rs/ApplicationConfig.java | 3 ++- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java index 8d5c483..6a0dee6 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/i18n/AppConstants.java @@ -334,7 +334,7 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo String welcomeBody(); /** - * @return + * @return translation */ @DefaultStringValue("Welcome to the new version of AgroMetInfo !<br/>" + "To help us improve the application and make it as responsive as possible to your needs, " @@ -358,7 +358,7 @@ public interface AppConstants extends com.google.gwt.i18n.client.ConstantsWithLo String welcomeTitle(); /** - * @return + * @return translation */ @DefaultStringValue("Other") String surveyFormOtherTextCheckbox(); diff --git a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java index 4032e30..7380db7 100644 --- a/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java +++ b/www-client/src/main/java/fr/agrometinfo/www/client/view/LayoutView.java @@ -6,7 +6,6 @@ import static org.jboss.elemento.Elements.img; import static org.jboss.elemento.Elements.li; import java.util.List; -import java.util.StringJoiner; import org.dominokit.domino.ui.grid.flex.FlexItem; import org.dominokit.domino.ui.icons.Icons; @@ -16,9 +15,6 @@ import org.dominokit.domino.ui.loaders.Loader; import org.dominokit.domino.ui.loaders.LoaderEffect; import org.dominokit.domino.ui.menu.Menu; import org.dominokit.domino.ui.menu.MenuItem; -import org.dominokit.domino.ui.notifications.Notification; -import org.dominokit.domino.ui.popover.PopupPosition; -import org.dominokit.domino.ui.popover.Tooltip; import org.dominokit.domino.ui.style.Styles; import org.dominokit.domino.ui.utils.DominoElement; import org.dominokit.domino.ui.utils.DominoUIConfig; diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java index de1362f..b6ff6d4 100644 --- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java +++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationConfig.java @@ -43,7 +43,8 @@ public class ApplicationConfig extends Application { // Jackson configuration JacksonConfig.class, // JAX-RS resources - ApplicationResource.class, GeometryResource.class, IndicatorResource.class, SurveyFormResource.class, UserResource.class, + ApplicationResource.class, GeometryResource.class, IndicatorResource.class, + SurveyFormResource.class, UserResource.class, // POJO // Dependencies of resources LogFilter.class -- GitLab