Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development: Restructure non-notification mails to use data transfer objects #9858

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import de.tum.cit.aet.artemis.core.domain.User;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.IMailRecipientUserDTO;
import tech.jhipster.config.JHipsterProperties;

/**
Expand Down Expand Up @@ -47,14 +47,14 @@ public MailSendingService(JHipsterProperties jHipsterProperties, JavaMailSender
* @param isHtml Whether the mail should support HTML tags
*/
@Async
public void sendEmail(User recipient, String subject, String content, boolean isMultipart, boolean isHtml) {
public void sendEmail(IMailRecipientUserDTO recipient, String subject, String content, boolean isMultipart, boolean isHtml) {
log.debug("Send email[multipart '{}' and html '{}'] to '{}' with subject '{}'", isMultipart, isHtml, recipient, subject);

// Prepare message using a Spring helper
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try {
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, StandardCharsets.UTF_8.name());
message.setTo(recipient.getEmail());
message.setTo(recipient.email());
message.setFrom(jHipsterProperties.getMail().getFrom());
message.setSubject(subject);
message.setText(content, isHtml);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@
import de.tum.cit.aet.artemis.communication.domain.Post;
import de.tum.cit.aet.artemis.communication.domain.notification.Notification;
import de.tum.cit.aet.artemis.communication.domain.notification.NotificationConstants;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.IMailRecipientUserDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.activation_mail.ActivationMailRecipientDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_failed_mail.DataExportFailedContentDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_failed_mail.DataExportFailedMailAdminRecipientDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_successful_mail.DataExportSuccessfulContentsDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_successful_mail.DataExportSuccessfulMailAdminRecipientDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.notifications.NotificationMailRecipientDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.password_reset_mail.PasswordResetRecipientDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.saml2_set_password_mail.SAML2SetPasswordMailRecipientDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.weekly_summary_mail.WeeklySummaryMailContentDTO;
import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.weekly_summary_mail.WeeklySummaryMailRecipientDTO;
import de.tum.cit.aet.artemis.core.domain.Course;
import de.tum.cit.aet.artemis.core.domain.DataExport;
import de.tum.cit.aet.artemis.core.domain.User;
Expand All @@ -47,11 +58,9 @@ public class MailService implements InstantNotificationService {

private static final String BASE_URL = "baseUrl";

private static final String DATA_EXPORT = "dataExport";
private static final String DATA_EXPORT_CONTENTS = "dataExportContents";

private static final String DATA_EXPORTS = "dataExports";

private static final String REASON = "reason";
private static final String DATA_EXPORT_FAILED_CONTENT = "dataExportFailedContent";

@Value("${server.url}")
private URL artemisServerUrl;
Expand Down Expand Up @@ -86,8 +95,7 @@ public class MailService implements InstantNotificationService {
private static final String TIME_SERVICE = "timeService";

// weekly summary related variables

private static final String WEEKLY_SUMMARY_NEW_EXERCISES = "weeklySummaryNewExercises";
private static final String WEEKLY_SUMMARY_CONTENT = "weeklySummaryContent";

public MailService(MessageSource messageSource, SpringTemplateEngine templateEngine, TimeService timeService, MailSendingService mailSendingService) {
this.messageSource = messageSource;
Expand All @@ -99,82 +107,89 @@ public MailService(MessageSource messageSource, SpringTemplateEngine templateEng
/**
* Sends a predefined mail based on a template
*
* @param user The receiver of the mail
* @param recipient The receiver of the mail
* @param templateName The name of the template
* @param titleKey The key mapping the title for the subject of the mail
*/
public void sendEmailFromTemplate(User user, String templateName, String titleKey) {
Locale locale = Locale.forLanguageTag(user.getLangKey());
Context context = createBaseContext(user, locale);
prepareTemplateAndSendEmail(user, templateName, titleKey, context);
private void sendEmailFromTemplate(IMailRecipientUserDTO recipient, String templateName, String titleKey) {
Locale locale = Locale.forLanguageTag(recipient.langKey());
xHadie marked this conversation as resolved.
Show resolved Hide resolved
Context context = createBaseContext(recipient, locale);
prepareTemplateAndSendEmail(recipient, templateName, titleKey, context);
}

/**
* Sends an email to a user (the internal admin user) about a failed data export creation.
*
* @param admin the admin user
* @param templateName the name of the email template
* @param titleKey the subject of the email
* @param dataExport the data export that failed
* @param reason the exception that caused the data export to fail
* @param recipientAdmin the admin user
* @param templateName the name of the email template
* @param titleKey the subject of the email
* @param exportFailCaseContent the relevant information of the failed data export
*/
public void sendDataExportFailedEmailForAdmin(User admin, String templateName, String titleKey, DataExport dataExport, Exception reason) {
Locale locale = Locale.forLanguageTag(admin.getLangKey());
Context context = createBaseContext(admin, locale);
context.setVariable(DATA_EXPORT, dataExport);
context.setVariable(REASON, reason);
prepareTemplateAndSendEmailWithArgumentInSubject(admin, templateName, titleKey, dataExport.getUser().getLogin(), context);
private void sendDataExportFailedEmailForAdmin(IMailRecipientUserDTO recipientAdmin, String templateName, String titleKey, DataExportFailedContentDTO exportFailCaseContent) {
Locale locale = Locale.forLanguageTag(recipientAdmin.langKey());
xHadie marked this conversation as resolved.
Show resolved Hide resolved
Context context = createBaseContext(recipientAdmin, locale);
context.setVariable(DATA_EXPORT_FAILED_CONTENT, exportFailCaseContent);
prepareTemplateAndSendEmailWithArgumentInSubject(recipientAdmin, templateName, titleKey, exportFailCaseContent.exportUsername(), context);
}

public void sendSuccessfulDataExportsEmailToAdmin(User admin, String templateName, String titleKey, Set<DataExport> dataExports) {
Locale locale = Locale.forLanguageTag(admin.getLangKey());
Context context = createBaseContext(admin, locale);
context.setVariable(DATA_EXPORTS, dataExports);
prepareTemplateAndSendEmail(admin, templateName, titleKey, context);
private void sendSuccessfulDataExportsEmailToAdmin(IMailRecipientUserDTO recipientAdmin, String templateName, String titleKey,
DataExportSuccessfulContentsDTO dataExportContents) {
Locale locale = Locale.forLanguageTag(recipientAdmin.langKey());
xHadie marked this conversation as resolved.
Show resolved Hide resolved
Context context = createBaseContext(recipientAdmin, locale);
context.setVariable(DATA_EXPORT_CONTENTS, dataExportContents);
prepareTemplateAndSendEmail(recipientAdmin, templateName, titleKey, context);
}

private void prepareTemplateAndSendEmail(User admin, String templateName, String titleKey, Context context) {
private void prepareTemplateAndSendEmail(IMailRecipientUserDTO recipient, String templateName, String titleKey, Context context) {
String content = templateEngine.process(templateName, context);
String subject = messageSource.getMessage(titleKey, null, context.getLocale());
mailSendingService.sendEmail(admin, subject, content, false, true);
mailSendingService.sendEmail(recipient, subject, content, false, true);
}

private void prepareTemplateAndSendEmailWithArgumentInSubject(User admin, String templateName, String titleKey, String argument, Context context) {
private void prepareTemplateAndSendEmailWithArgumentInSubject(IMailRecipientUserDTO recipient, String templateName, String titleKey, String argument, Context context) {
String content = templateEngine.process(templateName, context);
String subject = messageSource.getMessage(titleKey, new Object[] { argument }, context.getLocale());
mailSendingService.sendEmail(admin, subject, content, false, true);
mailSendingService.sendEmail(recipient, subject, content, false, true);
}

private Context createBaseContext(User admin, Locale locale) {
/**
* Creates a base context for the email
*
* @param recipient DTO representing the user in a given use-case
* @param locale language preference of the user
*/
private Context createBaseContext(IMailRecipientUserDTO recipient, Locale locale) {
Context context = new Context(locale);
context.setVariable(USER, admin);
context.setVariable(USER, recipient);
context.setVariable(BASE_URL, artemisServerUrl);
return context;
}

public void sendActivationEmail(User user) {
log.debug("Sending activation email to '{}'", user.getEmail());
sendEmailFromTemplate(user, "mail/activationEmail", "email.activation.title");
sendEmailFromTemplate(ActivationMailRecipientDTO.of(user), "mail/activationEmail", "email.activation.title");
}

public void sendPasswordResetMail(User user) {
log.debug("Sending password reset email to '{}'", user.getEmail());
sendEmailFromTemplate(user, "mail/passwordResetEmail", "email.reset.title");
sendEmailFromTemplate(PasswordResetRecipientDTO.of(user), "mail/passwordResetEmail", "email.reset.title");
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}

public void sendSAML2SetPasswordMail(User user) {
log.debug("Sending SAML2 set password email to '{}'", user.getEmail());
sendEmailFromTemplate(user, "mail/samlSetPasswordEmail", "email.saml.title");
sendEmailFromTemplate(SAML2SetPasswordMailRecipientDTO.of(user), "mail/samlSetPasswordEmail", "email.saml.title");
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}

public void sendDataExportFailedEmailToAdmin(User admin, DataExport dataExport, Exception reason) {
log.debug("Sending data export failed email to admin email address '{}'", admin.getEmail());
sendDataExportFailedEmailForAdmin(admin, "mail/dataExportFailedAdminEmail", "email.dataExportFailedAdmin.title", dataExport, reason);
sendDataExportFailedEmailForAdmin(DataExportFailedMailAdminRecipientDTO.of(admin), "mail/dataExportFailedAdminEmail", "email.dataExportFailedAdmin.title",
DataExportFailedContentDTO.of(reason, dataExport));
}

public void sendSuccessfulDataExportsEmailToAdmin(User admin, Set<DataExport> dataExports) {
log.debug("Sending successful creation of data exports email to admin email address '{}'", admin.getEmail());
sendSuccessfulDataExportsEmailToAdmin(admin, "mail/successfulDataExportsAdminEmail", "email.successfulDataExportCreationsAdmin.title", dataExports);
sendSuccessfulDataExportsEmailToAdmin(DataExportSuccessfulMailAdminRecipientDTO.of(admin), "mail/successfulDataExportsAdminEmail",
"email.successfulDataExportCreationsAdmin.title", DataExportSuccessfulContentsDTO.of(dataExports));
}

// notification related
Expand Down Expand Up @@ -224,6 +239,7 @@ public void sendNotification(Notification notification, Set<User> users, Object
* @param user who should be contacted
* @param notificationSubject that is used to provide further information (e.g. exercise, attachment, post, etc.)
*/

xHadie marked this conversation as resolved.
Show resolved Hide resolved
@Override
public void sendNotification(Notification notification, User user, Object notificationSubject) {
NotificationType notificationType = NotificationConstants.findCorrespondingNotificationType(notification.getTitle());
Expand Down Expand Up @@ -282,7 +298,7 @@ public void sendNotification(Notification notification, User user, Object notifi
context.setVariable(BASE_URL, artemisServerUrl);

String content = createContentForNotificationEmailByType(notificationType, context);
mailSendingService.sendEmail(user, subject, content, false, true);
mailSendingService.sendEmail(NotificationMailRecipientDTO.of(user), subject, content, false, true);
}

/**
Expand Down Expand Up @@ -402,15 +418,12 @@ public void sendWeeklySummaryEmail(User user, Set<Exercise> exercises) {
Locale locale = Locale.forLanguageTag(user.getLangKey());

Context context = new Context(locale);
context.setVariable(USER, user);
context.setVariable(WEEKLY_SUMMARY_NEW_EXERCISES, exercises);

context.setVariable(TIME_SERVICE, this.timeService);
String subject = "Weekly Summary";

context.setVariable(BASE_URL, artemisServerUrl);
context.setVariable(USER, WeeklySummaryMailRecipientDTO.of(user));
context.setVariable(WEEKLY_SUMMARY_CONTENT, WeeklySummaryMailContentDTO.of(exercises, timeService));

String subject = "Weekly Summary";
String content = templateEngine.process("mail/weeklySummary", context);
mailSendingService.sendEmail(user, subject, content, false, true);
mailSendingService.sendEmail(WeeklySummaryMailRecipientDTO.of(user), subject, content, false, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto;

/**
* Minimal information a recipient of an email needs to provide.
*/
public interface IMailRecipientUserDTO {

String langKey = "";

String email = "";
xHadie marked this conversation as resolved.
Show resolved Hide resolved

String langKey();

String email();
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.activation_mail;

import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.IMailRecipientUserDTO;
import de.tum.cit.aet.artemis.core.domain.User;

public record ActivationMailRecipientDTO(String langKey, String email, String login, String activationKey) implements IMailRecipientUserDTO {
xHadie marked this conversation as resolved.
Show resolved Hide resolved

public static ActivationMailRecipientDTO of(User user) {
return new ActivationMailRecipientDTO(user.getLangKey(), user.getEmail(), user.getLogin(), user.getActivationKey());
}
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_failed_mail;

import de.tum.cit.aet.artemis.core.domain.DataExport;

public record DataExportFailedContentDTO(String reason, String exportUsername) {

public static DataExportFailedContentDTO of(Exception exception, DataExport dataExport) {
return new DataExportFailedContentDTO(exception.getMessage(), dataExport.getUser().getLogin());
}
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_failed_mail;

import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.IMailRecipientUserDTO;
import de.tum.cit.aet.artemis.core.domain.User;

public record DataExportFailedMailAdminRecipientDTO(String langKey, String email, String login) implements IMailRecipientUserDTO {

public static DataExportFailedMailAdminRecipientDTO of(User user) {
return new DataExportFailedMailAdminRecipientDTO(user.getLangKey(), user.getEmail(), user.getLogin());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_successful_mail;

import de.tum.cit.aet.artemis.core.domain.DataExport;

public record DataExportSuccessfulContentDTO(String userLogin) {

public static DataExportSuccessfulContentDTO of(DataExport dataExport) {
return new DataExportSuccessfulContentDTO(dataExport.getUser().getLogin());
}
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_successful_mail;

import java.util.Set;
import java.util.stream.Collectors;

import de.tum.cit.aet.artemis.core.domain.DataExport;

public record DataExportSuccessfulContentsDTO(Set<DataExportSuccessfulContentDTO> contents) {

public static DataExportSuccessfulContentsDTO of(Set<DataExport> exportSet) {
Set<DataExportSuccessfulContentDTO> contents = exportSet.stream().map(DataExportSuccessfulContentDTO::of).collect(Collectors.toSet());
return new DataExportSuccessfulContentsDTO(contents);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_successful_mail;

import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.IMailRecipientUserDTO;
import de.tum.cit.aet.artemis.core.domain.User;

public record DataExportSuccessfulMailAdminRecipientDTO(String langKey, String email) implements IMailRecipientUserDTO {

public static DataExportSuccessfulMailAdminRecipientDTO of(User user) {
return new DataExportSuccessfulMailAdminRecipientDTO(user.getLangKey(), user.getEmail());
}
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.notifications;

import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.IMailRecipientUserDTO;
import de.tum.cit.aet.artemis.core.domain.User;

public record NotificationMailRecipientDTO(String langKey, String email, String name, String login) implements IMailRecipientUserDTO {

public static NotificationMailRecipientDTO of(User user) {
return new NotificationMailRecipientDTO(user.getLangKey(), user.getEmail(), user.getName(), user.getLogin());
}
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.password_reset_mail;

import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.IMailRecipientUserDTO;
import de.tum.cit.aet.artemis.core.domain.User;

public record PasswordResetRecipientDTO(String langKey, String email, String login, String resetKey) implements IMailRecipientUserDTO {

public static PasswordResetRecipientDTO of(User user) {
return new PasswordResetRecipientDTO(user.getLangKey(), user.getEmail(), user.getLogin(), user.getResetKey());
}
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.saml2_set_password_mail;

import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.IMailRecipientUserDTO;
import de.tum.cit.aet.artemis.core.domain.User;

public record SAML2SetPasswordMailRecipientDTO(String langKey, String email, String login, String resetKey) implements IMailRecipientUserDTO {

public static SAML2SetPasswordMailRecipientDTO of(User user) {
return new SAML2SetPasswordMailRecipientDTO(user.getLangKey(), user.getEmail(), user.getLogin(), user.getResetKey());
}
xHadie marked this conversation as resolved.
Show resolved Hide resolved
}
Loading
Loading