package de.asideas.crowdsource.domain.service.user; import de.asideas.crowdsource.domain.model.CommentEntity; import de.asideas.crowdsource.domain.model.ProjectEntity; import de.asideas.crowdsource.domain.model.UserEntity; import de.asideas.crowdsource.repository.UserRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.expression.Expression; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Service; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder; import java.util.*; import java.util.stream.Collectors; @SuppressWarnings("Duplicates") @Service public class UserNotificationService { public static final Integer COMMENT_EXCERPT_LENGTH = 160; public static final String FROM_ADDRESS = "noreply@crowd.asideas.de"; public static final String PROJECT_LINK_PATTERN = "/project/{id}"; public static final String ACTIVATION_LINK_PATTERN = "/signup/{emailAddress}/activation/{activationToken}"; public static final String PASSWORD_RECOVERY_LINK_PATTERN = "/login/password-recovery/{emailAddress}/activation/{activationToken}"; public static final String SUBJECT_ACTIVATION = "Bitte vergib ein Passwort für Dein Konto auf der CrowdSource Platform"; public static final String SUBJECT_PROJECT_CREATED = "Neues Projekt erstellt"; public static final String SUBJECT_PROJECT_MODIFIED = "Ein Projekt wurde editiert"; public static final String SUBJECT_PASSWORD_FORGOTTEN = "Bitte vergib ein Passwort für Dein Konto auf der CrowdSource Platform"; public static final String SUBJECT_PROJECT_PUBLISHED = "Freigabe Deines Projektes"; public static final String SUBJECT_PROJECT_REJECTED = "Freigabe Deines Projektes"; public static final String SUBJECT_PROJECT_DEFERRED = "Dein Projekt setzt in der nächsten Finanzierungsrunde aus."; public static final String SUBJECT_PROJECT_COMMENTED = "Ein neuer Kommentar in Deinem Projekt"; private static final Logger LOG = LoggerFactory.getLogger(UserNotificationService.class); @Value("${de.asideas.crowdsource.baseUrl:http://localhost:8080}") private String applicationUrl; @Autowired private Expression activationEmailTemplate; @Autowired private Expression newProjectEmailTemplate; @Autowired private Expression passwordForgottenEmailTemplate; @Autowired private Expression projectPublishedEmailTemplate; @Autowired private Expression projectRejectedEmailTemplate; @Autowired private Expression projectDeferredEmailTemplate; @Autowired private Expression projectModifiedEmailTemplate; @Autowired private Expression projectCommentedEmailTemplate; @Autowired private UserRepository userRepository; @Autowired private JavaMailSender mailSender; @Autowired private AsyncTaskExecutor taskExecutorSmtp; public void sendActivationMail(UserEntity user) { String activationLink = buildLink(ACTIVATION_LINK_PATTERN, user.getEmail(), user.getActivationToken()); LOG.debug("Sending activation link {} to {}", activationLink, user.getEmail()); StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("link", activationLink); context.setVariable("userName", user.fullNameFromEmail()); final String mailContent = activationEmailTemplate.getValue(context, String.class); sendMail(user.getEmail(), SUBJECT_ACTIVATION, mailContent); } public void sendPasswordRecoveryMail(UserEntity user) { String passwordRecoveryLink = buildLink(PASSWORD_RECOVERY_LINK_PATTERN, user.getEmail(), user.getActivationToken()); LOG.debug("Sending password recovery link {} to {}", passwordRecoveryLink, user.getEmail()); StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("link", passwordRecoveryLink); context.setVariable("userName", user.fullNameFromEmail()); final String mailContent = passwordForgottenEmailTemplate.getValue(context, String.class); sendMail(user.getEmail(), SUBJECT_PASSWORD_FORGOTTEN, mailContent); } public void notifyCreatorOnProjectStatusUpdate(ProjectEntity project) { final StandardEvaluationContext context = new StandardEvaluationContext(); final String projectLink = getProjectLink(project.getId()); context.setVariable("link", projectLink); context.setVariable("userName", project.getCreator().fullNameFromEmail()); switch (project.getStatus()) { case PUBLISHED: final String publishMessage = projectPublishedEmailTemplate.getValue(context, String.class); sendMail(project.getCreator().getEmail(), SUBJECT_PROJECT_PUBLISHED, publishMessage); break; case REJECTED: final String rejectedMessage = projectRejectedEmailTemplate.getValue(context, String.class); sendMail(project.getCreator().getEmail(), SUBJECT_PROJECT_REJECTED, rejectedMessage); break; case DEFERRED: case PUBLISHED_DEFERRED: final String deferringMessage = projectDeferredEmailTemplate.getValue(context, String.class); sendMail(project.getCreator().getEmail(), SUBJECT_PROJECT_DEFERRED, deferringMessage); break; default: final String defaultMessage = "Das Projekt " + project.getTitle() + " wurde in den Zustand " + project.getStatus().name() + " versetzt."; final String defaultSubject = "Der Zustand des Projekts " + project.getTitle() + " hat sich geändert!"; sendMail(project.getCreator().getEmail(), defaultSubject, defaultMessage); break; } } public void notifyCreatorOnComment(CommentEntity comment) { ProjectEntity project = comment.getProject(); if (comment.getUser().equals(project.getCreator())) { return; } final String projectLink = getProjectLink(project.getId()); UserEntity recipient = project.getCreator(); StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("recipientName", recipient.fullNameFromEmail()); context.setVariable("projectName", project.getTitle()); context.setVariable("commentingUser", comment.getUser().fullNameFromEmail()); context.setVariable("commentExcerpt", commentExcerpt(comment)); context.setVariable("link", projectLink); final String mailContent = projectCommentedEmailTemplate.getValue(context, String.class); final SimpleMailMessage message = newMailMessage(recipient.getEmail(), SUBJECT_PROJECT_COMMENTED, mailContent); sendMails(Collections.singleton(message)); } public void notifyCreatorAndAdminOnProjectModification(ProjectEntity project, UserEntity modifier) { final String projectLink = getProjectLink(project.getId()); final Set<UserEntity> users2Notify = new HashSet<>(userRepository.findAllAdminUsers()); users2Notify.add(modifier); users2Notify.add(project.getCreator()); final List<SimpleMailMessage> mails = users2Notify.stream().map(recipient -> { StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("link", projectLink); context.setVariable("recipientName", recipient.fullNameFromEmail()); context.setVariable("modifierName", modifier.fullNameFromEmail()); final String mailContent = projectModifiedEmailTemplate.getValue(context, String.class); return newMailMessage(recipient.getEmail(), SUBJECT_PROJECT_MODIFIED, mailContent); }).collect(Collectors.toList()); sendMails(mails); } public void notifyAdminOnProjectCreation(ProjectEntity project, String emailAddress) { final String projectLink = getProjectLink(project.getId()); StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("link", projectLink); final String mailContent = newProjectEmailTemplate.getValue(context, String.class); sendMail(emailAddress, SUBJECT_PROJECT_CREATED, mailContent); } private String getProjectLink(String projectId) { UriComponentsBuilder uriBuilder = ServletUriComponentsBuilder.fromUriString(applicationUrl); uriBuilder.fragment(PROJECT_LINK_PATTERN); return uriBuilder.buildAndExpand(projectId).toUriString(); } private String buildLink(String urlPattern, String emailAddress, String activationToken) { UriComponentsBuilder uriBuilder = ServletUriComponentsBuilder.fromUriString(applicationUrl); uriBuilder.fragment(urlPattern); return uriBuilder.buildAndExpand(emailAddress, activationToken).toUriString(); } private String commentExcerpt(CommentEntity comment){ final String commentString = comment.getComment(); if (commentString.length() <= COMMENT_EXCERPT_LENGTH){ return commentString; } return commentString.substring(0, COMMENT_EXCERPT_LENGTH) + " ..."; } private void sendMail(String email, String subject, String messageText) { final SimpleMailMessage mailMessage = newMailMessage(email, subject, messageText); taskExecutorSmtp.submit(() -> { try { LOG.info("Sending mail with subject: " + mailMessage.getSubject() ); mailSender.send(mailMessage); } catch (Exception e) { LOG.error("Error on E-Mail Send. Message was: " + mailMessage, e); } }); } private void sendMails(final Collection<SimpleMailMessage> messages) { taskExecutorSmtp.submit(() -> { for (SimpleMailMessage message : messages) { try { LOG.info("Sending mail with subject: " + message.getSubject() ); mailSender.send(message); } catch (Exception e) { LOG.error("Error on E-Mail Send. Message was: " + message, e); } } }); } private SimpleMailMessage newMailMessage(String recipientEmail, String subject, String messageText) { final SimpleMailMessage mailMessage = new SimpleMailMessage(); mailMessage.setTo(recipientEmail); mailMessage.setFrom(FROM_ADDRESS); mailMessage.setSubject(subject); mailMessage.setText(messageText); return mailMessage; } }