This is an automated email from the git hooks/post-receive script. New commit to branch feature/2264 in repository wao. See http://git.codelutin.com/wao.git commit 9e55adbaee72973770f08c5a2776ee0e5d9a3d3f Author: Brendan Le Ny <bleny@codelutin.com> Date: Fri Dec 26 16:33:20 2014 +0100 Ajout d'une règle de validation pour le nombre d'individus échantilonnés --- .../wao/services/service/ContactsService.java | 17 ++++- .../service/IllegalSampleSizeException.java | 10 +++ .../service/MissingSampleSizeException.java | 10 +++ .../resources/i18n/wao-services_en_GB.properties | 2 + .../resources/i18n/wao-services_fr_FR.properties | 2 + .../ifremer/wao/web/action/EditContactAction.java | 30 ++------- .../wao/web/action/ValidateContactJsonAction.java | 77 ++++++++-------------- .../webapp/WEB-INF/content/edit-contact-input.jsp | 2 + 8 files changed, 77 insertions(+), 73 deletions(-) diff --git a/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactsService.java b/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactsService.java index cefdd93..5e0a05e 100644 --- a/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactsService.java +++ b/wao-services/src/main/java/fr/ifremer/wao/services/service/ContactsService.java @@ -528,6 +528,12 @@ public class ContactsService extends WaoServiceSupport { } catch (IllegalAcceptationException e) { String message = l(l, "wao.import.contact.failure.illegalAcceptation", lineNumber); throw new ImportErrorException(message); + } catch (MissingSampleSizeException e) { + String message = l(l, "wao.import.contact.failure.missingSampleSize", lineNumber); + throw new ImportErrorException(message); + } catch (IllegalSampleSizeException e) { + String message = l(l, "wao.import.contact.failure.illegalSampleSize", lineNumber); + throw new ImportErrorException(message); } save0(updateContactCommand); @@ -596,7 +602,9 @@ public class ContactsService extends WaoServiceSupport { MissingContactDataReliabilityException, MissingContactCommentAdminException, MissingContactTerrestrialLocationException, - IllegalAcceptationException { + IllegalAcceptationException, + MissingSampleSizeException, + IllegalSampleSizeException { // Check if contact can be updated boolean canUpdateContact = authenticatedWaoUser.isAuthorizedToEditContact(updateContactCommand.getContact()) @@ -640,6 +648,13 @@ public class ContactsService extends WaoServiceSupport { if (contact.getObsProgram().isObsVente() && contact.getTerrestrialLocation() == null) { throw new MissingContactTerrestrialLocationException(contact); } + if (contact.getObsProgram().isSclerochronology() && contact.getSampleSize() == null) { + throw new MissingSampleSizeException(contact); + } + } + + if (contact.getSampleSize() != null && contact.getSampleSize() <= 0) { + throw new IllegalSampleSizeException(contact); } if (BooleanUtils.isTrue(contact.getValidationCompany())) { diff --git a/wao-services/src/main/java/fr/ifremer/wao/services/service/IllegalSampleSizeException.java b/wao-services/src/main/java/fr/ifremer/wao/services/service/IllegalSampleSizeException.java new file mode 100644 index 0000000..59ba3ff --- /dev/null +++ b/wao-services/src/main/java/fr/ifremer/wao/services/service/IllegalSampleSizeException.java @@ -0,0 +1,10 @@ +package fr.ifremer.wao.services.service; + +import fr.ifremer.wao.entity.Contact; + +public class IllegalSampleSizeException extends ContactValidationException { + + public IllegalSampleSizeException(Contact contact) { + super(contact); + } +} diff --git a/wao-services/src/main/java/fr/ifremer/wao/services/service/MissingSampleSizeException.java b/wao-services/src/main/java/fr/ifremer/wao/services/service/MissingSampleSizeException.java new file mode 100644 index 0000000..fcbd2ca --- /dev/null +++ b/wao-services/src/main/java/fr/ifremer/wao/services/service/MissingSampleSizeException.java @@ -0,0 +1,10 @@ +package fr.ifremer.wao.services.service; + +import fr.ifremer.wao.entity.Contact; + +public class MissingSampleSizeException extends ContactValidationException { + + public MissingSampleSizeException(Contact contact) { + super(contact); + } +} diff --git a/wao-services/src/main/resources/i18n/wao-services_en_GB.properties b/wao-services/src/main/resources/i18n/wao-services_en_GB.properties index 47dcf3e..b5eb341 100644 --- a/wao-services/src/main/resources/i18n/wao-services_en_GB.properties +++ b/wao-services/src/main/resources/i18n/wao-services_en_GB.properties @@ -39,6 +39,7 @@ wao.import.contact.failure.dataInputDateBeforeToday=Data input date must be befo wao.import.contact.failure.districtMissing=You need to precise the boat district wao.import.contact.failure.duplicatedMainObserverInSecondaryObservers=Main observer can not be also a secondary observer wao.import.contact.failure.illegalAcceptation=Contact must be accepted by company before being accepted by program +wao.import.contact.failure.illegalSampleSize=The number of individuals must be positive wao.import.contact.failure.invalidObservationBeginDate=La date de début de la marée doit correspondre à un mois valide (non vide) de la ligne wao.import.contact.failure.locationTypeMissing=The type of the location must be filled wao.import.contact.failure.mismatchCompanyForObserver=Observer %s is not member of %s @@ -57,6 +58,7 @@ wao.import.contact.failure.missingObservationEndDate=Observation end date must b wao.import.contact.failure.missingObservedDataControl=You must provide a value for observed data control wao.import.contact.failure.missingObserver=There can't be no observer for state '%s' wao.import.contact.failure.missingRestitution=You must provide the restitution forward date +wao.import.contact.failure.missingSampleSize=You must provide de number of individuals wao.import.contact.failure.missingTerrestrialLocation=You must provide the terrestrial location wao.import.contact.failure.not.updatable=Insufficient credentials to update contact wao.import.contact.failure.observationEndDateAfterToday=La date de fin de la marée ne peut pas être postérieure à la date du jour diff --git a/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties b/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties index a89b1dc..e6c221d 100644 --- a/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties +++ b/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties @@ -37,6 +37,7 @@ wao.import.contact.failure.dataInputDateBeforeObservationEndDate=La date de sais wao.import.contact.failure.districtMissing=Il faut préciser le code d'un quartier maritime wao.import.contact.failure.duplicatedMainObserverInSecondaryObservers=L'utilisateur référant ne doit pas se trouver aussi parmi les observateurs secondaires wao.import.contact.failure.illegalAcceptation=Le contact doit être accepté par la société avant d'être accepté par le programme +wao.import.contact.failure.illegalSampleSize=Ligne %s \: Le nombre d'individus échantillonnés doit être strictement positif wao.import.contact.failure.invalidObservationBeginDate=Ligne %s \: La date de début de la marée doit correspondre à un mois valide (non vide) de la ligne wao.import.contact.failure.locationTypeMissing=Le type du lieu doit être renseigné wao.import.contact.failure.mismatchCompanyForObserver=Ligne %s \: L'observateur %s n'est pas membre de %s @@ -55,6 +56,7 @@ wao.import.contact.failure.missingObservationEndDate=Ligne %s \: La date de fin wao.import.contact.failure.missingObservedDataControl=Ligne %s \: Il faut préciser une valeur pour le contrôle des données observées wao.import.contact.failure.missingObserver=Ligne %s \: Il ne peut y avoir aucun observateur pour l'état '%s' wao.import.contact.failure.missingRestitution=Ligne %s \: Il faut préciser une date de transmission de la restitution de la donnée avant de valider +wao.import.contact.failure.missingSampleSize=Ligne %s \: Il faut préciser le nombre d'individus échantillonnés wao.import.contact.failure.missingTerrestrialLocation=Ligne %s \: Il faut préciser le lieu terrestre wao.import.contact.failure.not.updatable=Ligne %s \: Vous n'avez pas les droits suffisants pour modifier le contact wao.import.contact.failure.observationEndDateAfterToday=Ligne %s \: La date de fin de la marée doit être antérieure à la date du jour diff --git a/wao-web/src/main/java/fr/ifremer/wao/web/action/EditContactAction.java b/wao-web/src/main/java/fr/ifremer/wao/web/action/EditContactAction.java index 5ce9b9d..5be4b0e 100644 --- a/wao-web/src/main/java/fr/ifremer/wao/web/action/EditContactAction.java +++ b/wao-web/src/main/java/fr/ifremer/wao/web/action/EditContactAction.java @@ -45,6 +45,7 @@ import fr.ifremer.wao.services.service.ContactWithObservedDataControlToCorrectio import fr.ifremer.wao.services.service.ContactsService; import fr.ifremer.wao.services.service.DuplicatedContactMainObserverInSecondaryObserversException; import fr.ifremer.wao.services.service.IllegalAcceptationException; +import fr.ifremer.wao.services.service.IllegalSampleSizeException; import fr.ifremer.wao.services.service.InvalidContactObservationBeginDateException; import fr.ifremer.wao.services.service.MismatchContactMainObserverCompanyException; import fr.ifremer.wao.services.service.MismatchContactSecondaryObserverCompanyException; @@ -60,6 +61,7 @@ import fr.ifremer.wao.services.service.MissingContactObservedDataControlExceptio import fr.ifremer.wao.services.service.MissingContactRestitutionException; import fr.ifremer.wao.services.service.MissingContactStateMotifException; import fr.ifremer.wao.services.service.MissingContactTerrestrialLocationException; +import fr.ifremer.wao.services.service.MissingSampleSizeException; import fr.ifremer.wao.services.service.UnknownContactIdException; import fr.ifremer.wao.services.service.UnwantedContactContactStateMotifException; import fr.ifremer.wao.services.service.UpdateContactCommand; @@ -254,86 +256,66 @@ public class EditContactAction extends WaoJspActionSupport implements Preparable service.validate(authenticatedWaoUser, updateContactCommand); } catch (ContactNotUpdatableException e) { session.addErrorMessages(t("wao.ui.contacts.validation.failure.not.updatable")); - } catch (UnwantedContactContactStateMotifException e) { addFieldError("updateContactCommand.contact.contactStateMotif", t("wao.ui.form.Contact.error.unwantedContactStateMotif")); - } catch (MissingContactObservationEndDateException e) { String state = WaoUtils.l(getLocale(), e.getContact().getContactState().toI18Able(obsProgram)); addFieldError("updateContactCommand.contact.observationEndDate", t("wao.ui.form.Contact.error.missingObservationEndDate", state)); - } catch (ContactDataInputDateBeforeObservationEndDateException e) { addFieldError("updateContactCommand.contact.dataInputDate", t("wao.ui.form.Contact.error.dataInputDateBeforeObservationEndDate")); - } catch (InvalidContactObservationBeginDateException e) { addFieldError("updateContactCommand.contact.observationBeginDate", t("wao.ui.form.Contact.error.invalidObservationBeginDate")); - } catch (MissingContactRestitutionException e) { addFieldError("updateContactCommand.contact.restitution", t("wao.ui.form.Contact.error.missingRestitution")); - } catch (ContactDataInputDateAfterTodayException e) { addFieldError("updateContactCommand.contact.dataInputDate", t("wao.ui.form.Contact.error.dataInputDateAfterToday")); - } catch (MissingContactCommentException e) { String state = WaoUtils.l(getLocale(), e.getContact().getContactState().toI18Able(obsProgram)); addFieldError("updateContactCommand.contact.comment", t("wao.ui.form.Contact.error.missingComment", state)); - } catch (MismatchContactMainObserverCompanyException e) { String organisationName = e.getOrganisation().getName(); String observerLogin = e.getObserver().getLogin(); addFieldError("updateContactCommand.contact.mainObserver", t("wao.ui.form.Contact.error.mismatchCompanyForObserver", observerLogin, organisationName)); - } catch (ContactRestitutionDateBeforeDataInputDateException e) { addFieldError("updateContactCommand.contact.restitution", t("wao.ui.form.Contact.error.transmissionDateBeforeDataInputDate")); - } catch (ContactObservationEndDateBeforeBeginDateException e) { addFieldError("updateContactCommand.contact.observationEndDate", t("wao.ui.form.Contact.error.observationEndDateBeforeBeginDate")); - } catch (DuplicatedContactMainObserverInSecondaryObserversException e) { addFieldError("updateContactCommand.contact.secondaryObservers", t("wao.ui.form.Contact.error.duplicatedMainObserverInSecondaryObservers")); - } catch (MissingContactDataReliabilityException e) { addFieldError("updateContactCommand.contact.dataReliability", t("wao.ui.form.Contact.error.missingDataReliability")); - } catch (MismatchContactSecondaryObserverCompanyException e) { String organisationName = e.getOrganisation().getName(); String observerLogin = e.getObserver().getLogin(); addFieldError("updateContactCommand.contact.secondaryObservers", t("wao.ui.form.Contact.error.mismatchCompanyForObserver", observerLogin, organisationName)); - } catch (MissingContactObservedDataControlException e) { addFieldError("updateContactCommand.contact.observedDataControl", t("wao.ui.form.Contact.error.missingObservedDataControl")); - } catch (ContactWithObservedDataControlToCorrectionAskedException e) { addFieldError("updateContactCommand.contact.observedDataControl", t("wao.ui.form.Contact.error.observedDataControlToCorrectionAsked")); - } catch (MissingContactStateMotifException e) { addFieldError("updateContactCommand.contactStateMotifId", t("wao.ui.form.Contact.error.missingContactStateMotif")); - } catch (MissingContactDataInputDateException e) { addFieldError("updateContactCommand.contact.dataInputDate", t("wao.ui.form.Contact.error.missingDataInputDate")); - } catch (MissingContactMainObserverException e) { addFieldError("updateContactCommand.contact.mainObserver", t("wao.ui.form.Contact.error.missingMainObserver")); - } catch (MissingContactCommentAdminException e) { String dataReliability = WaoUtils.l(getLocale(), e.getContact().getDataReliability()); addFieldError("updateContactCommand.contact.commentAdmin", t("wao.ui.form.Contact.error.missingCommentAdmin", dataReliability)); - } catch (ContactObservationEndDateAfterTodayException e) { addFieldError("updateContactCommand.contact.observationEndDate", t("wao.ui.form.Contact.error.observationEndDateAfterToday")); - } catch (MissingContactObservationBeginDateException e) { String state = WaoUtils.l(getLocale(), e.getContact().getContactState().toI18Able(obsProgram)); addFieldError("updateContactCommand.contact.observationBeginDate", t("wao.ui.form.Contact.error.missingObservationBeginDate", state)); - } catch (MissingContactMammalsInfoException e) { addFieldError("updateContactCommand.contact.mammalsInfo", t("wao.ui.form.Contact.error.missingMammalsInfo")); - } catch (MissingContactTerrestrialLocationException e) { addFieldError("updateContactCommand.terrestrialLocationId", t("wao.ui.form.Contact.error.missingTerrestrialLocation")); - } catch (IllegalAcceptationException e) { throw new IllegalStateException("should never occur", e); + } catch (MissingSampleSizeException e) { + addFieldError("updateContactCommand.contact.sampleSize", t("wao.ui.form.Contact.error.missingSampleSize")); + } catch (IllegalSampleSizeException e) { + addFieldError("updateContactCommand.contact.sampleSize", t("wao.ui.form.Contact.error.illegalSampleSize")); } } diff --git a/wao-web/src/main/java/fr/ifremer/wao/web/action/ValidateContactJsonAction.java b/wao-web/src/main/java/fr/ifremer/wao/web/action/ValidateContactJsonAction.java index bd62216..875acf4 100644 --- a/wao-web/src/main/java/fr/ifremer/wao/web/action/ValidateContactJsonAction.java +++ b/wao-web/src/main/java/fr/ifremer/wao/web/action/ValidateContactJsonAction.java @@ -38,6 +38,7 @@ import fr.ifremer.wao.services.service.ContactWithObservedDataControlToCorrectio import fr.ifremer.wao.services.service.ContactsService; import fr.ifremer.wao.services.service.DuplicatedContactMainObserverInSecondaryObserversException; import fr.ifremer.wao.services.service.IllegalAcceptationException; +import fr.ifremer.wao.services.service.IllegalSampleSizeException; import fr.ifremer.wao.services.service.InvalidContactObservationBeginDateException; import fr.ifremer.wao.services.service.MismatchContactMainObserverCompanyException; import fr.ifremer.wao.services.service.MismatchContactSecondaryObserverCompanyException; @@ -53,6 +54,7 @@ import fr.ifremer.wao.services.service.MissingContactObservedDataControlExceptio import fr.ifremer.wao.services.service.MissingContactRestitutionException; import fr.ifremer.wao.services.service.MissingContactStateMotifException; import fr.ifremer.wao.services.service.MissingContactTerrestrialLocationException; +import fr.ifremer.wao.services.service.MissingSampleSizeException; import fr.ifremer.wao.services.service.UnknownContactIdException; import fr.ifremer.wao.services.service.UnwantedContactContactStateMotifException; import fr.ifremer.wao.services.service.UpdateContactCommand; @@ -171,87 +173,66 @@ public class ValidateContactJsonAction extends WaoJsonActionSupport implements P service.validate(authenticatedWaoUser, updateContactCommand); } catch (ContactNotUpdatableException e) { session.addErrorMessages(t("wao.ui.contacts.validation.failure.not.updatable")); - } catch (UnwantedContactContactStateMotifException e) { - errorMessage = t("wao.ui.form.Contact.error.unwantedContactStateMotif"); - + errorMessage = t("wao.ui.form.Contact.error.unwantedContactStateMotif"); } catch (MissingContactObservationEndDateException e) { String state = WaoUtils.l(getLocale(), e.getContact().getContactState().toI18Able(obsProgram)); - errorMessage = t("wao.ui.form.Contact.error.missingObservationEndDate", state); - + errorMessage = t("wao.ui.form.Contact.error.missingObservationEndDate", state); } catch (ContactDataInputDateBeforeObservationEndDateException e) { - errorMessage = t("wao.ui.form.Contact.error.dataInputDateBeforeObservationEndDate"); - + errorMessage = t("wao.ui.form.Contact.error.dataInputDateBeforeObservationEndDate"); } catch (InvalidContactObservationBeginDateException e) { - errorMessage = t("wao.ui.form.Contact.error.invalidObservationBeginDate"); - + errorMessage = t("wao.ui.form.Contact.error.invalidObservationBeginDate"); } catch (MissingContactRestitutionException e) { - errorMessage = t("wao.ui.form.Contact.error.missingRestitution"); - + errorMessage = t("wao.ui.form.Contact.error.missingRestitution"); } catch (ContactDataInputDateAfterTodayException e) { - errorMessage = t("wao.ui.form.Contact.error.dataInputDateAfterToday"); - + errorMessage = t("wao.ui.form.Contact.error.dataInputDateAfterToday"); } catch (MissingContactCommentException e) { String state = WaoUtils.l(getLocale(), e.getContact().getContactState().toI18Able(obsProgram)); - errorMessage = t("wao.ui.form.Contact.error.missingComment", state); - + errorMessage = t("wao.ui.form.Contact.error.missingComment", state); } catch (MismatchContactMainObserverCompanyException e) { String companyName = e.getOrganisation().getName(); String observerLogin = e.getObserver().getLogin(); - errorMessage = t("wao.ui.form.Contact.error.mismatchCompanyForObserver", observerLogin, companyName); - + errorMessage = t("wao.ui.form.Contact.error.mismatchCompanyForObserver", observerLogin, companyName); } catch (ContactRestitutionDateBeforeDataInputDateException e) { - errorMessage = t("wao.ui.form.Contact.error.transmissionDateBeforeDataInputDate"); - + errorMessage = t("wao.ui.form.Contact.error.transmissionDateBeforeDataInputDate"); } catch (ContactObservationEndDateBeforeBeginDateException e) { - errorMessage = t("wao.ui.form.Contact.error.observationEndDateBeforeBeginDate"); - + errorMessage = t("wao.ui.form.Contact.error.observationEndDateBeforeBeginDate"); } catch (DuplicatedContactMainObserverInSecondaryObserversException e) { - errorMessage = t("wao.ui.form.Contact.error.duplicatedMainObserverInSecondaryObservers"); - + errorMessage = t("wao.ui.form.Contact.error.duplicatedMainObserverInSecondaryObservers"); } catch (MissingContactDataReliabilityException e) { - errorMessage = t("wao.ui.form.Contact.error.missingDataReliability"); - + errorMessage = t("wao.ui.form.Contact.error.missingDataReliability"); } catch (MismatchContactSecondaryObserverCompanyException e) { String companyName = e.getOrganisation().getName(); String observerLogin = e.getObserver().getLogin(); - errorMessage = t("wao.ui.form.Contact.error.mismatchCompanyForObserver", observerLogin, companyName); - + errorMessage = t("wao.ui.form.Contact.error.mismatchCompanyForObserver", observerLogin, companyName); } catch (MissingContactObservedDataControlException e) { - errorMessage = t("wao.ui.form.Contact.error.missingObservedDataControl"); - + errorMessage = t("wao.ui.form.Contact.error.missingObservedDataControl"); } catch (ContactWithObservedDataControlToCorrectionAskedException e) { errorMessage = t("wao.ui.form.Contact.error.observedDataControlToCorrectionAsked"); - } catch (MissingContactStateMotifException e) { - errorMessage = t("wao.ui.form.Contact.error.missingContactStateMotif"); - + errorMessage = t("wao.ui.form.Contact.error.missingContactStateMotif"); } catch (MissingContactDataInputDateException e) { - errorMessage = t("wao.ui.form.Contact.error.missingDataInputDate"); - + errorMessage = t("wao.ui.form.Contact.error.missingDataInputDate"); } catch (MissingContactMainObserverException e) { - errorMessage = t("wao.ui.form.Contact.error.missingMainObserver"); - + errorMessage = t("wao.ui.form.Contact.error.missingMainObserver"); } catch (MissingContactCommentAdminException e) { String dataReliability = WaoUtils.l(getLocale(), e.getContact().getDataReliability()); - errorMessage = t("wao.ui.form.Contact.error.missingCommentAdmin", dataReliability); - + errorMessage = t("wao.ui.form.Contact.error.missingCommentAdmin", dataReliability); } catch (ContactObservationEndDateAfterTodayException e) { - errorMessage = t("wao.ui.form.Contact.error.observationEndDateAfterToday"); - + errorMessage = t("wao.ui.form.Contact.error.observationEndDateAfterToday"); } catch (MissingContactObservationBeginDateException e) { String state = WaoUtils.l(getLocale(), e.getContact().getContactState().toI18Able(obsProgram)); - errorMessage = t("wao.ui.form.Contact.error.missingObservationBeginDate", state); - + errorMessage = t("wao.ui.form.Contact.error.missingObservationBeginDate", state); } catch (MissingContactTerrestrialLocationException e) { - errorMessage = t("wao.ui.form.Contact.error.missingContactTerrestrialLocation"); - + errorMessage = t("wao.ui.form.Contact.error.missingContactTerrestrialLocation"); } catch (MissingContactMammalsInfoException e) { - errorMessage = t("wao.ui.form.Contact.error.missingContactMammalsInfo"); - + errorMessage = t("wao.ui.form.Contact.error.missingContactMammalsInfo"); } catch (IllegalAcceptationException e) { - errorMessage = t("wao.ui.form.Contact.error.illegalAcceptationException"); - + errorMessage = t("wao.ui.form.Contact.error.illegalAcceptationException"); + } catch (MissingSampleSizeException e) { + errorMessage = t("wao.ui.form.Contact.error.missingSampleSize"); + } catch (IllegalSampleSizeException e) { + errorMessage = t("wao.ui.form.Contact.error.illegalSampleSize"); } if (isSuccessful()) { diff --git a/wao-web/src/main/webapp/WEB-INF/content/edit-contact-input.jsp b/wao-web/src/main/webapp/WEB-INF/content/edit-contact-input.jsp index c4d603c..1793618 100644 --- a/wao-web/src/main/webapp/WEB-INF/content/edit-contact-input.jsp +++ b/wao-web/src/main/webapp/WEB-INF/content/edit-contact-input.jsp @@ -346,6 +346,8 @@ <s:textfield name="updateContactCommand.contact.sampleSize" label="%{getText('wao.ui.field.Contact.sampleSize')}" type="number" + min="1" + step="1" disabled="%{!#editObservationReport}" cssClass="input-small" inputAppend="%{getText('wao.ui.field.Contact.sampleSize.unit')}"/> -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.