Skip to content

Commit

Permalink
Refactor EmailService class:
Browse files Browse the repository at this point in the history
Improve method names for clarity.
Extract common HTML generation logic to a separate method.
Use constants for repeated strings.
Add JavaDoc comments for public methods.
Enhance error handling and logging in saveNewAnalyticsRecords method.
  • Loading branch information
LeonardoMeireles55 committed Jan 21, 2025
1 parent 942e068 commit 72d5168
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package leonardo.labutilities.qualitylabpro.services.analytics;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -211,32 +210,31 @@ public abstract List<AnalyticsRecord> findAnalyticsByNameAndLevel(Pageable pagea

@Override
public void saveNewAnalyticsRecords(List<AnalyticsRecord> valuesOfLevelsList) {
List<leonardo.labutilities.qualitylabpro.entities.Analytics> newAnalytics =
valuesOfLevelsList.stream().filter(this::isAnalyticsNonExistent)
.map(AnalyticsMapper::toEntity)
.collect(Collectors.toList());
var newAnalytics = valuesOfLevelsList.stream()
.filter(this::isAnalyticsNonExistent)
.map(AnalyticsMapper::toEntity)
.collect(Collectors.toList());

if (newAnalytics.isEmpty()) {
log.warn("No new analytics records to save.");
throw new CustomGlobalErrorHandling.DataIntegrityViolationException();
}

var analyticsList = analyticsRepository.saveAll(newAnalytics);
log.info("New analytics records saved: {}...", analyticsList.get(0).toString());

var notPassedList = analyticsList.stream()
.map(AnalyticsMapper::toRecord).filter(this::isRecordStd3s).toList();
.map(AnalyticsMapper::toRecord)
.filter(this::isRecordStd3s)
.toList();

if (!notPassedList.isEmpty()) {
String formattedList = notPassedList.stream()
.map(record -> String.format(
"name: %s:, level: %s, value: %s, expected value: %s, rules: %s, status: %s, at: %s\n Recommendation: Please review the test procedures and ensure all equipment is calibrated.",
record.name(), record.level(), record.value().toString(), record.mean().toString(), record.rules(), record.description(), record.date().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))))
.collect(Collectors.joining("\n"));
String emailBody = String.format(
"Dear Team,\n\nThe following analytics records did not pass the standard deviation criteria:\n\n%s\n\nPlease take the necessary actions to address these issues.",
formattedList);
emailService.sendEmail(new EmailRecord("[email protected]", "Warning: Analytics Not Passed", emailBody));
String emailBody = emailService.generateAnalyticsFailedEmailBody(notPassedList);
emailService.sendHtmlEmail(new EmailRecord("[email protected]", "Warning: Analytics Not Passed", emailBody));
}
}


@Override
public Page<AnalyticsRecord> findAnalytics(Pageable pageable) {
return analyticsRepository.findPaged(pageable);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,114 @@
package leonardo.labutilities.qualitylabpro.services.email;

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import leonardo.labutilities.qualitylabpro.dtos.analytics.AnalyticsRecord;
import leonardo.labutilities.qualitylabpro.dtos.email.EmailRecord;
import lombok.extern.slf4j.Slf4j;
import lombok.RequiredArgsConstructor;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Slf4j
@Service
public class EmailService {
private static final String EMAIL_SUBJECT_PREFIX = "LabGraph - ";
private static final String HTML_TEMPLATE = "<html><head></head><body>%s</body></html>";
private static final String TABLE_STYLE = "<style>table { border-collapse: collapse; width: 100%%; } th, td { border: 1px solid black; padding: 8px; text-align: left; } th { background-color: #f2f2f2; } tr:nth-child(even) { background-color: #f9f9f9; }</style>";

private final JavaMailSender javaMailSender;

@Value("${spring.mail.username}")
private String emailFrom;

/**
* Sends a plain text email.
*
* @param email the email record containing recipient, subject, and body
*/
@Async
public void sendEmail(EmailRecord email) {
var message = new SimpleMailMessage();
public void sendPlainTextEmail(EmailRecord email) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(emailFrom);
message.setTo(email.to());
message.setSubject("LabGraph - " + email.subject());
message.setSubject(EMAIL_SUBJECT_PREFIX + email.subject());
message.setText(buildEmailBody(email));
javaMailSender.send(message);
}

/**
* Sends an email with an HTML body.
*
* @param email the email record containing recipient, subject, and body
*/
@Async
public void sendHtmlEmail(EmailRecord email) {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(emailFrom);
helper.setTo(email.to());
helper.setSubject(EMAIL_SUBJECT_PREFIX + email.subject());
helper.setText(buildEmailBody(email), true); // true indicates HTML
javaMailSender.send(mimeMessage);
} catch (MessagingException e) {
log.error("Failed to send email with HTML body", e);
}
}

/**
* Generates the email body for analytics records that failed.
*
* @param notPassedList the list of analytics records that did not pass
* @return the generated HTML email body
*/
public String generateAnalyticsFailedEmailBody(List<AnalyticsRecord> notPassedList) {
String formattedList = notPassedList.stream()
.map(record -> String.format(
"<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>",
record.name(), record.level(), record.value().toString(), record.mean().toString(), record.rules(),
record.description(), record.date().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))))
.collect(Collectors.joining("\n"));
return String.format(HTML_TEMPLATE,
TABLE_STYLE +
"<p>The following analytics records did not pass the standard deviation criteria:</p>" +
"<table><tr><th>Name</th><th>Level</th><th>Value</th><th>Expected Value</th><th>Rules</th><th>Status</th><th>Date</th></tr>" +
formattedList +
"</table><p>Please take the necessary actions to address these issues.</p>");
}

public String generateUserLoginEmailBody(String username, String email, String date) {
return generateUserActionEmailBody("logged in", username, email, date);
}

public String generateUserCreationEmailBody(String username, String email, String date) {
return generateUserActionEmailBody("been created", username, email, date);
}

public String generateUserDeletionEmailBody(String username, String email, String date) {
return generateUserActionEmailBody("been deleted", username, email, date);
}

public String generateUserUpdateEmailBody(String username, String email, String date) {
return generateUserActionEmailBody("been updated", username, email, date);
}

private String generateUserActionEmailBody(String action, String username, String email, String date) {
return String.format(HTML_TEMPLATE,
String.format("<p>User <b>%s</b> has %s with email <b>%s</b> at <b>%s</b>.</p>",
username, action, email, date));
}

private String buildEmailBody(EmailRecord email) {
return String.format("\n\n%s\n\nBest regards,\nLabGraph Team",
email.body());
return String.format("\n\n%s\n\nBest regards,\nLabGraph Team", email.body());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private void sendRecoveryEmail(RecoveryEmailRecord recoveryEmailRecord) {
"Dear user,\n\nUse the following temporary password to recover your account: %s\n\nBest regards,\nYour Team",
recoveryEmailRecord.temporaryPassword());
log.info("Sending recovery email to: {}", recoveryEmailRecord.email());
emailService.sendEmail(new EmailRecord(recoveryEmailRecord.email(), subject, message));
emailService.sendPlainTextEmail(new EmailRecord(recoveryEmailRecord.email(), subject, message));
}

public void recoverPassword(String username, String email) {
Expand Down Expand Up @@ -76,9 +76,9 @@ public TokenJwtRecord signIn(String email, String password) {
final var authToken = new UsernamePasswordAuthenticationToken(email, password);
final var auth = authenticationManager.authenticate(authToken);
final var user = (User) auth.getPrincipal();
String message = String.format("Hello!,\n\nYou have successfully logged in on %s.", java.time.LocalDateTime.now()
String message = String.format("Hello There!\nYou have successfully logged on %s.", java.time.LocalDateTime.now()
.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
emailService.sendEmail(new EmailRecord(user.getEmail(), "Login Notification", message));
emailService.sendPlainTextEmail(new EmailRecord(user.getEmail(), "Login Notification", message));

return new TokenJwtRecord(tokenService.generateToken(user));
}
Expand Down

0 comments on commit 72d5168

Please sign in to comment.