package de.flower.rmt.service.mail;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import de.flower.common.util.Check;
import de.flower.rmt.model.db.entity.Invitation;
import de.flower.rmt.model.db.entity.Uniform;
import de.flower.rmt.model.db.entity.User;
import de.flower.rmt.model.db.entity.event.AbstractSoccerEvent;
import de.flower.rmt.model.db.entity.event.AbstractSoccerEvent_;
import de.flower.rmt.model.db.entity.event.Event;
import de.flower.rmt.model.db.entity.event.Event_;
import de.flower.rmt.model.db.entity.event.Match_;
import de.flower.rmt.model.db.type.EventType;
import de.flower.rmt.model.db.type.RSVPStatus;
import de.flower.rmt.model.dto.Notification;
import de.flower.rmt.service.IEventManager;
import de.flower.rmt.service.IICalendarProvider;
import de.flower.rmt.service.IInvitationManager;
import de.flower.rmt.service.IUrlProvider;
import de.flower.rmt.ui.markup.html.form.renderer.SurfaceRenderer;
import de.flower.rmt.util.Dates;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author flowerrrr
*/
@Service
public class NotificationService implements INotificationService, IICalendarProvider {
private final static Logger log = LoggerFactory.getLogger(NotificationService.class);
@Autowired
private IMailService mailService;
@Autowired
private ITemplateService templateService;
@Autowired
private IEventManager eventManager;
@Autowired
private IInvitationManager invitationManager;
@Autowired
private IUrlProvider urlProvider;
@Autowired
private MessageSourceAccessor messageSource;
@Override
public void sendResetPasswordMail(final User user, final User manager) {
mailService.sendMail(getResetPasswordMessage(user, manager));
}
@VisibleForTesting
protected SimpleMailMessage getResetPasswordMessage(final User user, final User manager) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(user.getEmails());
if (manager != null) {
message.setBcc(manager.getEmail());
}
Map<String, Object> model = new HashMap<String, Object>();
model.put("user", user);
String subject = templateService.mergeTemplate(EmailTemplate.PASSWORD_RESET.getSubject(), model);
String content = templateService.mergeTemplate(EmailTemplate.PASSWORD_RESET.getContent(), model);
message.setSubject(subject);
message.setText(content);
return message;
}
@Override
public void sendInvitationNewUser(final User user, final User manager) {
mailService.sendMail(getInvitationNewUserMessage(user, manager));
}
@VisibleForTesting
protected SimpleMailMessage getInvitationNewUserMessage(User user, User manager) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(user.getEmails());
message.setBcc(manager.getEmail());
Map<String, Object> model = new HashMap<String, Object>();
model.put("user", user);
model.put("manager", manager);
model.put("club", user.getClub());
String subject = templateService.mergeTemplate(EmailTemplate.INVITATION_NEWUSER.getSubject(), model);
String content = templateService.mergeTemplate(EmailTemplate.INVITATION_NEWUSER.getContent(), model);
message.setSubject(subject);
message.setText(content);
return message;
}
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
// required to enable lazy fetching of event and event.created by user
public void sendStatusChangedMessage(final Invitation invitationIn) {
Invitation invitation = invitationManager.loadById(invitationIn.getId());
SimpleMailMessage message = getStatusChangedMessage(invitation);
mailService.sendMail(message);
}
@VisibleForTesting
protected SimpleMailMessage getStatusChangedMessage(final Invitation invitation) {
SimpleMailMessage message = new SimpleMailMessage();
Event event = invitation.getEvent();
User user = invitation.getUser();
User manager = invitation.getEvent().getCreatedBy();
message.setTo(manager.getEmail());
Map<String, Object> model = new HashMap<String, Object>();
model.put("user", user);
model.put("event", invitation.getEvent());
model.put("eventDateTime", Dates.formatDateTimeShortWithWeekday(event.getDateTimeAsDate()));
model.put("eventType", messageSource.getMessage(event.getEventType().getResourceKey()));
model.put("status", messageSource.getMessage(RSVPStatus.getResourceKey(invitation.getStatus())));
String subject = templateService.mergeTemplate(EmailTemplate.INVITATION_STATUSCHANGED.getSubject(), model);
String content = templateService.mergeTemplate(EmailTemplate.INVITATION_STATUSCHANGED.getContent(), model);
message.setSubject(subject);
message.setText(content);
return message;
}
@Override
public Notification newEventNotification(final Event eventIn) {
Event event = eventManager.loadById(eventIn.getId(), Event_.venue, Event_.team, AbstractSoccerEvent_.uniform, Match_.opponent);
return getNewEventNotification(event);
}
@VisibleForTesting
protected Notification getNewEventNotification(Event event) {
Notification notification = new Notification();
final Map<String, Object> model = getEventDetailsModel(event);
String eventDetails = templateService.mergeTemplate(EmailTemplate.EVENT_DETAILS.getTemplate(), model);
model.put("eventDetails", eventDetails);
notification.setSubject(templateService.mergeTemplate(EmailTemplate.NOTIFICATION_EVENT.getSubject(), model));
notification.setBody(templateService.mergeTemplate(EmailTemplate.NOTIFICATION_EVENT.getContent(), model));
// create iCalendar attachment
notification.setAttachment(getCalendarAttachment(event));
return notification;
}
@Override
public String getICalendar(final Event event) {
final Map<String, Object> model = Maps.newHashMap();
ICalendarHelper iCalendarHelper = new ICalendarHelper(event);
model.put("uid", iCalendarHelper.getUid());
model.put("dtstart", iCalendarHelper.getDtstart());
model.put("dtend", iCalendarHelper.getDtend());
model.put("dtstamp", iCalendarHelper.getDtstamp());
model.put("summary", iCalendarHelper.getSummary());
model.put("description", iCalendarHelper.getDescription(getEventDetails(event)));
model.put("location", iCalendarHelper.getLocation());
String iCalender = templateService.mergeTemplate(EmailTemplate.EVENT_ICALENDAR.getTemplate(), model);
return iCalender;
}
@VisibleForTesting
protected Notification.Attachment getCalendarAttachment(Event event) {
Notification.Attachment attachment = new Notification.Attachment();
attachment.name = messageSource.getMessage("icalendar.name");
attachment.contentType = ICalendarHelper.CONTENT_TYPE_MAIL;
attachment.data = ICalendarHelper.getBytes(getICalendar(event));
return attachment;
}
@Override
public void sendNoResponseReminder(Event event, final List<Invitation> invitations) {
Check.isTrue(!event.isCanceled(), "Trying to send reminder mail for canceled event.");
log.info("Sending no-response reminder to [{}]", invitations);
SimpleMailMessage message = getNoResponseReminderMessage(event);
List<String> to = Lists.newArrayList();
for (Invitation invitation : invitations) {
if (invitation.hasEmail()) {
to.addAll(Arrays.asList(invitation.getEmails()));
} else {
log.info("Cannot send reminder for invitation without email address [{}].", invitation);
}
}
if (to.isEmpty()) {
log.warn("#sendNoResponseReminder() called with inviations that have no email address assigned.");
return;
}
message.setBcc(to.toArray(new String[]{}));
mailService.sendMail(message);
// send mail to manager
sendSummaryToManager(event, to, "No response to invitation mail.");
}
private void sendSummaryToManager(final Event event, final List<String> to, final String reason) {
final SimpleMailMessage message;
message = new SimpleMailMessage();
message.setTo(event.getCreatedBy().getEmail());
message.setSubject("das tool: Reminder-Mail summary");
String body = "An auto-reminder-mail was sent to the following recpients.\n"
+ "Event: " + urlProvider.deepLinkEvent(event.getId()) + "\n"
+ "Reason: " + reason + "\n"
+ "Users:\n";
body += StringUtils.join(to, "\n");
body += "\n"
+ "_____________________________________________________\n"
+ "Sent by das-tool reminder task.";
message.setText(body);
mailService.sendMail(message);
}
@VisibleForTesting
protected SimpleMailMessage getNoResponseReminderMessage(final Event event) {
SimpleMailMessage message = new SimpleMailMessage();
final Map<String, Object> model = getEventDetailsModel(event);
String eventDetails = templateService.mergeTemplate(EmailTemplate.EVENT_DETAILS.getTemplate(), model);
model.put("eventDetails", eventDetails);
message.setSubject(templateService.mergeTemplate(EmailTemplate.NORESPONSE_REMINDER.getSubject(), model));
message.setText(templateService.mergeTemplate(EmailTemplate.NORESPONSE_REMINDER.getContent(), model));
return message;
}
@Override
public void sendUnsureReminder(final Event event, final List<Invitation> invitations) {
Check.isTrue(!event.isCanceled(), "Trying to send reminder mail for canceled event.");
log.info("Sending unsure reminder to [{}]", invitations);
SimpleMailMessage message = getUnsureReminderMessage(event);
List<String> to = Lists.newArrayList();
for (Invitation invitation : invitations) {
if (invitation.hasEmail()) {
to.addAll(Arrays.asList(invitation.getEmails()));
} else {
log.info("Cannot send reminder for invitation without email address [{}].", invitation);
}
}
if (to.isEmpty()) {
log.warn("#sendUnsureReminder() called with inviations that have no email address assigned.");
return;
}
message.setBcc(to.toArray(new String[]{}));
mailService.sendMail(message);
// send mail to manager
sendSummaryToManager(event, to, "Response status set to 'maybe'.");
}
@VisibleForTesting
protected SimpleMailMessage getUnsureReminderMessage(final Event event) {
SimpleMailMessage message = new SimpleMailMessage();
final Map<String, Object> model = getEventDetailsModel(event);
String eventDetails = templateService.mergeTemplate(EmailTemplate.EVENT_DETAILS.getTemplate(), model);
model.put("eventDetails", eventDetails);
message.setSubject(templateService.mergeTemplate(EmailTemplate.UNSURE_REMINDER.getSubject(), model));
message.setText(templateService.mergeTemplate(EmailTemplate.UNSURE_REMINDER.getContent(), model));
return message;
}
@Override
public void sendEventCanceledMessage(final Event event, final List<Invitation> invitations) {
log.info("Sending event canceled notification to [{}]", invitations);
SimpleMailMessage message = getEventCanceledMessage(event);
List<String> to = Lists.newArrayList();
for (Invitation invitation : invitations) {
if (invitation.hasEmail()) {
to.addAll(Arrays.asList(invitation.getEmails()));
}
}
message.setBcc(to.toArray(new String[]{}));
mailService.sendMail(message);
}
@VisibleForTesting
protected SimpleMailMessage getEventCanceledMessage(final Event event) {
SimpleMailMessage message = new SimpleMailMessage();
final Map<String, Object> model = getEventDetailsModel(event);
String eventDetails = templateService.mergeTemplate(EmailTemplate.EVENT_DETAILS.getTemplate(), model);
model.put("eventDetails", eventDetails);
message.setSubject(templateService.mergeTemplate(EmailTemplate.EVENT_CANCELED.getSubject(), model));
message.setText(templateService.mergeTemplate(EmailTemplate.EVENT_CANCELED.getContent(), model));
return message;
}
protected String getEventDetails(Event event) {
final Map<String, Object> model = getEventDetailsModel(event);
String eventDetails = templateService.mergeTemplate(EmailTemplate.EVENT_DETAILS.getTemplate(), model);
return eventDetails;
}
@VisibleForTesting
protected Map<String, Object> getEventDetailsModel(Event event) {
final Map<String, Object> model = new HashMap<String, Object>();
model.put("event", event);
model.put("eventDate", Dates.formatDateMediumWithWeekday(event.getDateTimeAsDate()));
model.put("eventTime", Dates.formatTimeShort(event.getDateTimeAsDate()));
model.put("eventDateTime", Dates.formatDateTimeShortWithWeekday(event.getDateTimeAsDate()));
model.put("eventType", messageSource.getMessage(event.getEventType().getResourceKey()));
model.put("eventTypeMatch", EventType.Match);
model.put("eventLink", urlProvider.deepLinkEvent(event.getId()));
model.put("isSoccerEvent", EventType.isSoccerEvent(event));
if (event.getVenue() != null) {
model.put("directionsLink", urlProvider.getDirectionsUrl(event.getVenue().getLatLng()));
}
if (EventType.isSoccerEvent(event)) {
AbstractSoccerEvent soccerEvent = (AbstractSoccerEvent) event;
model.put("kickoffTime", Dates.formatTimeShort(soccerEvent.getKickoff()));
model.put("surfaceList", new SurfaceRenderer() {
@Override
protected String getResourceString(final String key) {
return messageSource.getMessage(key);
}
}.renderList(soccerEvent.getSurfaceList()));
if (soccerEvent.getUniform() != null) {
Uniform u = soccerEvent.getUniform();
final Object[] params = new Object[]{u.getShirt(), u.getShorts(), u.getSocks()};
model.put("uniform", messageSource.getMessage("uniform.set", params));
}
}
return model;
}
}