This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 13b49204f8fff651898bbf8530d40fc6838c7510 Author: Sylvain Bavencoff <bavencoff@codelutin.com> Date: Wed Nov 8 11:02:10 2017 +0100 Afficher la liste des emails non délivré pour l'administrateur du sondage (refs #168). ajouter une attente entre chaque envois de mail. --- .../db/migration/h2/V3_1_0_9__add_invalid_mail.sql | 3 ++ .../postgresql/V3_1_0_9__add_invalid_mail.sql | 3 ++ pollen-persistence/src/main/xmi/pollen.properties | 2 +- pollen-persistence/src/main/xmi/pollen.zargo | Bin 30597 -> 30672 bytes .../org/chorem/pollen/rest/api/v1/PollApi.java | 10 +++++ pollen-services/src/main/config/PollenServices.ini | 6 +++ .../org/chorem/pollen/services/bean/PollBean.java | 10 +++++ .../pollen/services/bean/VoterListMemberBean.java | 10 +++++ .../pollen/services/job/AbstractPollenJob.java | 9 ++++ .../services/service/NotificationService.java | 6 +-- .../pollen/services/service/PollService.java | 27 +++++++++++ .../pollen/services/service/VoterListService.java | 1 + .../pollen/services/service/mail/EmailService.java | 50 +++++++++++++++++---- .../services/service/mail/MailBoxService.java | 20 +++++++++ .../service/mail/PollenInvalidEmailsException.java | 16 +++++++ .../services/service/mail/PollenMailType.java | 7 ++- .../i18n/pollen-services_en_GB.properties | 1 + .../i18n/pollen-services_fr_FR.properties | 1 + pollen-ui-riot-js/src/main/web/i18n/en.json | 3 ++ pollen-ui-riot-js/src/main/web/i18n/fr.json | 3 ++ pollen-ui-riot-js/src/main/web/js/Poll.js | 7 +++ pollen-ui-riot-js/src/main/web/js/PollForm.js | 7 +++ pollen-ui-riot-js/src/main/web/js/PollService.js | 5 +++ .../src/main/web/tag/poll/CheckEmails.tag.html | 45 +++++++++++++++++++ .../src/main/web/tag/poll/EditPoll.tag.html | 2 + .../src/main/web/tag/poll/Poll.tag.html | 3 ++ .../web/tag/voterList/VoterListMemberCard.tag.html | 8 +++- 27 files changed, 248 insertions(+), 17 deletions(-) diff --git a/pollen-persistence/src/main/resources/db/migration/h2/V3_1_0_9__add_invalid_mail.sql b/pollen-persistence/src/main/resources/db/migration/h2/V3_1_0_9__add_invalid_mail.sql new file mode 100644 index 00000000..5e21a2cf --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/h2/V3_1_0_9__add_invalid_mail.sql @@ -0,0 +1,3 @@ +-- add invalid email in PollenPrincipal +alter table pollenprincipal add invalid boolean; +update pollenprincipal set invalid = false; \ No newline at end of file diff --git a/pollen-persistence/src/main/resources/db/migration/postgresql/V3_1_0_9__add_invalid_mail.sql b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_1_0_9__add_invalid_mail.sql new file mode 100644 index 00000000..5e21a2cf --- /dev/null +++ b/pollen-persistence/src/main/resources/db/migration/postgresql/V3_1_0_9__add_invalid_mail.sql @@ -0,0 +1,3 @@ +-- add invalid email in PollenPrincipal +alter table pollenprincipal add invalid boolean; +update pollenprincipal set invalid = false; \ No newline at end of file diff --git a/pollen-persistence/src/main/xmi/pollen.properties b/pollen-persistence/src/main/xmi/pollen.properties index e772d404..b8f11682 100644 --- a/pollen-persistence/src/main/xmi/pollen.properties +++ b/pollen-persistence/src/main/xmi/pollen.properties @@ -18,7 +18,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # #L% ###m -model.tagvalue.version=3.1.0.8 +model.tagvalue.version=3.1.0.9 #model.tagValue.notGenerateToString=true #model.tagValue.constantPrefix=PROPERTY_ #model.tagValue.useEnumerationName=true diff --git a/pollen-persistence/src/main/xmi/pollen.zargo b/pollen-persistence/src/main/xmi/pollen.zargo index 7a92a588..3031d4e4 100644 Binary files a/pollen-persistence/src/main/xmi/pollen.zargo and b/pollen-persistence/src/main/xmi/pollen.zargo differ diff --git a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollApi.java b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollApi.java index e41942e0..8c455cf5 100644 --- a/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollApi.java +++ b/pollen-rest-api/src/main/java/org/chorem/pollen/rest/api/v1/PollApi.java @@ -52,6 +52,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.Date; import java.util.List; +import java.util.Set; /** * TODO @@ -185,6 +186,15 @@ public class PollApi { return Response.ok(feedContent).build(); } + @Path("/polls/{pollId}/invalidEmails") + @GET + public Set<String> getInvalidEmails(@Context PollService pollService, + @PathParam("pollId") PollenEntityId<Poll> pollId) { + + return pollService.getInvalidEmails(pollId.getEntityId()); + + } + @Path("/polls/{pollId}/reports") @POST public void addReport(@Context ReportService reportService, diff --git a/pollen-services/src/main/config/PollenServices.ini b/pollen-services/src/main/config/PollenServices.ini index 5b946125..d084e71a 100644 --- a/pollen-services/src/main/config/PollenServices.ini +++ b/pollen-services/src/main/config/PollenServices.ini @@ -99,6 +99,12 @@ key = pollen.smtp.from type = string defaultValue = "noreply@serveur.com" +[option smtpWait] +description = pollen.configuration.smtpWait +key = pollen.smtp.wait +type = int +defaultValue = 1000 + [option mailBoxHost] description = pollen.configuration.mailBox.host key = pollen.mailBox.host diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollBean.java index b1d2bbaf..4fda8c9d 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/PollBean.java @@ -111,6 +111,8 @@ public class PollBean extends PollenBean<Poll> { protected Set<String> participants; + protected Set<String> invalidEmails; + protected long voteCount; protected long participantCount; @@ -473,4 +475,12 @@ public class PollBean extends PollenBean<Poll> { public void setVoteCountingConfig(VoteCountingConfig voteCountingConfig) { this.voteCountingConfig = voteCountingConfig; } + + public Set<String> getInvalidEmails() { + return invalidEmails; + } + + public void setInvalidEmails(Set<String> invalidEmails) { + this.invalidEmails = invalidEmails; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListMemberBean.java b/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListMemberBean.java index 929f3a16..c354436d 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListMemberBean.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/bean/VoterListMemberBean.java @@ -42,6 +42,8 @@ public class VoterListMemberBean extends PollenBean<VoterListMember> { protected boolean voting; + protected boolean invalidEmail; + public VoterListMemberBean() { super(VoterListMember.class); } @@ -88,4 +90,12 @@ public class VoterListMemberBean extends PollenBean<VoterListMember> { public void setVoting(boolean voting) { this.voting = voting; } + + public boolean isInvalidEmail() { + return invalidEmail; + } + + public void setInvalidEmail(boolean invalidEmail) { + this.invalidEmail = invalidEmail; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/job/AbstractPollenJob.java b/pollen-services/src/main/java/org/chorem/pollen/services/job/AbstractPollenJob.java index a2ba060b..0897dc09 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/job/AbstractPollenJob.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/job/AbstractPollenJob.java @@ -21,6 +21,8 @@ package org.chorem.pollen.services.job; * #L% */ +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.chorem.pollen.persistence.PollenTopiaPersistenceContext; import org.chorem.pollen.services.PollenApplicationContext; import org.chorem.pollen.services.PollenService; @@ -37,6 +39,8 @@ import java.util.Locale; */ public abstract class AbstractPollenJob implements Job { + private static final Log log = LogFactory.getLog(AbstractPollenJob.class); + public static final String APPLICATION_CONTEXT = "applicationContext"; protected PollenApplicationContext applicationContext; @@ -54,6 +58,11 @@ public abstract class AbstractPollenJob implements Job { serviceContext = applicationContext.newServiceContext(persistenceContext, Locale.getDefault()); execute(); + } catch (Exception e) { + if (log.isErrorEnabled()) { + log.error("Exception on Job", e); + } + throw new JobExecutionException(e); } } 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 446c2d01..34976bf9 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 @@ -141,6 +141,7 @@ public class NotificationService extends PollenServiceSupport { UserAccountEmailAddressAddedEmail email = emailService.newUserAccountEmailAddressAddedEmail(user, emailAddress); email.addTo(emailAddress.getEmailAddress()); emailService.send(email); + commit(); } public void onUserEmailValidated(PollenUser user, PollenUserEmailAddress emailAddress) { @@ -219,8 +220,6 @@ public class NotificationService extends PollenServiceSupport { }); } commit(); - - } public void onPollEdited(Poll poll, Set<String> newParticipants) { @@ -437,7 +436,7 @@ public class NotificationService extends PollenServiceSupport { emailService.send(pollReportForAdminEmail); }); commit(); - + } public void onExceedingMaxVoters(Poll poll, int maxVoters) { @@ -446,5 +445,6 @@ public class NotificationService extends PollenServiceSupport { ExceedingMaxVotersEmail email = emailService.newExceedingMaxVotersEmail(poll, maxVoters); email.addTo(poll.getCreator().getEmail()); emailService.send(email); + commit(); } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java index 8afbb635..3e8bfd0a 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/PollService.java @@ -32,6 +32,8 @@ import org.chorem.pollen.persistence.entity.PollType; import org.chorem.pollen.persistence.entity.PollenPrincipal; import org.chorem.pollen.persistence.entity.PollenUser; import org.chorem.pollen.persistence.entity.Polls; +import org.chorem.pollen.persistence.entity.VoterList; +import org.chorem.pollen.persistence.entity.VoterListMember; import org.chorem.pollen.services.bean.ChoiceBean; import org.chorem.pollen.services.bean.PaginationParameterBean; import org.chorem.pollen.services.bean.PaginationResultBean; @@ -703,4 +705,29 @@ public class PollService extends PollenServiceSupport { } + public Set<String> getInvalidEmails(String pollId) { + Set<String> invalidEmails = Sets.newHashSet(); + + if (isPermitted(PermissionVerb.editPoll, pollId)) { + + Poll poll = getPoll0(pollId); + + if (poll.getCreator().isInvalid()) { + invalidEmails.add(poll.getCreator().getEmail()); + } + + if (Polls.isPollRestricted(poll)) { + getVoterListMemberDao() + .forProperties(VoterListMember.PROPERTY_VOTER_LIST + "." + VoterList.PROPERTY_POLL, poll) + .addEquals(VoterListMember.PROPERTY_MEMBER + "." + PollenPrincipal.PROPERTY_INVALID, true) + .findAll() + .stream() + .map(voterListMember -> voterListMember.getMember().getEmail()) + .forEach(invalidEmails::add); + } + + } + + return invalidEmails; + } } diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java index d49e3ed3..accc09d0 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/VoterListService.java @@ -70,6 +70,7 @@ public class VoterListService extends PollenServiceSupport { boolean voting = getVoteDao().forVoterListMemberContains(entity).exists(); bean.setVoting(voting); + bean.setInvalidEmail(entity.getMember().isInvalid()); return bean; } 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 e7ecb372..cbb7f5f9 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 @@ -28,6 +28,7 @@ import com.github.mustachejava.MustacheFactory; import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -55,9 +56,11 @@ import org.chorem.pollen.services.config.PollenServicesConfig; import org.chorem.pollen.services.service.PollenServiceSupport; import org.nuiton.i18n.I18n; +import javax.mail.Address; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Part; +import javax.mail.SendFailedException; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; @@ -72,6 +75,9 @@ import java.util.List; import java.util.Locale; import java.util.Set; import java.util.TimeZone; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.nuiton.i18n.I18n.n; import static org.nuiton.i18n.I18n.t; @@ -336,6 +342,10 @@ public class EmailService extends PollenServiceSupport { EmailToResendTopiaDao emailToResendDao = getEmailToResendDao(); List<EmailToResend> allEmailsToResend = emailToResendDao.findAll(); + if (log.isDebugEnabled()) { + log.debug("Send " + allEmailsToResend.size() + " emails ..."); + } + for (EmailToResend emailToResend : allEmailsToResend) { try { String to = emailToResend.getTos(); @@ -349,23 +359,47 @@ public class EmailService extends PollenServiceSupport { bccs.addAll(Arrays.asList(bcc.split(RECIPIENT_SEPARATOR))); } - Collection<InternetAddress> replyTo; - try { - replyTo = Arrays.asList(InternetAddress.parse(emailToResend.getReplyTo())); - } catch (AddressException e) { - throw new PollenTechnicalException("error parse replyTo", e); + Collection<InternetAddress> replyTo = null; + if (StringUtils.isNotEmpty(emailToResend.getReplyTo())) { + try { + replyTo = Arrays.asList(InternetAddress.parse(emailToResend.getReplyTo())); + } catch (AddressException e) { + throw new PollenTechnicalException("error parse replyTo", e); + } } doSend(emailToResend.getSubject(), emailToResend.getBody(), emailToResend.getAdrFrom(), replyTo, tos, bccs); - emailToResendDao.delete(emailToResend); commit(); } catch (EmailException e) { + if (SendFailedException.class.isInstance(e.getCause())) { + SendFailedException sendFailedException = SendFailedException.class.cast(e.getCause()); + if (ArrayUtils.isNotEmpty(sendFailedException.getInvalidAddresses())) { + List<String> emails = Stream.of(sendFailedException.getInvalidAddresses()) + .map(Address::toString) + .collect(Collectors.toList()); + getPollenPrincipalDao() + .forEmailIn(emails) + .findAll() + .forEach(pollenPrincipal -> pollenPrincipal.setInvalid(true)); + commit(); + } + } else { + if (log.isErrorEnabled()) { + log.error("Error while resending an email, keep it and try again", e); + } + } + } + + try { + TimeUnit.MILLISECONDS.sleep(getPollenServiceConfig().getSmtpWait()); + } catch (InterruptedException e) { if (log.isErrorEnabled()) { - log.error("Error while resending an email, keep it and try again", e); + log.error("Error while resending an email, Interrupted sleeping", e); } } + } } @@ -400,8 +434,6 @@ public class EmailService extends PollenServiceSupport { String from = fromAddress.toUnicodeString(); Collection<InternetAddress> replyTo = mail.getReplyTo(); - - EmailToResend emailToResend = getEmailToResendDao().create(); emailToResend.setSubject(subject); emailToResend.setBody(body); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/MailBoxService.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/MailBoxService.java index 6578fd49..da2c73e9 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/MailBoxService.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/MailBoxService.java @@ -206,6 +206,26 @@ public class MailBoxService extends PollenServiceSupport { } + protected void undeliveredFlagPollenPrincipal(PollenPrincipal pollenPrincipal, Message message) { + + if (isUndeliveredMessage(message)) { + pollenPrincipal.setInvalid(true); + commit(); + } + } + + + protected boolean isUndeliveredMessage(Message message) { + try { + return message.getSubject().contains("Undelivered Mail Returned to Sender"); + } catch (MessagingException e) { + if (log.isErrorEnabled()) { + log.error("error on read message on mail box", e); + } + return false; + } + } + protected String getMailId(String address) { String mailId = null; String smtpFrom = getPollenServiceConfig().getSmtpFrom(); diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/PollenInvalidEmailsException.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/PollenInvalidEmailsException.java new file mode 100644 index 00000000..ed840ade --- /dev/null +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/PollenInvalidEmailsException.java @@ -0,0 +1,16 @@ +package org.chorem.pollen.services.service.mail; + +import java.util.List; + +/** + * @author Sylvain Bavencoff - bavencoff@codelutin.com + */ +public class PollenInvalidEmailsException extends Exception { + + protected final List<String> invalidEmails; + + public PollenInvalidEmailsException(List<String> invalidEmails, Throwable cause) { + super(cause); + this.invalidEmails = invalidEmails; + } +} diff --git a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/PollenMailType.java b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/PollenMailType.java index 11d22bcf..494406ce 100644 --- a/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/PollenMailType.java +++ b/pollen-services/src/main/java/org/chorem/pollen/services/service/mail/PollenMailType.java @@ -26,7 +26,7 @@ public enum PollenMailType { pcpe(PollChoicePeriodEndedEmail.class, (service, context) -> service.noAction()), pcps(PollChoicePeriodStartedEmail.class, (service, context) -> service.noAction()), pcl(PollClosedEmail.class, (service, context) -> service.noAction()), - pcr(PollCreatedEmail.class, (service, context) -> service.noAction()), + pcr(PollCreatedEmail.class, (service, context) -> service.undeliveredFlagPollenPrincipal(context.getPoll().getCreator(), context.getMessage())), per(PollEndReminderEmail.class, (service, context) -> service.noAction()), pi(PollInvitationEmail.class, (service, context) -> service.forwardToCreatorAction(context.getPoll(), context.getMessage())), pr(PollReportEmail.class, (service, context) -> service.noAction()), @@ -35,7 +35,10 @@ public enum PollenMailType { pvps(PollVotePeriodStartedEmail.class, (service, context) -> service.noAction()), pvr(PollVoteReminderEmail.class, (service, context) -> service.noAction()), rv(ResendValidationEmail.class, (service, context) -> service.noAction()), - rpi(RestrictedPollInvitationEmail.class, (service, context) -> service.forwardToCreatorAction(context.getPoll(), context.getMessage())), + rpi(RestrictedPollInvitationEmail.class, (service, context) -> { + service.forwardToCreatorAction(context.getPoll(), context.getMessage()); + service.undeliveredFlagPollenPrincipal(context.getPrincipal(), context.getMessage()); + }), uac(UserAccountCreatedEmail.class, (service, context) -> service.noAction()), uacfp(UserAccountCreatedFromProviderEmail.class, (service, context) -> service.noAction()), uad(UserAccountDeletedEmail.class, (service, context) -> service.noAction()), 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 2458d219..81bcde79 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 @@ -32,6 +32,7 @@ pollen.configuration.sessionTimeoutDelay=Inactivity delay before invalidate the pollen.configuration.smptHost=Smtp Host pollen.configuration.smtpFrom=Smtp From pollen.configuration.smtpPort=Smtp Port +pollen.configuration.smtpWait=Time between two send mail to smtp pollen.configuration.userConnectedRequired=Only connected users can be access on application pollen.configuration.usersCanCreatePoll=Wich user can create Poll ("All_USERS", "USERS_CONNECTED" or "USERS_SELECTED") pollen.configuration.version=Application version 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 f3ceaf7a..5a28f64c 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 @@ -32,6 +32,7 @@ pollen.configuration.sessionTimeoutDelay=Temps autorisé d'inactivité avant d'i pollen.configuration.smptHost=Hôte smtp pollen.configuration.smtpFrom=Expéditeur pollen.configuration.smtpPort=Port smtp +pollen.configuration.smtpWait=Intervalle de temps entre deux envois de mail au SMTP pollen.configuration.userConnectedRequired=Seul les utilisateurs connectés peuvent accéder à l'application pollen.configuration.usersCanCreatePoll=Quels utilisateurs peuvent créer des sondages ("All_USERS", "USERS_CONNECTED" ou "USERS_SELECTED") pollen.configuration.version=Version de l'application diff --git a/pollen-ui-riot-js/src/main/web/i18n/en.json b/pollen-ui-riot-js/src/main/web/i18n/en.json index 26fe15a4..2ff2f69e 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/en.json +++ b/pollen-ui-riot-js/src/main/web/i18n/en.json @@ -381,6 +381,8 @@ "poll_created_vote": "To vote on poll, please use following link", "poll_created_editUrl": "Manage poll", "poll_created_voteUrl": "Vote on poll", + "poll_invalidEmails_message_before": "Emails send to next address can't be delivered :", + "poll_invalidEmails_message_after": "thank to check this address.", "users_title": "All users", "users_noUser": "No user", "users_one": "{0} user", @@ -551,6 +553,7 @@ "voterList_member_resendInvitation_success": "invitation send", "voterList_maxVotersAlert_title": "Number of voters limitation", "voterList_maxVotersAlert": "The number of voters exceeds the limit of the standard offer ({0} voters). Users can continue to vote but only the first {0} votes are taken into account in the calculation of the result. Read <a href=\"#home\">the offers page</a> to unlock this limit.", + "voterList_member_invalidEmail": "invitation mail can't be delivered, thank to check email address.", "modal_cancel": "Cancel", "modal_ok": "Ok", "confirm_cancel": "Cancel", diff --git a/pollen-ui-riot-js/src/main/web/i18n/fr.json b/pollen-ui-riot-js/src/main/web/i18n/fr.json index 5699f9d6..f3570c5c 100644 --- a/pollen-ui-riot-js/src/main/web/i18n/fr.json +++ b/pollen-ui-riot-js/src/main/web/i18n/fr.json @@ -381,6 +381,8 @@ "poll_created_vote": "Pour voter, veuillez utiliser le lien suivant", "poll_created_editUrl": "Gérer le sondage", "poll_created_voteUrl": "Voter", + "poll_invalidEmails_message_before": "Les courriels envoyés aux adresses suivantes n'ont pas put être délivrées :", + "poll_invalidEmails_message_after": "Merci des vérifier ces adresses.", "users_title": "Les utilisateurs", "users_noUser": "Aucun utilisateur", "users_one": "{0} utilisateur", @@ -551,6 +553,7 @@ "voterList_member_deleteMessage": "Supprimer le participant ?", "voterList_member_resendInvitation": "Renvoyer une invitation", "voterList_member_resendInvitation_success": "L'invitation est envoyée", + "voterList_member_invalidEmail": "Le mail d'invitation n'a pas pu être délivré, merci de verifier l'adresse électronique.", "voterList_maxVotersAlert_title": "Limitation du Nombre de votants", "voterList_maxVotersAlert": "Le nombre de participants dépasse la limite de l'offre standard ({0} votants). Tout les participants pourront voter mais seul les {0} premiers votes seront pris en compte dans le calcul du résultat. Consulter <a href=\"#home\">la page des nos offres</a> pour déverrouiller cette limite.", "modal_cancel": "Annuler", diff --git a/pollen-ui-riot-js/src/main/web/js/Poll.js b/pollen-ui-riot-js/src/main/web/js/Poll.js index 3dc4f817..a2b03aa8 100644 --- a/pollen-ui-riot-js/src/main/web/js/Poll.js +++ b/pollen-ui-riot-js/src/main/web/js/Poll.js @@ -407,6 +407,13 @@ class Poll { }); } + getInvalidEmails() { + if (this.id) { + return pollService.getInvalidEmails(this.id, this.permission); + } + return Promise.reject("Init poll after get invalid emails"); + } + } module.exports = singleton(Poll); 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 a3a0c15e..9530c05b 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollForm.js +++ b/pollen-ui-riot-js/src/main/web/js/PollForm.js @@ -326,6 +326,13 @@ class PollForm { return Promise.reject("Init poll after reopen"); } + getInvalidEmails() { + if (this.model.id) { + return pollService.getInvalidEmails(this.model.id, this.permission); + } + return Promise.reject("Init poll after get invalid emails"); + } + } module.exports = singleton(PollForm); diff --git a/pollen-ui-riot-js/src/main/web/js/PollService.js b/pollen-ui-riot-js/src/main/web/js/PollService.js index 41d79b40..c1537c8b 100644 --- a/pollen-ui-riot-js/src/main/web/js/PollService.js +++ b/pollen-ui-riot-js/src/main/web/js/PollService.js @@ -123,6 +123,11 @@ class PollService extends FetchService { let url = this._getUrlPrefix(pollId) + "/reports/" + report.id; return this.post(url, {report: report}, {permission: permission}); } + + getInvalidEmails(pollId, permission) { + let url = this._getUrlPrefix(pollId) + "/invalidEmails"; + return this.get(url, {permission: permission}); + } } module.exports = singleton(PollService); diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/CheckEmails.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/CheckEmails.tag.html new file mode 100644 index 00000000..fdfa7574 --- /dev/null +++ b/pollen-ui-riot-js/src/main/web/tag/poll/CheckEmails.tag.html @@ -0,0 +1,45 @@ +<CheckEmails> + <div show={invalidEmails.length} + class="c-alert c-alert--warning"> + {__.message_before} + <ul class="emails"> + <li each={email in invalidEmails}>{email}</li> + </ul> + {__.message_after} + </div> + + <script type="es6"> + this.session = require("../../js/Session"); + this.installBundle(this.session, "poll_invalidEmails"); + + this.poll = require("../../js/Poll.js"); + + this.choiceToAdd = this.poll.initChoice(); + this.invalidEmails = []; + + this.updateInvalidEmails = () => { + let promise = this.opts.form ? this.opts.form.getInvalidEmails() : this.poll.getInvalidEmails(); + promise.then(emails => { + this.invalidEmails = emails; + this.update(); + }, () => {}); + }; + + this.updateInvalidEmails(); + this.intervalId = window.setInterval(this.updateInvalidEmails, 5000); + + this.on("unmount", () => { + window.clearInterval(this.intervalId); + }); + + + </script> + + <style> + .emails { + margin-left: 3em; + } + + </style> + +</CheckEmails> diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/EditPoll.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/EditPoll.tag.html index 4092b293..7ff51b68 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/EditPoll.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/EditPoll.tag.html @@ -26,6 +26,7 @@ require("./Settings.tag.html"); require("../voterList/VoterList.tag.html"); require("./Summary.tag.html"); require("../components/HumanInput.tag.html"); +require("./CheckEmails.tag.html"); <EditPoll> @@ -56,6 +57,7 @@ require("../components/HumanInput.tag.html"); </div> <div class="main-content"> + <CheckEmails if={!form.creation} form={form}/> <Description if={!showSummary && form.step === 0} form={form} ref="description"/> <Choices if={!showSummary && form.step === 1} form={form} ref="choices"/> <Settings if={!showSummary && form.step === 2} form={form} ref="settings"/> diff --git a/pollen-ui-riot-js/src/main/web/tag/poll/Poll.tag.html b/pollen-ui-riot-js/src/main/web/tag/poll/Poll.tag.html index f98cf18d..cc8ec7dd 100644 --- a/pollen-ui-riot-js/src/main/web/tag/poll/Poll.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/poll/Poll.tag.html @@ -23,6 +23,7 @@ require("./Comments.tag.html"); require("./Results.tag.html"); require("./Choices.tag.html"); require("./Settings.tag.html"); +require("./CheckEmails.tag.html"); require("../popup/QrCodeButton.tag.html"); require("../components/MultiLineLabel.tag.html"); require("../components/InnerHtml.tag.html"); @@ -136,6 +137,8 @@ require("./Report.tag.html"); <p><MultiLineLabel label="{poll.description}"></MultiLineLabel></p> </div> + <CheckEmails if={poll.permission}/> + <div class="c-alert c-alert--warning" if={poll.maxVoters > 0 && poll.voteCount > poll.maxVoters}> <ContentLoader path={maxVotersAlertPage}/> diff --git a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberCard.tag.html b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberCard.tag.html index a138f4dc..70fbab89 100644 --- a/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberCard.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/voterList/VoterListMemberCard.tag.html @@ -8,12 +8,12 @@ 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% @@ -40,6 +40,10 @@ require("./VoterListMemberEditModal.tag.html"); {parent.opts.member.email} </span> <i if={parent.opts.member.voting} class="voting success fa fa-check" aria-hidden="true"></i> + <i if={parent.opts.member.invalidEmail} + class="voting error fa fa-times" + title={parent.__.invalidEmail} + aria-hidden="true"></i> </yield> </Card> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.