Skip to content
Snippets Groups Projects
Commit 73fe8671 authored by Michal Badin's avatar Michal Badin
Browse files

Merge branch 'mailing' into 'develop'

Thymeleaf

See merge request !51
parents 7ed78935 3e943339
No related branches found
No related tags found
2 merge requests!54Merge develop into main,!51Thymeleaf
Pipeline #
......@@ -116,6 +116,10 @@
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
</project>
......@@ -2,9 +2,17 @@ package cz.muni.pa165.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.thymeleaf.templateresolver.ITemplateResolver;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Properties;
@Configuration
......@@ -26,4 +34,21 @@ public class MailConfig {
return mailSender;
}
@Bean
public TemplateEngine emailTemplateEngine() {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
return templateEngine;
}
private ITemplateResolver htmlTemplateResolver() {
final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/templates/");
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(false);
return templateResolver;
}
}
\ No newline at end of file
package cz.muni.pa165.exceptions;
/**
* @author Michal Badin
*/
public class EmailException extends RuntimeException {
public EmailException(String message, Throwable cause) {
super(message, cause);
}
}
package cz.muni.pa165.service;
import cz.muni.pa165.exceptions.EmailException;
import cz.muni.pa165.generated.model.*;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
@Service
public class NotificationService {
private static final String EMAIL = "formula.team.management@gmail.com";
private static final Logger log = LoggerFactory.getLogger(NotificationService.class);
private final JavaMailSender emailSender;
private final TemplateEngine templateEngine;
@Autowired
public NotificationService(JavaMailSender emailSender) {
public NotificationService(JavaMailSender emailSender, TemplateEngine templateEngine) {
this.emailSender = emailSender;
this.templateEngine = templateEngine;
}
public ConfirmationDto notify(NotificationDto notificationDto) {
......@@ -25,80 +38,73 @@ public class NotificationService {
public ConfirmationDto notifyNewComponent(CarComponentNotificationDto carComponentNotificationDto) {
var c = carComponentNotificationDto.getCarComponent();
var subject = "New component: " + c.getInformation();
var text = "New component was added to Formula team management core.\n"
+ "\nType: " + c.getComponentType()
+ "\nInformation: " + c.getInformation()
+ "\nWeight: " + c.getWeight();
return sendEmail(subject, text, carComponentNotificationDto.getReceivers());
Context ctx = new Context();
ctx.setVariable("id", c.getId());
ctx.setVariable("type", c.getComponentType());
ctx.setVariable("info", c.getInformation());
ctx.setVariable("weight", c.getWeight());
var htmlContent = templateEngine.process("new-component-email", ctx);
return sendEmail(subject, htmlContent, carComponentNotificationDto.getReceivers());
}
public ConfirmationDto notifyNewApplication(ApplicationNotificationDto applicationNotificationDto) {
var a = applicationNotificationDto.getApplication();
var subject = "New application: " + getFullName(a);
var text = "New application was received.\n"
+ "\nId: " + a.getId()
+ "\nName: " + a.getName()
+ "\nSurname: " + a.getSurname()
+ "\nBirthday: " + a.getBirthday()
+ "\nEmail: " + a.getEmail()
+ "\nFilling out date: " + a.getFillingOutDate();
Context ctx = new Context();
ctx.setVariable("id", a.getId());
ctx.setVariable("name", a.getName());
ctx.setVariable("surname", a.getSurname());
ctx.setVariable("birthday", a.getBirthday().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
ctx.setVariable("email", a.getEmail());
ctx.setVariable("fillingOutDate", a.getFillingOutDate().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
return sendEmail(subject, text, applicationNotificationDto.getReceivers());
var htmlContent = templateEngine.process("new-application-email", ctx);
return sendEmail(subject, htmlContent, applicationNotificationDto.getReceivers());
}
public ConfirmationDto notifyApplicationStatusChange(ApplicationNotificationDto applicationNotificationDto) {
var a = applicationNotificationDto.getApplication();
var subject = "Application for Formula Driver Position";
var text = "";
var htmlContent = "";
Context ctx = new Context();
ctx.setVariable("fullName", getFullName(a));
ctx.setVariable("today", LocalDate.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
if (a.getStatus() == ApplicationStatus.ACCEPTED) {
text = "Dear " + getFullName(a) + ",\n" +
"\n" +
"I am pleased to inform you that your application for the position of Formula Driver has been accepted. We are excited to have you join our team and look forward to working with you.\n" +
"\n" +
"Your experience, skills, and passion for racing make you an excellent fit for our team. We believe that you will be a valuable asset to our organization and we are eager to see what you can accomplish on the track.\n" +
"\n" +
"As a next step, we will contact you shortly to discuss the details of your employment contract and to schedule your training and orientation. In the meantime, please do not hesitate to contact us if you have any questions or concerns.\n" +
"\n" +
"Thank you for your interest in our team and for taking the time to apply. We look forward to a long and successful partnership with you.\n" +
"\n" +
"Best regards,\n" +
"\n" +
"Formula Team Management";
htmlContent = templateEngine.process("accepted-email", ctx);
} else {
text = "Dear " + getFullName(a) + ",\n" +
"\n" +
"I regret to inform you that your application for the Formula Driver position has been declined. While we appreciate your interest in the role, we have decided to pursue other candidates whose skills and experience more closely match our requirements.\n" +
"\n" +
"I want to personally thank you for taking the time to apply for the position and for your passion for motorsports. We would like to keep your resume on file in case any suitable openings arise in the future.\n" +
"\n" +
"If you have any questions or would like feedback on your application, please feel free to reach out to us.\n" +
"\n" +
"Thank you again for considering Formula Team Management, and we wish you all the best in your future endeavors.\n" +
"\n" +
"Best regards,\n" +
"\n" +
"Formula Team Management";
htmlContent = templateEngine.process("rejected-email", ctx);
}
return sendEmail(subject, text, applicationNotificationDto.getReceivers());
return sendEmail(subject, htmlContent, applicationNotificationDto.getReceivers());
}
private ConfirmationDto sendEmail(String subject, String content, List<String> receivers) {
var message = new SimpleMailMessage();
message.setFrom(EMAIL);
message.setTo(receivers.toArray(String[]::new));
message.setSubject(subject);
message.setText(content);
emailSender.send(message);
return new ConfirmationDto()
.sender(EMAIL)
.receivers(receivers)
.subject(subject)
.message(content);
private ConfirmationDto sendEmail(String subject, String text, List<String> receivers) {
MimeMessage message = emailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true, StandardCharsets.UTF_8.name());
helper.setFrom(EMAIL);
helper.setTo(receivers.toArray(String[]::new));
helper.setSubject(subject);
helper.setText(text, true);
emailSender.send(message);
return new ConfirmationDto()
.sender(EMAIL)
.receivers(receivers)
.subject(subject)
.message(text);
} catch (MessagingException e) {
throw new EmailException("Failed to send email", e);
}
}
private String getFullName(ApplicationDto applicationDto) {
......
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="utf-8">
<title>Application for Formula Driver Position</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f6f6f6;
}
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.header-right {
margin-left: auto;
}
.container {
max-width: 625px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
h1 {
font-size: 24px;
font-weight: bold;
margin: 0;
text-align: left;
}
.date {
font-size: 14px;
font-weight: normal;
margin: 0;
}
.location {
font-size: 14px;
font-weight: normal;
margin: 0;
}
p {
font-size: 16px;
line-height: 1.5;
margin: 20px 0;
text-align: justify;
}
.signature {
font-size: 14px;
font-weight: normal;
margin: 50px 0 0 0;
text-align: right;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Application for Formula Driver Position</h1>
<div class="header-right">
<div class="date" th:text="${today}"></div>
<div class="location">Brno, Czech Republic</div>
</div>
</div>
<p><b>Dear <span th:text="${fullName}"></span>,</b></p>
<p>I am pleased to inform you that your application for the position of Formula Driver has been <b>Accepted</b>. We are excited to have you join our team and look forward to working with you.</p>
<p>Your experience, skills, and passion for racing make you an excellent fit for our team. We believe that you will be a valuable asset to our organization and we are eager to see what you can accomplish on the track.</p>
<p>As a next step, we will contact you shortly to discuss the details of your employment contract and to schedule your training and orientation. In the meantime, please do not hesitate to contact us if you have any questions or concerns.</p>
<p>Thank you for your interest in our team and for taking the time to apply. We look forward to a long and successful partnership with you.</p>
<p>Best regards,
<br>Formula Team Management</p>
<div class="signature">-- Formula Team Management</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="utf-8">
<title>Application for Formula Driver Position</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f6f6f6;
}
.container {
max-width: 625px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
h1 {
font-size: 24px;
font-weight: bold;
margin: 0;
text-align: left;
}
p {
font-size: 16px;
line-height: 1.5;
margin: 20px 0;
text-align: justify;
}
</style>
</head>
<body>
<div class="container">
<h1>New Application Received</h1>
<table>
<tr>
<td>Id:</td>
<td th:text="${id}"></td>
</tr>
<tr>
<td>Name:</td>
<td th:text="${name}"></td>
</tr>
<tr>
<td>Surname:</td>
<td th:text="${surname}"></td>
</tr>
<tr>
<td>Birthday:</td>
<td th:text="${birthday}"></td>
</tr>
<tr>
<td>Email:</td>
<td th:text="${email}"></td>
</tr>
<tr>
<td>Filling out date:</td>
<td th:text="${fillingOutDate}"></td>
</tr>
</table>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="utf-8">
<title>Application for Formula Driver Position</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f6f6f6;
}
.container {
max-width: 625px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
h1 {
font-size: 24px;
font-weight: bold;
margin: 0;
text-align: left;
}
p {
font-size: 16px;
line-height: 1.5;
margin: 20px 0;
text-align: justify;
}
</style>
</head>
<body>
<div class="container">
<h1>New component was added to Formula team management core</h1>
<table>
<tr>
<td>Id:</td>
<td th:text="${id}"></td>
</tr>
<tr>
<td>Component type:</td>
<td th:text="${type}"></td>
</tr>
<tr>
<td>Information:</td>
<td th:text="${info}"></td>
</tr>
<tr>
<td>Weight:</td>
<td th:text="${weight} + 'kg'"></td>
</tr>
</table>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="utf-8">
<title>Application for Formula Driver Position</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f6f6f6;
}
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.header-right {
margin-left: auto;
}
.container {
max-width: 625px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: relative;
}
h1 {
font-size: 24px;
font-weight: bold;
margin: 0;
text-align: left;
}
.date {
font-size: 14px;
font-weight: normal;
margin: 0;
}
.location {
font-size: 14px;
font-weight: normal;
margin: 0;
}
p {
font-size: 16px;
line-height: 1.5;
margin: 20px 0;
text-align: justify;
}
.signature {
font-size: 14px;
font-weight: normal;
margin: 50px 0 0 0;
text-align: right;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Application for Formula Driver Position</h1>
<div class="header-right">
<div class="date" th:text="${today}"></div>
<div class="location">Brno, Czech Republic</div>
</div>
</div>
<p><b>Dear <span th:text="${fullName}"></span>,</b></p>
<p>I regret to inform you that your application for the Formula Driver position has been <b>Declined</b>. While we appreciate your interest in the role, we have decided to pursue other candidates whose skills and experience more closely match our requirements.</p>
<p>I want to personally thank you for taking the time to apply for the position and for your passion for motorsports. We would like to keep your resume on file in case any suitable openings arise in the future.</p>
<p>If you have any questions or would like feedback on your application, please feel free to reach out to us.</p>
<p>Thank you again for considering Formula Team Management, and we wish you all the best in your future endeavors.</p>
<p>Best regards,
<br>Formula Team Management</p>
<div class="signature">-- Formula Team Management</div>
</div>
</body>
</html>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment