From db642103ed4fd013b59de48eb9838d402e115bbf Mon Sep 17 00:00:00 2001 From: akastijn Date: Sat, 16 Aug 2025 20:23:35 +0200 Subject: [PATCH] Add email notification service for appeals using Spring Mail and Thymeleaf templates. --- backend/build.gradle.kts | 2 + .../altitudeweb/AltitudeWebApplication.java | 2 +- .../controllers/forms/AppealController.java | 4 ++ .../altitudeweb/services/mail/AppealMail.java | 61 +++++++++++++++++++ .../src/main/resources/application.properties | 7 +++ .../resources/templates/appeal-email.html | 25 ++++++++ 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/com/alttd/altitudeweb/services/mail/AppealMail.java create mode 100644 backend/src/main/resources/templates/appeal-email.html diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index 67f6178..972a7e3 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -36,6 +36,8 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.security:spring-security-oauth2-resource-server") implementation("org.springframework.security:spring-security-oauth2-jose") + implementation("org.springframework.boot:spring-boot-starter-mail:3.1.5") + implementation("org.springframework.boot:spring-boot-starter-thymeleaf") //AOP implementation("org.aspectj:aspectjrt:1.9.19") diff --git a/backend/src/main/java/com/alttd/altitudeweb/AltitudeWebApplication.java b/backend/src/main/java/com/alttd/altitudeweb/AltitudeWebApplication.java index 6829afb..ad7971a 100644 --- a/backend/src/main/java/com/alttd/altitudeweb/AltitudeWebApplication.java +++ b/backend/src/main/java/com/alttd/altitudeweb/AltitudeWebApplication.java @@ -5,7 +5,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.EnableAspectJAutoProxy; -@SpringBootApplication +@SpringBootApplication(scanBasePackages = {"com.alttd.altitudeweb"}) @EnableAspectJAutoProxy public class AltitudeWebApplication { diff --git a/backend/src/main/java/com/alttd/altitudeweb/controllers/forms/AppealController.java b/backend/src/main/java/com/alttd/altitudeweb/controllers/forms/AppealController.java index 0531357..f019e01 100644 --- a/backend/src/main/java/com/alttd/altitudeweb/controllers/forms/AppealController.java +++ b/backend/src/main/java/com/alttd/altitudeweb/controllers/forms/AppealController.java @@ -10,6 +10,7 @@ import com.alttd.altitudeweb.model.DiscordAppealDto; import com.alttd.altitudeweb.model.MinecraftAppealDto; import com.alttd.altitudeweb.model.UpdateMailDto; import com.alttd.altitudeweb.services.limits.RateLimit; +import com.alttd.altitudeweb.services.mail.AppealMail; import com.alttd.altitudeweb.setup.Connection; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -29,6 +30,7 @@ import java.util.concurrent.TimeUnit; public class AppealController implements AppealsApi { private final AppealDataMapper mapper; + private final AppealMail appealMail; @RateLimit(limit = 3, timeValue = 1, timeUnit = TimeUnit.HOURS, key = "discordAppeal") @Override @@ -55,6 +57,8 @@ public class AppealController implements AppealsApi { }); Appeal appeal = appealCompletableFuture.join(); + appealMail.sendAppealNotification(appeal); + AppealResponseDto appealResponseDto = new AppealResponseDto( appeal.id().toString(), "Your appeal has been submitted. You will be notified when it has been reviewed.", diff --git a/backend/src/main/java/com/alttd/altitudeweb/services/mail/AppealMail.java b/backend/src/main/java/com/alttd/altitudeweb/services/mail/AppealMail.java new file mode 100644 index 0000000..9330fb3 --- /dev/null +++ b/backend/src/main/java/com/alttd/altitudeweb/services/mail/AppealMail.java @@ -0,0 +1,61 @@ +package com.alttd.altitudeweb.services.mail; + +import com.alttd.altitudeweb.database.web_db.forms.Appeal; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Service; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring6.SpringTemplateEngine; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AppealMail { + + private final JavaMailSender mailSender; + + @Value("${spring.mail.username}") + private String fromEmail; + + private static final String APPEAL_EMAIL = "appeal@alttd.com"; + + /** + * Sends an email notification about the appeal to both the user and the appeals team. + * + * @param appeal The appeal object containing all necessary information + */ + public void sendAppealNotification(Appeal appeal) { + try { + sendEmailToAppealsTeam(appeal); + + log.info("Appeal notification emails sent successfully for appeal ID: {}", appeal.id()); + } catch (Exception e) { + log.error("Failed to send appeal notification emails for appeal ID: {}", appeal.id(), e); + } + } + + private SpringTemplateEngine templateEngine; + + private void sendEmailToAppealsTeam(Appeal appeal) throws MessagingException { + MimeMessage message = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message, true); + + helper.setFrom(fromEmail); + helper.setTo(APPEAL_EMAIL); + helper.setReplyTo(appeal.email()); + helper.setSubject("New Appeal Submitted - " + appeal.username()); + + Context context = new Context(); + context.setVariable("appeal", appeal); + String content = templateEngine.process("appeal-email", context); + + helper.setText(content, true); + mailSender.send(message); + } + +} diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index df73a04..7b994e5 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -10,3 +10,10 @@ particles.file_path=${user.home}/.altitudeweb/particles notification.server.url=${SERVER_IP:10.0.0.107}:${SERVER_PORT:8080} my-server.address=${SERVER_ADDRESS:https://alttd.com} logging.level.com.alttd.altitudeweb=INFO +discord.token=${DISCORD_TOKEN} +spring.mail.host=${MAIL_HOST:smtp.zoho.com} +spring.mail.port=${MAIL_PORT:465} +spring.mail.username=${MAIL_USER} +spring.mail.password=${MAIL_PASSWORD} +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.starttls.enable=true diff --git a/backend/src/main/resources/templates/appeal-email.html b/backend/src/main/resources/templates/appeal-email.html new file mode 100644 index 0000000..56deb00 --- /dev/null +++ b/backend/src/main/resources/templates/appeal-email.html @@ -0,0 +1,25 @@ + + + + + Appeal Notification + + + +

Appeal by Username

+

Punishment information

+ +

Appeal:

+

Reason text

+ +