diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/MailSendingService.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/MailSendingService.java index 173aa77d7b3d..ceb009f1463b 100644 --- a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/MailSendingService.java +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/MailSendingService.java @@ -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; /** @@ -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); diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/MailService.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/MailService.java index fc6f7e9e1256..5c2ea605d731 100644 --- a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/MailService.java +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/MailService.java @@ -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; @@ -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; @@ -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; @@ -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()); + 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()); + 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 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()); + 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"); } 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"); } 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 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 @@ -282,7 +297,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); } /** @@ -402,15 +417,12 @@ public void sendWeeklySummaryEmail(User user, Set 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); } } diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/IMailRecipientUserDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/IMailRecipientUserDTO.java new file mode 100644 index 000000000000..931c3c09b1e6 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/IMailRecipientUserDTO.java @@ -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 = ""; + + String langKey(); + + String email(); +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/activation_mail/ActivationMailRecipientDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/activation_mail/ActivationMailRecipientDTO.java new file mode 100644 index 000000000000..682c6e333d12 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/activation_mail/ActivationMailRecipientDTO.java @@ -0,0 +1,14 @@ +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; + +/** + * DTO for the recipient of the activation mail + */ +public record ActivationMailRecipientDTO(String langKey, String email, String login, String activationKey) implements IMailRecipientUserDTO { + + public static ActivationMailRecipientDTO of(User user) { + return new ActivationMailRecipientDTO(user.getLangKey(), user.getEmail(), user.getLogin(), user.getActivationKey()); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_failed_mail/DataExportFailedContentDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_failed_mail/DataExportFailedContentDTO.java new file mode 100644 index 000000000000..c5708714195f --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_failed_mail/DataExportFailedContentDTO.java @@ -0,0 +1,16 @@ +package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_failed_mail; + +import de.tum.cit.aet.artemis.core.domain.DataExport; + +/** + * DTO for the content of a data export failed mail + * + * @param reason The reason why the data export failed + * @param exportUsername The username of the user who initiated the data export + */ +public record DataExportFailedContentDTO(String reason, String exportUsername) { + + public static DataExportFailedContentDTO of(Exception exception, DataExport dataExport) { + return new DataExportFailedContentDTO(exception.getMessage(), dataExport.getUser().getLogin()); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_failed_mail/DataExportFailedMailAdminRecipientDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_failed_mail/DataExportFailedMailAdminRecipientDTO.java new file mode 100644 index 000000000000..4bbab58637a7 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_failed_mail/DataExportFailedMailAdminRecipientDTO.java @@ -0,0 +1,14 @@ +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; + +/** + * DTO for the recipient of the data export failed mail for the admin + */ +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()); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_successful_mail/DataExportSuccessfulContentDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_successful_mail/DataExportSuccessfulContentDTO.java new file mode 100644 index 000000000000..6d6179b7411f --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_successful_mail/DataExportSuccessfulContentDTO.java @@ -0,0 +1,15 @@ +package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.data_export_successful_mail; + +import de.tum.cit.aet.artemis.core.domain.DataExport; + +/** + * DTO for the content of a data export successful mail. + * + * @param userLogin the login of the user who requested the data export + */ +public record DataExportSuccessfulContentDTO(String userLogin) { + + public static DataExportSuccessfulContentDTO of(DataExport dataExport) { + return new DataExportSuccessfulContentDTO(dataExport.getUser().getLogin()); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_successful_mail/DataExportSuccessfulContentsDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_successful_mail/DataExportSuccessfulContentsDTO.java new file mode 100644 index 000000000000..548ec0800081 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_successful_mail/DataExportSuccessfulContentsDTO.java @@ -0,0 +1,17 @@ +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; + +/** + * DTO for the contents of a data export successful mail notification. + */ +public record DataExportSuccessfulContentsDTO(Set contents) { + + public static DataExportSuccessfulContentsDTO of(Set exportSet) { + Set contents = exportSet.stream().map(DataExportSuccessfulContentDTO::of).collect(Collectors.toSet()); + return new DataExportSuccessfulContentsDTO(contents); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_successful_mail/DataExportSuccessfulMailAdminRecipientDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_successful_mail/DataExportSuccessfulMailAdminRecipientDTO.java new file mode 100644 index 000000000000..4388ab51549c --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/data_export_successful_mail/DataExportSuccessfulMailAdminRecipientDTO.java @@ -0,0 +1,14 @@ +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; + +/** + * DTO for the admin recipient of the data export successful mail notification. + */ +public record DataExportSuccessfulMailAdminRecipientDTO(String langKey, String email) implements IMailRecipientUserDTO { + + public static DataExportSuccessfulMailAdminRecipientDTO of(User user) { + return new DataExportSuccessfulMailAdminRecipientDTO(user.getLangKey(), user.getEmail()); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/notifications/NotificationMailRecipientDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/notifications/NotificationMailRecipientDTO.java new file mode 100644 index 000000000000..3b5ad58713e4 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/notifications/NotificationMailRecipientDTO.java @@ -0,0 +1,14 @@ +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; + +/** + * DTO for the recipient of a notification mail. + */ +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()); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/password_reset_mail/PasswordResetRecipientDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/password_reset_mail/PasswordResetRecipientDTO.java new file mode 100644 index 000000000000..1a8f1c3d3124 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/password_reset_mail/PasswordResetRecipientDTO.java @@ -0,0 +1,14 @@ +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; + +/** + * DTO for the password reset mail recipient + */ +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()); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/saml2_set_password_mail/SAML2SetPasswordMailRecipientDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/saml2_set_password_mail/SAML2SetPasswordMailRecipientDTO.java new file mode 100644 index 000000000000..142305daec62 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/saml2_set_password_mail/SAML2SetPasswordMailRecipientDTO.java @@ -0,0 +1,14 @@ +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; + +/** + * DTO for the recipient of the SAML2SetPasswordMail + */ +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()); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/weekly_summary_mail/WeeklyExerciseSummaryDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/weekly_summary_mail/WeeklyExerciseSummaryDTO.java new file mode 100644 index 000000000000..a571f41f82ce --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/weekly_summary_mail/WeeklyExerciseSummaryDTO.java @@ -0,0 +1,40 @@ +package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.weekly_summary_mail; + +import de.tum.cit.aet.artemis.core.service.TimeService; +import de.tum.cit.aet.artemis.exercise.domain.Exercise; + +/** + * A Data Transfer Object (DTO) representing a summary of an exercise for the weekly summary email. + * + * @param title the title of the exercise + * @param type the type of the exercise + * @param difficulty the difficulty level of the exercise + * @param releaseDate the release date of the exercise in a human-readable format + * @param dueDate the due date of the exercise in a human-readable format + * @param maxPoints the maximum points that can be earned for the exercise + * @param bonusPoints the bonus points that can be earned for the exercise + */ +public record WeeklyExerciseSummaryDTO(String title, String type, String difficulty, String releaseDate, String dueDate, double maxPoints, double bonusPoints) { + + /** + * Creates a new `WeeklyExerciseSummaryDTO` instance from the given `Exercise` instance. + * The release and due dates are converted to human-readable format using the given `TimeService`. + * + * @param exercise the exercise to be summarized + * @param timeService the service to convert dates to human-readable format + * @return a new `WeeklyExerciseSummaryDTO` instance + */ + public static WeeklyExerciseSummaryDTO of(Exercise exercise, TimeService timeService) { + String releaseDate = null, dueDate = null; + if (exercise.getReleaseDate() != null) { + releaseDate = timeService.convertToHumanReadableDate(exercise.getReleaseDate()); + } + if (exercise.getDueDate() != null) { + dueDate = timeService.convertToHumanReadableDate(exercise.getDueDate()); + } + + String difficulty = exercise.getDifficulty() != null ? exercise.getDifficulty().toString() : null; + + return new WeeklyExerciseSummaryDTO(exercise.getTitle(), exercise.getType(), difficulty, releaseDate, dueDate, exercise.getMaxPoints(), exercise.getBonusPoints()); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/weekly_summary_mail/WeeklySummaryMailContentDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/weekly_summary_mail/WeeklySummaryMailContentDTO.java new file mode 100644 index 000000000000..d0579c601a49 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/weekly_summary_mail/WeeklySummaryMailContentDTO.java @@ -0,0 +1,29 @@ +package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.weekly_summary_mail; + +import java.util.Set; +import java.util.stream.Collectors; + +import de.tum.cit.aet.artemis.core.service.TimeService; +import de.tum.cit.aet.artemis.exercise.domain.Exercise; + +/** + * A Data Transfer Object (DTO) representing the content of a weekly summary email. + * + * @param hasNewExercises indicates if there are new exercises in the summary + * @param exerciseSummaries a set of summaries for each exercise included in the weekly summary + */ +public record WeeklySummaryMailContentDTO(boolean hasNewExercises, Set exerciseSummaries) { + + /** + * Creates a new instance of WeeklySummaryMailContentDTO from a set of exercises. + * + * @param exercises the set of exercises to be included in the summary + * @param timeService the service used to convert dates to a human-readable format + * @return a new instance of WeeklySummaryMailContentDTO + */ + public static WeeklySummaryMailContentDTO of(Set exercises, TimeService timeService) { + boolean hasNewExercises = !exercises.isEmpty(); + Set exerciseSummaries = exercises.stream().map(exercise -> WeeklyExerciseSummaryDTO.of(exercise, timeService)).collect(Collectors.toSet()); + return new WeeklySummaryMailContentDTO(hasNewExercises, exerciseSummaries); + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/weekly_summary_mail/WeeklySummaryMailRecipientDTO.java b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/weekly_summary_mail/WeeklySummaryMailRecipientDTO.java new file mode 100644 index 000000000000..783eaeecee38 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/communication/service/notifications/mails/dto/weekly_summary_mail/WeeklySummaryMailRecipientDTO.java @@ -0,0 +1,14 @@ +package de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.weekly_summary_mail; + +import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.IMailRecipientUserDTO; +import de.tum.cit.aet.artemis.core.domain.User; + +/** + * DTO for the weekly summary mail recipient. + */ +public record WeeklySummaryMailRecipientDTO(String langKey, String email, String name) implements IMailRecipientUserDTO { + + public static WeeklySummaryMailRecipientDTO of(User user) { + return new WeeklySummaryMailRecipientDTO(user.getLangKey(), user.getEmail(), user.getName()); + } +} diff --git a/src/main/resources/templates/mail/dataExportFailedAdminEmail.html b/src/main/resources/templates/mail/dataExportFailedAdminEmail.html index 14d68464eac7..e5f134dbee7d 100644 --- a/src/main/resources/templates/mail/dataExportFailedAdminEmail.html +++ b/src/main/resources/templates/mail/dataExportFailedAdminEmail.html @@ -10,10 +10,10 @@
A data export creation failed. - Username + Username failed -

The error message

+

The error message

diff --git a/src/main/resources/templates/mail/notification/fragments.html b/src/main/resources/templates/mail/notification/fragments.html index 266a4291c74b..10f9ea55601b 100644 --- a/src/main/resources/templates/mail/notification/fragments.html +++ b/src/main/resources/templates/mail/notification/fragments.html @@ -190,7 +190,7 @@ --> Dear - fullName + fullName
diff --git a/src/main/resources/templates/mail/successfulDataExportsAdminEmail.html b/src/main/resources/templates/mail/successfulDataExportsAdminEmail.html index 7903a1e51573..db7c78a60a75 100644 --- a/src/main/resources/templates/mail/successfulDataExportsAdminEmail.html +++ b/src/main/resources/templates/mail/successfulDataExportsAdminEmail.html @@ -10,12 +10,9 @@

Successful data exports

-
- -

+
+

- -
diff --git a/src/main/resources/templates/mail/weeklySummary.html b/src/main/resources/templates/mail/weeklySummary.html index a531ce2d5c58..bbe46cde71e7 100644 --- a/src/main/resources/templates/mail/weeklySummary.html +++ b/src/main/resources/templates/mail/weeklySummary.html @@ -13,21 +13,21 @@
This is your Artemis summary of the last seven days.
- +

There are no new exercises that are still open:

- +

All newly released exercises that are still open:

    - +
  • -

    +

      -
    • - +
    • +
    • - + @@ -40,15 +40,15 @@
    • - -
    • Release Date
    • + +
    • Release Date
    • - -
    • Due Date
    • + +
    • Due Date
    • -
    • Max Points
    • - -
    • Bonus Points
    • +
    • Max Points
    • + +
    • Bonus Points
  • diff --git a/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/MailServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/MailServiceTest.java index b29c998d6ee7..a245aa54de7b 100644 --- a/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/MailServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/MailServiceTest.java @@ -31,6 +31,7 @@ import de.tum.cit.aet.artemis.communication.domain.notification.NotificationConstants; import de.tum.cit.aet.artemis.communication.service.notifications.MailSendingService; import de.tum.cit.aet.artemis.communication.service.notifications.MailService; +import de.tum.cit.aet.artemis.communication.service.notifications.mails.dto.activation_mail.ActivationMailRecipientDTO; import de.tum.cit.aet.artemis.core.domain.Course; import de.tum.cit.aet.artemis.core.domain.User; import de.tum.cit.aet.artemis.core.service.TimeService; @@ -124,7 +125,7 @@ void setUp() throws MalformedURLException, URISyntaxException { */ @Test void testSendEmail() { - mailSendingService.sendEmail(student1, subject, content, false, true); + mailSendingService.sendEmail(ActivationMailRecipientDTO.of(student1), subject, content, false, true); verify(javaMailSender).send(any(MimeMessage.class)); } @@ -134,7 +135,7 @@ void testSendEmail() { @Test void testNoMailSendExceptionThrown() { doThrow(new MailSendException("Some error occurred during mail send")).when(javaMailSender).send(any(MimeMessage.class)); - assertThatNoException().isThrownBy(() -> mailSendingService.sendEmail(student1, subject, content, false, true)); + assertThatNoException().isThrownBy(() -> mailSendingService.sendEmail(ActivationMailRecipientDTO.of(student1), subject, content, false, true)); } /** diff --git a/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/AbstractMailContentTest.java b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/AbstractMailContentTest.java new file mode 100644 index 000000000000..6965aab4c304 --- /dev/null +++ b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/AbstractMailContentTest.java @@ -0,0 +1,61 @@ +package de.tum.cit.aet.artemis.communication.notifications.service.mail; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.verify; + +import org.junit.jupiter.api.BeforeEach; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.thymeleaf.spring6.SpringTemplateEngine; + +import de.tum.cit.aet.artemis.communication.service.notifications.MailSendingService; +import de.tum.cit.aet.artemis.communication.service.notifications.MailService; +import de.tum.cit.aet.artemis.core.domain.User; +import de.tum.cit.aet.artemis.core.service.TimeService; +import de.tum.cit.aet.artemis.shared.base.AbstractSpringIntegrationIndependentTest; + +/** + * Abstract class for testing mail content and the correct usage of DTO attributes in the mail content. + */ +class AbstractMailContentTest extends AbstractSpringIntegrationIndependentTest { + + protected MailService mailService; + + @Mock + protected MailSendingService mailSendingService; + + @Autowired + protected TimeService timeService; + + @Autowired + private SpringTemplateEngine templateEngine; + + @Autowired + private MessageSource messageSource; + + @BeforeEach + void setup() { + mailService = new MailService(messageSource, templateEngine, timeService, mailSendingService); + } + + /** + * All users attempted to receive a mail should have at least a language key set. + */ + protected User createMinimalMailRecipientUser() { + User recipient = new User(); + recipient.setLangKey("de"); + return recipient; + } + + /** + * Retrieve the content of the interpreted thymeleaf template, which represents the mail content. + */ + protected String getGeneratedEmailTemplateText() { + ArgumentCaptor contentCaptor = ArgumentCaptor.forClass(String.class); + verify(mailSendingService).sendEmail(any(), any(String.class), contentCaptor.capture(), anyBoolean(), anyBoolean()); + return contentCaptor.getValue(); + } +} diff --git a/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/ActivationMailTest.java b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/ActivationMailTest.java new file mode 100644 index 000000000000..b8bf8b39de18 --- /dev/null +++ b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/ActivationMailTest.java @@ -0,0 +1,29 @@ +package de.tum.cit.aet.artemis.communication.notifications.service.mail; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import de.tum.cit.aet.artemis.core.domain.User; + +class ActivationMailTest extends AbstractMailContentTest { + + /** + * Test that the variables injected in the template are used in the generated HTML content. + */ + @Test + void testThatVariablesAreInjectedIntoTheTemplate() { + // Arrange: + User recipient = createMinimalMailRecipientUser(); + recipient.setLogin("test_student"); + recipient.setActivationKey("test_key"); + + // Act: + mailService.sendActivationEmail(recipient); + + // Assert: + String capturedContent = getGeneratedEmailTemplateText(); + assertThat(capturedContent).contains("test_student"); + assertThat(capturedContent).contains("test_key"); + } +} diff --git a/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/DataExportFailedMailTest.java b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/DataExportFailedMailTest.java new file mode 100644 index 000000000000..8b80b5301cda --- /dev/null +++ b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/DataExportFailedMailTest.java @@ -0,0 +1,38 @@ +package de.tum.cit.aet.artemis.communication.notifications.service.mail; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import de.tum.cit.aet.artemis.core.domain.DataExport; +import de.tum.cit.aet.artemis.core.domain.User; + +class DataExportFailedMailTest extends AbstractMailContentTest { + + /** + * Test that the variables injected in the template are used in the generated HTML content. + */ + @Test + void testThatVariablesAreInjectedIntoTheTemplate() { + // Arrange: + User recipient = createMinimalMailRecipientUser(); + recipient.setLogin("test_login"); + + User dataExporSubjecttUser = new User(); + dataExporSubjecttUser.setLogin("test_subject"); + + DataExport dataExport = new DataExport(); + dataExport.setUser(dataExporSubjecttUser); + + Exception reason = new Exception("test_reason"); + + // Act: + mailService.sendDataExportFailedEmailToAdmin(recipient, dataExport, reason); + + // Assert: + String capturedContent = getGeneratedEmailTemplateText(); + assertThat(capturedContent).contains("test_login"); + assertThat(capturedContent).contains("test_subject"); + assertThat(capturedContent).contains("test_reason"); + } +} diff --git a/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/DataExportSuccessfulMailTest.java b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/DataExportSuccessfulMailTest.java new file mode 100644 index 000000000000..4a1e66a8b5f1 --- /dev/null +++ b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/DataExportSuccessfulMailTest.java @@ -0,0 +1,51 @@ +package de.tum.cit.aet.artemis.communication.notifications.service.mail; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import de.tum.cit.aet.artemis.core.domain.DataExport; +import de.tum.cit.aet.artemis.core.domain.User; + +class DataExportSuccessfulMailTest extends AbstractMailContentTest { + + /** + * Test that the variables injected in the template are used in the generated HTML content. + */ + @Test + void testThatVariablesAreInjectedIntoTheTemplate() { + // Arrange: + User recipient = createMinimalMailRecipientUser(); + recipient.setLogin("test_login"); + recipient.setResetKey("test_reset_key"); + Set dataExports = createThreeDataExportsWithThreeDifferentUsers(); + + // Act: + mailService.sendSuccessfulDataExportsEmailToAdmin(recipient, dataExports); + + // Assert: + String capturedContent = getGeneratedEmailTemplateText(); + assertThat(capturedContent).contains("test_subject_1"); + assertThat(capturedContent).contains("test_subject_2"); + assertThat(capturedContent).contains("test_subject_3"); + } + + private static Set createThreeDataExportsWithThreeDifferentUsers() { + User dataExportSubjectUser1 = new User(); + User dataExportSubjectUser2 = new User(); + User dataExportSubjectUser3 = new User(); + dataExportSubjectUser1.setLogin("test_subject_1"); + dataExportSubjectUser2.setLogin("test_subject_2"); + dataExportSubjectUser3.setLogin("test_subject_3"); + DataExport dataExport1 = new DataExport(); + DataExport dataExport2 = new DataExport(); + DataExport dataExport3 = new DataExport(); + dataExport1.setUser(dataExportSubjectUser1); + dataExport2.setUser(dataExportSubjectUser2); + dataExport3.setUser(dataExportSubjectUser3); + + return Set.of(dataExport1, dataExport2, dataExport3); + } +} diff --git a/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/PasswordResetMailTest.java b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/PasswordResetMailTest.java new file mode 100644 index 000000000000..4b65a90ee9aa --- /dev/null +++ b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/PasswordResetMailTest.java @@ -0,0 +1,29 @@ +package de.tum.cit.aet.artemis.communication.notifications.service.mail; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import de.tum.cit.aet.artemis.core.domain.User; + +class PasswordResetMailTest extends AbstractMailContentTest { + + /** + * Test that the variables injected in the template are used in the generated HTML content. + */ + @Test + void testThatVariablesAreInjectedIntoTheTemplate() { + // Arrange: + User recipient = createMinimalMailRecipientUser(); + recipient.setLogin("test_login"); + recipient.setResetKey("test_reset_key"); + + // Act: + mailService.sendPasswordResetMail(recipient); + + // Assert: + String capturedContent = getGeneratedEmailTemplateText(); + assertThat(capturedContent).contains("test_login"); + assertThat(capturedContent).contains("test_reset_key"); + } +} diff --git a/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/SAML2SetPasswordMailTest.java b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/SAML2SetPasswordMailTest.java new file mode 100644 index 000000000000..7b9ec3d97ecb --- /dev/null +++ b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/SAML2SetPasswordMailTest.java @@ -0,0 +1,29 @@ +package de.tum.cit.aet.artemis.communication.notifications.service.mail; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import de.tum.cit.aet.artemis.core.domain.User; + +class SAML2SetPasswordMailTest extends AbstractMailContentTest { + + /** + * Test that the variables injected in the template are used in the generated HTML content. + */ + @Test + void testThatVariablesAreInjectedIntoTheTemplate() { + // Arrange: + User recipient = createMinimalMailRecipientUser(); + recipient.setLogin("test_login"); + recipient.setResetKey("test_reset_key"); + + // Act: + mailService.sendSAML2SetPasswordMail(recipient); + + // Assert: + String capturedContent = getGeneratedEmailTemplateText(); + assertThat(capturedContent).contains("test_login"); + assertThat(capturedContent).contains("test_reset_key"); + } +} diff --git a/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/WeeklySummaryMailTest.java b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/WeeklySummaryMailTest.java new file mode 100644 index 000000000000..537fc7ab71a3 --- /dev/null +++ b/src/test/java/de/tum/cit/aet/artemis/communication/notifications/service/mail/WeeklySummaryMailTest.java @@ -0,0 +1,75 @@ +package de.tum.cit.aet.artemis.communication.notifications.service.mail; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.ZonedDateTime; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import de.tum.cit.aet.artemis.core.domain.User; +import de.tum.cit.aet.artemis.exercise.domain.DifficultyLevel; +import de.tum.cit.aet.artemis.exercise.domain.Exercise; +import de.tum.cit.aet.artemis.quiz.domain.QuizExercise; +import de.tum.cit.aet.artemis.text.domain.TextExercise; + +class WeeklySummaryMailTest extends AbstractMailContentTest { + + /** + * Test that the variables injected in the template are used in the generated HTML content. + */ + @Test + void testThatVariablesAreInjectedIntoTheTemplate() { + // Arrange: + User recipient = createMinimalMailRecipientUser(); + recipient.setLogin("test_login"); + recipient.setResetKey("test_reset_key"); + + ZonedDateTime dueDateTime = ZonedDateTime.now().plusDays(1); + ZonedDateTime releaseDateTime = ZonedDateTime.now().minusDays(1); + + Exercise easyExercise = new TextExercise(); + easyExercise.setTitle("easy_exercise"); + easyExercise.setDifficulty(DifficultyLevel.EASY); + easyExercise.setReleaseDate(releaseDateTime); + easyExercise.setDueDate(dueDateTime); + easyExercise.setBonusPoints(0.0); + easyExercise.setMaxPoints(101.0); + + Exercise mediumExercise = new QuizExercise(); + mediumExercise.setTitle("medium_exercise"); + mediumExercise.setDifficulty(DifficultyLevel.MEDIUM); + mediumExercise.setReleaseDate(releaseDateTime); + mediumExercise.setDueDate(dueDateTime); + mediumExercise.setBonusPoints(12.0); + mediumExercise.setMaxPoints(201.0); + + Exercise hardExercise = new QuizExercise(); + hardExercise.setTitle("hard_exercise"); + hardExercise.setDifficulty(DifficultyLevel.HARD); + hardExercise.setReleaseDate(releaseDateTime); + hardExercise.setDueDate(dueDateTime); + hardExercise.setBonusPoints(13.0); + hardExercise.setMaxPoints(301.0); + + Set exercises = Set.of(easyExercise, mediumExercise, hardExercise); + + // Act: + mailService.sendWeeklySummaryEmail(recipient, exercises); + + // Assert: + String capturedContent = getGeneratedEmailTemplateText(); + for (Exercise e : exercises) { + String dueDateFormat = timeService.convertToHumanReadableDate(e.getDueDate()); + String releaseDateFormat = timeService.convertToHumanReadableDate(e.getReleaseDate()); + + assertThat(capturedContent).contains(e.getTitle()); + assertThat(capturedContent).contains(e.getType()); + assertThat(capturedContent).containsAnyOf("Schwer", "Mittel", "Leicht"); + assertThat(capturedContent).contains(String.format("%.0f", e.getBonusPoints())); + assertThat(capturedContent).contains(String.format("%.0f", e.getMaxPoints())); + assertThat(capturedContent).contains(dueDateFormat); + assertThat(capturedContent).contains(releaseDateFormat); + } + } +} diff --git a/src/test/java/de/tum/cit/aet/artemis/core/service/DataExportScheduleServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/core/service/DataExportScheduleServiceTest.java index aac8fe17f6ec..38873bbd0bbe 100644 --- a/src/test/java/de/tum/cit/aet/artemis/core/service/DataExportScheduleServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/core/service/DataExportScheduleServiceTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyLong; -import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; @@ -84,7 +83,7 @@ void testScheduledCronTaskSendsEmailToAdminAboutSuccessfulDataExports() throws I doThrow(new RuntimeException("error")).doNothing().doNothing().when(fileService).scheduleDirectoryPathForRecursiveDeletion(any(Path.class), anyLong()); dataExportScheduleService.createDataExportsAndDeleteOldOnes(); var dataExportsAfterCreation = dataExportRepository.findAllSuccessfullyCreatedDataExports(); - verify(mailService).sendSuccessfulDataExportsEmailToAdmin(any(User.class), anyString(), anyString(), eq(Set.copyOf(dataExportsAfterCreation))); + verify(mailService).sendSuccessfulDataExportsEmailToAdmin(any(User.class), eq(Set.copyOf(dataExportsAfterCreation))); }