This is an automated email from the git hooks/post-receive script. New commit to branch feature/pollen-riot-js in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 5337f63ca66326d246e6ed9d58d9166f11ac69e7 Author: Tony CHEMIT <dev@tchemit.fr> Date: Sun Jan 15 18:48:22 2017 +0100 Add resendValidation backend + use now cookies to manage auth cache --- .../org/chorem/pollen/rest/api/v1/AuthApi.java | 10 +++ .../chorem/pollen/rest/api/v1/PollenUserApi.java | 1 + pollen-rest-api/src/main/resources/mapping | 1 + pollen-rest-api/src/main/webapp/WEB-INF/web.xml | 43 ++++++++++++ .../services/service/NotificationService.java | 11 +++ .../pollen/services/service/PollenUserService.java | 22 +++++- .../pollen/services/service/mail/EmailService.java | 14 ++++ .../service/mail/ResendValidationEmail.java | 78 ++++++++++++++++++++++ .../services/service/security/SecurityService.java | 4 ++ .../resources/email/ResendValidationEmail.mustache | 8 +++ .../email/ResendValidationEmail_fr.mustache | 7 ++ .../i18n/pollen-services_en_GB.properties | 1 + .../i18n/pollen-services_fr_FR.properties | 1 + pollen-ui-riot-js/src/main/web/i18n.json | 14 ++++ pollen-ui-riot-js/src/main/web/js/AuthService.js | 6 +- pollen-ui-riot-js/src/main/web/js/FetchService.js | 4 ++ pollen-ui-riot-js/src/main/web/js/PollForm.js | 3 +- pollen-ui-riot-js/src/main/web/tag/SignCheck.tag | 25 +++---- pollen-ui-riot-js/src/main/web/tag/SignUp.tag | 8 ++- 19 files changed, 238 insertions(+), 23 deletions(-) diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java index 474b408..79f05c1 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/AuthApi.java @@ -32,9 +32,11 @@ import org.chorem.pollen.persistence.entity.SessionToken; import org.chorem.pollen.persistence.entity.SessionTokenImpl; import org.chorem.pollen.rest.api.PollenRestApiRequestContext; import org.chorem.pollen.services.bean.PollenEntityRef; +import org.chorem.pollen.services.service.PollenUserService; import org.chorem.pollen.services.service.security.DefaultPollenSecurityContext; import org.chorem.pollen.services.service.security.MissingAuthenticationException; import org.chorem.pollen.services.service.security.PollenAuthenticationException; +import org.chorem.pollen.services.service.security.PollenInvalidEmailActivationTokenException; import org.chorem.pollen.services.service.security.PollenInvalidSessionTokenException; import org.chorem.pollen.services.service.security.SecurityService; import org.debux.webmotion.server.WebMotionController; @@ -100,4 +102,12 @@ public class AuthApi extends WebMotionController { securityService.lostPassword(login); } + + + public void resendValidation(PollenUserService pollenUserService, String login) { + + pollenUserService.resendValidation(login); + + } + } diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollenUserApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollenUserApi.java index 31790c3..2ae88d8 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollenUserApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollenUserApi.java @@ -28,6 +28,7 @@ import org.chorem.pollen.services.bean.PollenEntityId; import org.chorem.pollen.services.bean.PollenEntityRef; import org.chorem.pollen.services.bean.PollenUserBean; import org.chorem.pollen.services.service.InvalidFormException; +import org.chorem.pollen.services.service.NotificationService; import org.chorem.pollen.services.service.PollenUserService; import org.chorem.pollen.services.service.security.PollenInvalidEmailActivationTokenException; import org.debux.webmotion.server.WebMotionController; diff --git a/pollen-rest-api/src/main/resources/mapping b/pollen-rest-api/src/main/resources/mapping index 7ffb99e..e68db7b 100644 --- a/pollen-rest-api/src/main/resources/mapping +++ b/pollen-rest-api/src/main/resources/mapping @@ -57,6 +57,7 @@ POST,PUT /v1/login AuthApi.login POST,PUT /v1/login2 AuthApi.login2 GET /v1/lostpassword/{login} AuthApi.lostPassword GET /v1/logout AuthApi.logout +GET /v1/resendValidation/{login} AuthApi.resendValidation # ChoiceApi diff --git a/pollen-rest-api/src/main/webapp/WEB-INF/web.xml b/pollen-rest-api/src/main/webapp/WEB-INF/web.xml index 269ec67..45e02fa 100644 --- a/pollen-rest-api/src/main/webapp/WEB-INF/web.xml +++ b/pollen-rest-api/src/main/webapp/WEB-INF/web.xml @@ -73,4 +73,47 @@ <tracking-mode>COOKIE</tracking-mode> </session-config> + + <!-- Exception --> + <error-page> + <exception-type>java.lang.Exception</exception-type> + <location>/error</location> + </error-page> + + <!-- Bad Request --> + <error-page> + <error-code>400</error-code> + <location>/error</location> + </error-page> + + <!-- Unauthorized --> + <error-page> + <error-code>401</error-code> + <location>/error</location> + </error-page> + + <!-- Forbidden --> + <error-page> + <error-code>403</error-code> + <location>/error</location> + </error-page> + + <!-- Not Found --> + <error-page> + <error-code>404</error-code> + <location>/error</location> + </error-page> + + <!-- Request Time-out --> + <error-page> + <error-code>408</error-code> + <location>/error</location> + </error-page> + + <!-- Internal Server Error --> + <error-page> + <error-code>500</error-code> + <location>/error</location> + </error-page> + </web-app> diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java index bc6ed58..a5b7396 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/NotificationService.java @@ -31,6 +31,7 @@ import org.chorem.pollen.services.service.mail.EmailService; import org.chorem.pollen.services.service.mail.LostPasswordEmail; import org.chorem.pollen.services.service.mail.PollClosedEmail; import org.chorem.pollen.services.service.mail.PollCreatedEmail; +import org.chorem.pollen.services.service.mail.ResendValidationEmail; import org.chorem.pollen.services.service.mail.UserAccountCreatedEmail; /** @@ -52,6 +53,16 @@ public class NotificationService extends PollenServiceSupport { } + public void onResendValidation(PollenUser user) { + + EmailService emailService = getEmailService(); + ResendValidationEmail email = emailService.newUserResendValidationEmail(user); + + email.addTo(user.getEmail()); + emailService.send(email); + + } + public void onUserEdited(PollenUser user) { // TODO } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java index feccb7c..422302f 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollenUserService.java @@ -209,8 +209,7 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer } - public void validateUserEmail(String userId, - String token) throws PollenInvalidEmailActivationTokenException { + public void validateUserEmail(String userId, String token) throws PollenInvalidEmailActivationTokenException { checkNotNull(userId); checkNotNull(token); @@ -228,6 +227,23 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer } + public void resendValidation(String email) { + checkNotNull(email); + + PollenUser user = getPollenUserDao().forEmailEquals(email).findUniqueOrNull(); + if (user == null) { + return; + } + + if (user.getEmailActivationToken() == null) { + user.setEmailActivationToken(getSecurityService().generateNewToken()); + commit(); + } + + getNotificationService().onResendValidation(user); + + } + public void createDefaultUsers() throws InvalidFormException { if (getPollenUserDao().count() == 0) { @@ -240,6 +256,7 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer user.setAdministrator(true); user.setEmail("admin@pollen.org"); user.setPassword("admin"); + user.setName("admin"); listUser.add(user); @@ -248,6 +265,7 @@ public class PollenUserService extends PollenServiceSupport implements PollenSer user.setAdministrator(false); user.setEmail("user@pollen.org"); user.setPassword("user"); + user.setName("user"); listUser.add(user); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java index 824b125..b426262 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/EmailService.java @@ -193,6 +193,20 @@ public class EmailService extends PollenServiceSupport { return email; } + public ResendValidationEmail newUserResendValidationEmail(PollenUser user) { + ResendValidationEmail email = new ResendValidationEmail(getLocale()); + email.setUser(user); + email.setPollenUrl(getPollenUIUrlRenderService().getPollenUrl()); + + PollenEntityId<PollenUser> userId = PollenEntityId.newId(PollenUser.class); + userId.setEntityId(user.getTopiaId()); + userId.encode(serviceContext.getTopiaApplicationContext().getTopiaIdFactory()); + + email.setValidateUrl(getPollenUIUrlRenderService().getUserValidateUrl(userId.getReducedId(), user.getEmailActivationToken().getToken())); + + return email; + } + public LostPasswordEmail newLostPasswordEmail(Locale locale, PollenUser user, String password) { LostPasswordEmail email = new LostPasswordEmail(locale); email.setUser(user); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/ResendValidationEmail.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/ResendValidationEmail.java new file mode 100644 index 0000000..97de0fd --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/ResendValidationEmail.java @@ -0,0 +1,78 @@ +package org.chorem.pollen.services.service.mail; + +/* + * #%L + * Pollen :: Service + * %% + * Copyright (C) 2009 - 2017 Code Lutin, Tony Chemit + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +import org.chorem.pollen.persistence.entity.PollenUser; +import org.nuiton.i18n.I18n; + +import java.util.Locale; + +/** + * Created on 4/30/14. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 2.0 + */ +public class ResendValidationEmail extends PollenMail { + + private PollenUser user; + + private String validateUrl; + private String pollenUrl; + + protected ResendValidationEmail(Locale locale) { + super(locale); + } + + @Override + public String getSubject() { + if (user.getName() == null) { + return I18n.l(locale, "pollen.service.mail.ResendValidationEmail.subject", user.getEmail()); + } + return I18n.l(locale, "pollen.service.mail.ResendValidationEmail.subject", user.getName()); + } + + public PollenUser getUser() { + return user; + } + + public void setUser(PollenUser user) { + this.user = user; + } + + public String getValidateUrl() { + return validateUrl; + } + + public void setValidateUrl(String validateUrl) { + this.validateUrl = validateUrl; + } + + public String getPollenUrl() { + return pollenUrl; + } + + public void setPollenUrl(String pollenUrl) { + this.pollenUrl = pollenUrl; + } + +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java index b716e1a..f02929e 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/security/SecurityService.java @@ -330,6 +330,10 @@ public class SecurityService extends PollenServiceSupport { public void checkUserEmailValidation(PollenUser user, String emailToken) throws PollenInvalidEmailActivationTokenException { + if (user.getEmailActivationToken() == null) { + throw new PollenInvalidEmailActivationTokenException(); + } + boolean valid = Objects.equals(user.getEmailActivationToken().getToken(), emailToken); if (!valid) { diff --git a/pollen-services/src/main/resources/email/ResendValidationEmail.mustache b/pollen-services/src/main/resources/email/ResendValidationEmail.mustache new file mode 100644 index 0000000..4e4df8c --- /dev/null +++ b/pollen-services/src/main/resources/email/ResendValidationEmail.mustache @@ -0,0 +1,8 @@ +Welcome {{user.name}}, + + +You had just created an account on the web application Pollen. + +You must validate your email on this url: <a href="{{validateUrl}}">{{vaidateUrl}}</a> + +You can now manage your polls by logging on the <a href="{{pollenUrl}}">Pollen</a> website. \ No newline at end of file diff --git a/pollen-services/src/main/resources/email/ResendValidationEmail_fr.mustache b/pollen-services/src/main/resources/email/ResendValidationEmail_fr.mustache new file mode 100644 index 0000000..f8762cc --- /dev/null +++ b/pollen-services/src/main/resources/email/ResendValidationEmail_fr.mustache @@ -0,0 +1,7 @@ +Bonjour {{user.name}}, + +Vous venez de créer un compte sur l'application en ligne Pollen + +Vous devez valider votre courriel en allant sur cette adresse : <a href="{{validateUrl}}">{{vaidateUrl}}</a> + +Vous pouvez gérer vos sondages en vous connectant sur <a href="{{pollenUrl}}">Pollen</a>. \ No newline at end of file diff --git a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties index a3475c4..05c2853 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_en_GB.properties @@ -100,6 +100,7 @@ pollen.service.mail.PollCreatedEmail.subject=[Pollen] Poll creation (%s) pollen.service.mail.PollVotePeriodEndedEmail.subject=[Pollen] Vote period ended for poll %s pollen.service.mail.PollVotePeriodStartedEmail.subject=[Pollen] Vote period started for poll %s pollen.service.mail.PollVoteReminderEmail.subject=[Pollen] Reminder to vote on poll %s +pollen.service.mail.ResendValidationEmail.subject=[Pollen] Invitation to validate your account %s pollen.service.mail.RestrictedPollInvitationEmail.subject=[Pollen] Invitation to vote on poll %s pollen.service.mail.UserAccountCreatedEmail.subject=[Pollen] Confirmation of account creation %s pollen.service.mail.VoteAddedEmail.subject=[Pollen] A vote was added in poll %s diff --git a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties index 4366d77..ebedd6e 100644 --- a/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties +++ b/pollen-services/src/main/resources/i18n/pollen-services_fr_FR.properties @@ -99,6 +99,7 @@ pollen.service.mail.PollCreatedEmail.subject=[Pollen] Création du sondage %s pollen.service.mail.PollVotePeriodEndedEmail.subject=[Pollen] Période de vote terminée pour le sondage %s pollen.service.mail.PollVotePeriodStartedEmail.subject=[Pollen] Période de vote commencée pour le sondage %s pollen.service.mail.PollVoteReminderEmail.subject=[Pollen] Rappel du vote au sondage %s +pollen.service.mail.ResendValidationEmail.subject=[Pollen] Validation de votre compte %s pollen.service.mail.RestrictedPollInvitationEmail.subject=[Pollen] Invitation au sondage %s pollen.service.mail.UserAccountCreatedEmail.subject=[Pollen] Confirmation de création du compte %s pollen.service.mail.VoteAddedEmail.subject=[Pollen] Un nouveau vote a été ajouté au sondage %s diff --git a/pollen-ui-riot-js/src/main/web/i18n.json b/pollen-ui-riot-js/src/main/web/i18n.json index 8a82321..702e428 100644 --- a/pollen-ui-riot-js/src/main/web/i18n.json +++ b/pollen-ui-riot-js/src/main/web/i18n.json @@ -17,6 +17,13 @@ "resendvalidation_placeholder": "Entrer votre courriel", "resendvalidation_sent": "Un nouveau courriel d'invitation a été envoyé", "resendvalidation_error_emailNotFound": "Le courriel n'a pas été trouvé", + "signcheck_title":"Validation de votre compte", + "signcheck_signin":"Vous connecter", + "signcheck_resendValidation":"Envoyer une nouvelle invitation", + "signcheck_message":"Votre compte doit être validé afin de pouvoir vous connecter.", + "signcheck_validating":"Votre compte est en cour de validation...", + "signcheck_validating_error":"Votre compte n'a pas pu être validé, essayer de renvoyer une invitation.", + "signcheck_validating_success":"Votre compte a été validé. Vous pouvez vous connecter.", "signin_title": "Déjà membre ?", "signin_login": "Email", "signin_login_placeholder": "Entrer l'email", @@ -58,6 +65,13 @@ "signup_resendValidation": "Already member, but account never validated ?", "signup_error": "Could not register account.", "signup_error_email": "This email is already used.", + "signcheck_title":"Validate your account", + "signcheck_signin":"Sign in", + "signcheck_resendValidation":"Send a new invitation", + "signcheck_message":"Your account must be validate before you can connect.", + "signcheck_validating":"Your account is validating...", + "signcheck_validating_error":"Your account could not be validated, try to send a new invitation.", + "signcheck_validating_success":"Your account was validated! You can now sign in. Enjoy!", "createdaccount_title": "Your account was created", "createdaccount_description": "We sent you an email with the account validation process and your authentication data.", "createdaccount_action": "Continue", diff --git a/pollen-ui-riot-js/src/main/web/js/AuthService.js b/pollen-ui-riot-js/src/main/web/js/AuthService.js index c2444c4..683e499 100644 --- a/pollen-ui-riot-js/src/main/web/js/AuthService.js +++ b/pollen-ui-riot-js/src/main/web/js/AuthService.js @@ -6,7 +6,7 @@ let FetchService = require("./FetchService"); class AuthService extends FetchService { signIn(login, password) { - return this.fetch("/v1/login","POST", { + return this.fetch("/v1/login", "POST", { Authorization: "Basic " + btoa(login + ":" + password) }, null).then((auth) => { if (!auth) { @@ -31,7 +31,7 @@ class AuthService extends FetchService { } validateEmail(userId, token) { - return this.post("/v1/users/" + userId, {token: token}); + return this.put("/v1/users/" + userId + "?token=" + token); } newPassword(email) { @@ -39,7 +39,7 @@ class AuthService extends FetchService { } resendValidation(email) { - return this.get("/v1/lostpassword/" + email); + return this.get("/v1/resendValidation/" + email); } } diff --git a/pollen-ui-riot-js/src/main/web/js/FetchService.js b/pollen-ui-riot-js/src/main/web/js/FetchService.js index bb285bf..5225eb1 100644 --- a/pollen-ui-riot-js/src/main/web/js/FetchService.js +++ b/pollen-ui-riot-js/src/main/web/js/FetchService.js @@ -51,6 +51,10 @@ class FetchService { return this.fetch(url, "POST", null, body); } + put(url, body) { + return this.fetch(url, "PUT", null, body); + } + form(url, data) { let formData = null; if (data) { diff --git a/pollen-ui-riot-js/src/main/web/js/PollForm.js b/pollen-ui-riot-js/src/main/web/js/PollForm.js index 54121ae..0613862 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollForm.js +++ b/pollen-ui-riot-js/src/main/web/js/PollForm.js @@ -30,8 +30,7 @@ class PollForm { dateChoices: [] }; if (user) { - //FIXME On doit aussi remonter le nom de l'utilisateur - this.model.name = user.email; + this.model.name = user.name; this.model.email = user.email; } } diff --git a/pollen-ui-riot-js/src/main/web/tag/SignCheck.tag b/pollen-ui-riot-js/src/main/web/tag/SignCheck.tag index b0daf05..1a67725 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignCheck.tag +++ b/pollen-ui-riot-js/src/main/web/tag/SignCheck.tag @@ -1,20 +1,19 @@ let authService = require("../js/AuthService"); let session = require("../js/Session"); let emitter = require("../js/EmitterService"); -let route = require("riot-route"); -<SignCjeck> +<SignCheck> <div class="body-container"> <div class="body-container"> <form class="signcheck" method="post" onsubmit="{signIn}"> <div class="split"> <div class="legend"> - <i class="fa fa-user fa-3x"> </i>{__title__} + <i class="fa fa-user fa-3x"> </i>{__.title} </div> - <div>{__message__}</div> + <div>{__.message}</div> <br/> - <a class="button" href="/signin">{__signin__}</a> - <a class="button" href="/signup/validate">{__resendValidation__}</a> + <a if="{!error}" class="button" href="#signin">{__.signin}</a> + <a if="{error}" class="button" href="#signup/validate">{__.resendValidation}</a> <div class="{error ? 'error' : 'info'}">{message}</div> </div> @@ -26,16 +25,16 @@ let route = require("riot-route"); <script> this.installBundle(session.locale, "signcheck", emitter); - this.message = "Votre compte est en cours de validation..."; + this.message = this.__.validating; this.error = false; - authService.validateEmail(opts.id, opts.permission) + authService.validateEmail(opts.id, opts.token) .then(() => { - this.message = "Votre compte a été validé"; + this.message = this.__.validating_success; this.update(); }) .catch(() => { this.error = true; - this.message = "Votre compte n'a pas pu être validé"; + this.message = this.__.validating_error; this.update(); }); @@ -44,10 +43,6 @@ let route = require("riot-route"); <style scoped> - .wide { - width: 320px; - } - .button { margin: 5px 0; } @@ -94,4 +89,4 @@ let route = require("riot-route"); } </style> -</SignCjeck> +</SignCheck> diff --git a/pollen-ui-riot-js/src/main/web/tag/SignUp.tag b/pollen-ui-riot-js/src/main/web/tag/SignUp.tag index c704082..1dfa81c 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignUp.tag +++ b/pollen-ui-riot-js/src/main/web/tag/SignUp.tag @@ -29,11 +29,17 @@ require("./popup/AccountCreated.tag"); <script> + this.on('mount', () => { + if (this.validate) { + this.refs.resendValidation.open(); + } + }); + this.installBundle(session.locale, "signup", emitter); this.errors = ""; this.resendValidation = () => { - this.refs.resendValidation.open(); + this.validate = true; }; this.signUp = (e) => { -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.