Verschiebung nach anderem RePo - nun pro Projekt getrennt

This commit is contained in:
2026-04-01 10:41:19 +02:00
commit 7b9eda1d62
1048 changed files with 93351 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
package de.oaa.xxx.mail;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Email {
private String emailAdresse;
private String titel;
private String text;
}

View File

@@ -0,0 +1,39 @@
package de.oaa.xxx.mail;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
public class MailService {
private static final Logger LOGGER = LoggerFactory.getLogger(MailService.class);
private final JavaMailSender mailSender;
public MailService(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public boolean send(Email email) {
try {
MimeMessage message = mailSender.createMimeMessage();
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email.getEmailAdresse()));
message.setSubject(email.getTitel());
message.setFrom(InternetAddress.parse("noreply@xxx-sphere.de")[0]);
message.setContent(email.getText(), "text/html; charset=utf-8");
message.addHeader("X-Mailin-Tag", "no-tracking");
message.addHeader("X-Sib-Attributes", "{\"X-SIB-TRACKING\":\"0\"}");
mailSender.send(message);
return true;
} catch (MessagingException e) {
LOGGER.error(e.getLocalizedMessage(), e);
return false;
}
}
}

View File

@@ -0,0 +1,270 @@
package de.oaa.xxx.mail;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* Generates HTML email bodies with inline styles derived from app.theme.* properties.
* Changing theme colors in application.properties automatically updates email appearance.
* (Email clients don't support external CSS or CSS variables, so styles must be inlined.)
*/
@Service
public class MailTemplateService {
@Value("${app.theme.color-bg:#1a1a2e}")
private String colorBg;
@Value("${app.theme.color-card:#16213e}")
private String colorCard;
@Value("${app.theme.color-primary:#e94560}")
private String colorPrimary;
@Value("${app.theme.color-secondary:#0f3460}")
private String colorSecondary;
@Value("${app.theme.color-text:#eeeeee}")
private String colorText;
@Value("${app.theme.color-muted:#888888}")
private String colorMuted;
@Value("${app.theme.color-success:#2ecc71}")
private String colorSuccess;
public String buildEmailChangeMail(String name, String confirmLink, String newEmail) {
return """
<!DOCTYPE html>
<html lang="de">
<body style="margin:0; padding:2rem; background:%s; font-family:'Segoe UI',Arial,sans-serif; color:%s;">
<div style="max-width:460px; margin:0 auto; background:%s; border:1px solid %s; border-radius:12px; padding:2.5rem; box-shadow:0 8px 32px rgba(0,0,0,0.5);">
<h1 style="color:%s; text-align:center; margin:0 0 1.5rem 0; font-size:1.6rem;">XXX The Game</h1>
<p style="color:%s; margin:0 0 0.75rem 0;">Moin %s,</p>
<p style="color:%s; margin:0 0 0.5rem 0;">Du hast eine Änderung deiner E-Mail-Adresse angefordert.</p>
<p style="color:%s; margin:0 0 2rem 0;">Klick auf den Button, um deine neue Adresse <strong style="color:%s;">%s</strong> zu bestätigen:</p>
<div style="text-align:center; margin:0 0 2rem 0;">
<a href="%s"
style="display:inline-block; padding:0.75rem 2.5rem; background:%s; color:#ffffff;
border-radius:6px; text-decoration:none; font-weight:600; font-size:1rem;">
E-Mail-Adresse bestätigen
</a>
</div>
<hr style="border:none; border-top:1px solid %s; margin:0 0 1.5rem 0;">
<p style="color:%s; font-size:0.85em; margin:0;">
Falls du diese Änderung nicht angefordert hast, kannst du diese E-Mail einfach ignorieren.
</p>
</div>
</body>
</html>
""".formatted(
colorBg, colorText,
colorCard, colorSecondary,
colorPrimary,
colorText, name,
colorText,
colorText, colorPrimary, newEmail,
confirmLink, colorPrimary,
colorSecondary,
colorMuted
);
}
public String buildPasswordResetMail(String name, String resetLink) {
return """
<!DOCTYPE html>
<html lang="de">
<body style="margin:0; padding:2rem; background:%s; font-family:'Segoe UI',Arial,sans-serif; color:%s;">
<div style="max-width:460px; margin:0 auto; background:%s; border:1px solid %s; border-radius:12px; padding:2.5rem; box-shadow:0 8px 32px rgba(0,0,0,0.5);">
<h1 style="color:%s; text-align:center; margin:0 0 1.5rem 0; font-size:1.6rem;">XXX The Game</h1>
<p style="color:%s; margin:0 0 0.75rem 0;">Moin %s,</p>
<p style="color:%s; margin:0 0 0.5rem 0;">Du hast eine Anfrage zum Zurücksetzen deines Passworts gestellt.</p>
<p style="color:%s; margin:0 0 2rem 0;">Klick auf den Button, um ein neues Passwort zu vergeben:</p>
<div style="text-align:center; margin:0 0 2rem 0;">
<a href="%s"
style="display:inline-block; padding:0.75rem 2.5rem; background:%s; color:#ffffff;
border-radius:6px; text-decoration:none; font-weight:600; font-size:1rem;">
Passwort zurücksetzen
</a>
</div>
<hr style="border:none; border-top:1px solid %s; margin:0 0 1.5rem 0;">
<p style="color:%s; font-size:0.85em; margin:0;">
Falls du diese Anfrage nicht gestellt hast, kannst du diese E-Mail einfach ignorieren.
</p>
</div>
</body>
</html>
""".formatted(
colorBg, colorText,
colorCard, colorSecondary,
colorPrimary,
colorText, name,
colorText,
colorText,
resetLink, colorPrimary,
colorSecondary,
colorMuted
);
}
public String buildKeyholderInvitationMail(String keyholderName, String lockeeName, String lockName, String confirmLink) {
return """
<!DOCTYPE html>
<html lang="de">
<body style="margin:0; padding:2rem; background:%s; font-family:'Segoe UI',Arial,sans-serif; color:%s;">
<div style="max-width:460px; margin:0 auto; background:%s; border:1px solid %s; border-radius:12px; padding:2.5rem; box-shadow:0 8px 32px rgba(0,0,0,0.5);">
<h1 style="color:%s; text-align:center; margin:0 0 1.5rem 0; font-size:1.6rem;">XXX The Game</h1>
<p style="color:%s; margin:0 0 0.75rem 0;">Moin %s,</p>
<p style="color:%s; margin:0 0 0.5rem 0;">
<strong style="color:%s;">%s</strong> hat dich als Keyholder*In für das Chastity-Lock
<strong style="color:%s;">%s</strong> eingetragen.
</p>
<p style="color:%s; margin:0 0 2rem 0;">
Wenn du die Keyholder*In-Rolle annehmen möchtest, klicke auf den Button. Das Lock startet erst nach deiner Bestätigung mit dir als Keyholder*In.
</p>
<div style="text-align:center; margin:0 0 2rem 0;">
<a href="%s"
style="display:inline-block; padding:0.75rem 2.5rem; background:%s; color:#ffffff;
border-radius:6px; text-decoration:none; font-weight:600; font-size:1rem;">
Keyholder*In-Rolle annehmen
</a>
</div>
<hr style="border:none; border-top:1px solid %s; margin:0 0 1.5rem 0;">
<p style="color:%s; font-size:0.85em; margin:0;">
Falls du die Rolle nicht annehmen möchtest, kannst du diese E-Mail einfach ignorieren.
Das Lock läuft dann als Self-Lock weiter.
</p>
</div>
</body>
</html>
""".formatted(
colorBg, colorText,
colorCard, colorSecondary,
colorPrimary,
colorText, keyholderName,
colorText, colorPrimary, lockeeName,
colorPrimary, lockName,
colorText,
confirmLink, colorPrimary,
colorSecondary,
colorMuted
);
}
public String buildNotificationMail(String name, String text, String targetUrl, String baseUrl) {
String actionButton = targetUrl != null
? """
<div style="text-align:center; margin:0 0 2rem 0;">
<a href="%s%s"
style="display:inline-block; padding:0.75rem 2.5rem; background:%s; color:#ffffff;
border-radius:6px; text-decoration:none; font-weight:600; font-size:1rem;">
Zur Anwendung
</a>
</div>
""".formatted(baseUrl, targetUrl, colorPrimary)
: "<div style=\"margin:0 0 2rem 0;\"></div>";
String settingsUrl = baseUrl + "/konto/einstellungen.html#sec-benachrichtigungen";
return """
<!DOCTYPE html>
<html lang="de">
<body style="margin:0; padding:2rem; background:%s; font-family:'Segoe UI',Arial,sans-serif; color:%s;">
<div style="max-width:460px; margin:0 auto; background:%s; border:1px solid %s; border-radius:12px; padding:2.5rem; box-shadow:0 8px 32px rgba(0,0,0,0.5);">
<h1 style="color:%s; text-align:center; margin:0 0 1.5rem 0; font-size:1.6rem;">XXX The Game</h1>
<p style="color:%s; margin:0 0 0.75rem 0;">Hallo %s,</p>
<p style="color:%s; margin:0 0 2rem 0;">%s</p>
%s
<hr style="border:none; border-top:1px solid %s; margin:0 0 1.5rem 0;">
<p style="color:%s; font-size:0.85em; margin:0;">
Du erhältst diese E-Mail, weil du E-Mail-Benachrichtigungen für diese Kategorie aktiviert hast.
Du kannst deine Einstellungen jederzeit unter
<a href="%s" style="color:%s;">Einstellungen → Benachrichtigungen</a> anpassen.
</p>
</div>
</body>
</html>
""".formatted(
colorBg, colorText,
colorCard, colorSecondary,
colorPrimary,
colorText, name,
colorText, text,
actionButton,
colorSecondary,
colorMuted, settingsUrl, colorPrimary
);
}
public String buildActivationMail(String name, String activationLink, String activatePageUrl, String uuid) {
return """
<!DOCTYPE html>
<html lang="de">
<body style="margin:0; padding:2rem; background:%s; font-family:'Segoe UI',Arial,sans-serif; color:%s;">
<div style="max-width:460px; margin:0 auto; background:%s; border:1px solid %s; border-radius:12px; padding:2.5rem; box-shadow:0 8px 32px rgba(0,0,0,0.5);">
<h1 style="color:%s; text-align:center; margin:0 0 1.5rem 0; font-size:1.6rem;">XXX The Game</h1>
<p style="color:%s; margin:0 0 0.75rem 0;">Moin %s,</p>
<p style="color:%s; margin:0 0 0.5rem 0;">Vielen Dank für deine Anmeldung!</p>
<p style="color:%s; margin:0 0 2rem 0;">Klick auf den Button, um deine E-Mail-Adresse zu bestätigen:</p>
<div style="text-align:center; margin:0 0 2rem 0;">
<a href="%s"
style="display:inline-block; padding:0.75rem 2.5rem; background:%s; color:#ffffff;
border-radius:6px; text-decoration:none; font-weight:600; font-size:1rem;">
E-Mail bestätigen
</a>
</div>
<hr style="border:none; border-top:1px solid %s; margin:0 0 1.5rem 0;">
<p style="color:%s; font-size:0.9em; margin:0 0 0.5rem 0;">
Falls der Button nicht funktioniert, öffne
<a href="%s" style="color:%s;">%s</a>
und gib folgenden Code ein:
</p>
<p style="font-family:monospace; font-size:1.1em; background:%s; color:%s;
padding:0.5rem 1rem; border-radius:4px; display:inline-block; margin:0.5rem 0 1.5rem 0;">
%s
</p>
<p style="color:%s; margin:0;">Viel Spaß beim Spiel!</p>
</div>
</body>
</html>
""".formatted(
colorBg, colorText,
colorCard, colorSecondary,
colorPrimary,
colorText, name,
colorText,
colorText,
activationLink, colorPrimary,
colorSecondary,
colorMuted, activatePageUrl, colorPrimary, activatePageUrl,
colorSecondary, colorText,
uuid,
colorMuted
);
}
}