Files
no-copy/src/main/java/ru/soune/nocopy/service/mail/EmailService.java
T

164 lines
6.2 KiB
Java
Raw Normal View History

2026-01-20 03:47:51 +07:00
package ru.soune.nocopy.service.mail;
2026-01-23 16:09:51 +07:00
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
2026-01-19 19:26:59 +07:00
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.soune.nocopy.entity.user.AuthToken;
import ru.soune.nocopy.entity.user.EmailVerificationToken;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.repository.EmailVerificationTokenRepository;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.time.LocalDateTime;
2026-03-05 14:27:14 +07:00
import java.util.Map;
@Service
@RequiredArgsConstructor
@Slf4j
public class EmailService {
private final JavaMailSender mailSender;
private final EmailVerificationTokenRepository emailVerificationTokenRepository;
2026-01-20 03:47:51 +07:00
@Value("${app.email.verification.standart-subject}")
private String standartSubject;
@Value("${app.email.verification.standart-address-from}")
private String standartAdressFrom;
@Value("${app.email.verification.user}")
private String user;
2026-02-17 20:17:34 +07:00
@Value("${app.email.verification.drop-password-subject}")
private String dropPasswordSubject;
2026-03-07 01:36:31 +07:00
// @Value("${server.baseurl}")
// private String baseUrl;
@Value("${BASE_URL}")
2026-02-20 10:50:44 +07:00
private String baseUrl;
@Value("${server.front.port}")
private String frontPort;
2026-03-05 14:27:14 +07:00
public void sendEmail(String from, String sendTo, String subject, String body) throws MessagingException {
2026-01-23 16:09:51 +07:00
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
2026-03-05 14:27:14 +07:00
helper.setFrom(from);
helper.setTo(sendTo);
helper.setSubject(subject);
helper.setText(body, true);
2026-01-23 16:09:51 +07:00
mailSender.send(message);
}
2026-03-05 14:27:14 +07:00
public void sendVerificationEmail(User user, String code) throws MessagingException, IOException {
String htmlContent = loadAndProcessTemplate(Map.of("username", user.getFullName(), "code", code),
"templates/email-verification.html");
sendEmail("noreply@no-copy.ru", user.getEmail(), standartAdressFrom, htmlContent);
}
public void sendTokensNotFoundEmail(User user, Integer currentTokens, Integer missingTokens)
throws MessagingException, IOException {
String htmlContent = loadAndProcessTemplate(Map.of("username", user.getFullName(),
"current_tokens", String.valueOf(currentTokens), "missing_tokens",
String.valueOf(missingTokens), "link_to_token_board", baseUrl + "/pages/payment"),
"templates/token-not-found.html");
sendEmail("noreply@no-copy.ru", user.getEmail(), standartAdressFrom, htmlContent);
}
@Transactional
public EmailVerificationToken createEmailVerificationToken(AuthToken authToken) {
2026-02-20 11:11:24 +07:00
EmailVerificationToken existingToken = emailVerificationTokenRepository
.findByUserId(authToken.getUser().getId());
if (existingToken != null) {
emailVerificationTokenRepository.deleteById(existingToken.getId());
}
EmailVerificationToken emailToken = new EmailVerificationToken();
emailToken.setUser(authToken.getUser());
emailToken.setToken(generateVerificationCode());
emailToken.setCreatedAt(LocalDateTime.now());
return emailVerificationTokenRepository.save(emailToken);
}
private String generateVerificationCode() {
SecureRandom random = new SecureRandom();
int code = 100000 + random.nextInt(900000);
return String.valueOf(code);
}
2026-02-17 20:17:34 +07:00
private String loadAndProcessTemplate(String username, String code, String templatePath) throws IOException {
ClassPathResource resource = new ClassPathResource(templatePath);
String template = new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
2026-01-20 03:47:51 +07:00
String safeUsername = escapeHtml(username != null ? username : user);
String safeCode = escapeHtml(code);
return template
.replace("{{username}}", safeUsername)
.replace("{{code}}", safeCode);
}
2026-03-05 14:27:14 +07:00
private String loadAndProcessTemplate(Map<String, String> fieldsForTemplate, String templatePath) throws IOException {
ClassPathResource resource = new ClassPathResource(templatePath);
String template = new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
for (Map.Entry<String, String> entry : fieldsForTemplate.entrySet()) {
template = template.replace("{{" + entry.getKey() + "}}", escapeHtml(entry.getValue()));
}
return template;
}
private String escapeHtml(String text) {
if (text == null) return "";
return text
.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
.replace("\"", "&quot;")
.replace("'", "&#39;");
}
2026-02-17 20:17:34 +07:00
public void sendResetPasswordEmail(User user, String code) {
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setFrom(standartAdressFrom);
helper.setTo(user.getEmail());
helper.setSubject(dropPasswordSubject);
String htmlContent = loadAndProcessTemplate(user.getFullName(), code,
"templates/reset-password.html");
2026-02-20 11:19:54 +07:00
//TODO frontPort убрать после настройки редиректа nginx
2026-03-05 10:26:53 +07:00
String resetLink = escapeHtml(baseUrl + "/reset-password?email=" + user.getEmail());
2026-02-20 10:50:44 +07:00
htmlContent = htmlContent.replace("{{resetLink}}", resetLink);
2026-02-17 20:17:34 +07:00
helper.setText(htmlContent, true);
mailSender.send(message);
log.info("Email sent to: {}", user.getEmail());
} catch (Exception e) {
log.error("Failed to send email: {}", e.getMessage());
}
}
}