Erweiterungen

This commit is contained in:
2025-09-09 19:19:58 +02:00
parent bead579d4a
commit 8ecd05b3c0

View File

@@ -11,21 +11,39 @@ import com.vaadin.flow.component.textfield.PasswordField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.VaadinSession;
import com.vaadin.flow.server.auth.AnonymousAllowed;
import de.assecutor.votianlt.pages.service.UserService;
import de.assecutor.votianlt.util.MailUtil;
import jakarta.mail.MessagingException;
import java.security.SecureRandom;
import java.time.Duration;
import java.time.LocalDateTime;
@Route("register")
@PageTitle("Bei VotianLT registrieren")
@AnonymousAllowed
public class RegisterView extends VerticalLayout {
private final UserService userService;
private final MailUtil mailUtil;
private TextField emailField;
private PasswordField passwordField;
private PasswordField confirmPasswordField;
private TextField codeField;
private Button submitButton;
private Button verifyButton;
private Button resendButton;
public RegisterView(UserService userService) {
private String pendingCode; // 6-stelliger Code im View-Zustand
private LocalDateTime codeExpiresAt;
private LocalDateTime lastSentAt;
private boolean awaitingVerification = false;
public RegisterView(UserService userService, MailUtil mailUtil) {
this.userService = userService;
this.mailUtil = mailUtil;
// Layout-Konfiguration für vollständige Zentrierung
setSizeFull();
setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
@@ -80,22 +98,46 @@ public class RegisterView extends VerticalLayout {
confirmPasswordField.setRequired(true);
confirmPasswordField.setPlaceholder("Passwort wiederholen");
// Submit Button
submitButton = new Button("Registrieren", event -> registerUser());
codeField = new TextField("Bestätigungscode (6 Ziffern)");
codeField.setWidthFull();
codeField.setMaxLength(6);
codeField.setPattern("\\d{6}");
codeField.setPlaceholder("z. B. 123456");
codeField.setVisible(false);
codeField.addValueChangeListener(e -> {
String v = e.getValue();
if (v != null && !v.matches("\\d*")) {
codeField.setValue(v.replaceAll("[^0-9]", ""));
}
});
// Buttons
submitButton = new Button("Registrieren", event -> onStartRegistration());
submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_LARGE);
submitButton.setWidthFull();
verifyButton = new Button("Code prüfen und registrieren", event -> onVerifyCode());
verifyButton.addThemeVariants(ButtonVariant.LUMO_SUCCESS);
verifyButton.setWidthFull();
verifyButton.setVisible(false);
resendButton = new Button("Code erneut senden", event -> onResendCode());
resendButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
resendButton.setWidthFull();
resendButton.setVisible(false);
// Zurück-Link
Button backButton = new Button("Zurück zur Startseite", event ->
getUI().ifPresent(ui -> ui.navigate("")));
backButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
backButton.setWidthFull();
container.add(title, subtitle, emailField, passwordField, confirmPasswordField, submitButton, backButton);
container.add(title, subtitle, emailField, passwordField, confirmPasswordField,
submitButton, codeField, verifyButton, resendButton, backButton);
return container;
}
private void registerUser() {
private void onStartRegistration() {
var email = emailField.getValue().trim();
var password = passwordField.getValue();
var confirmPassword = confirmPasswordField.getValue();
@@ -106,50 +148,112 @@ public class RegisterView extends VerticalLayout {
emailField.focus();
return;
}
if (!email.contains("@") || !email.contains(".")) {
Notification.show("Bitte geben Sie eine gültige E-Mail-Adresse ein.", 3000, Notification.Position.MIDDLE);
emailField.focus();
return;
}
if (userService.existsByEmail(email)) {
Notification.show("Ein Benutzer mit dieser E-Mail-Adresse existiert bereits.", 4000, Notification.Position.MIDDLE);
return;
}
if (password.isEmpty()) {
Notification.show("Bitte geben Sie ein Passwort ein.", 3000, Notification.Position.MIDDLE);
passwordField.focus();
return;
}
if (password.length() < 6) {
Notification.show("Das Passwort muss mindestens 6 Zeichen lang sein.", 3000, Notification.Position.MIDDLE);
passwordField.focus();
return;
}
if (!password.equals(confirmPassword)) {
Notification.show("Die Passwörter stimmen nicht überein.", 3000, Notification.Position.MIDDLE);
confirmPasswordField.focus();
return;
}
// Alles ok: Code erzeugen und senden
sendVerificationCode(email);
}
private void sendVerificationCode(String email) {
// Rate-Limit: 60 Sekunden zwischen Sendungen
if (lastSentAt != null && Duration.between(lastSentAt, LocalDateTime.now()).getSeconds() < 60) {
long wait = 60 - Duration.between(lastSentAt, LocalDateTime.now()).getSeconds();
Notification.show("Bitte warten Sie " + wait + " Sekunden, bevor Sie den Code erneut senden.", 4000, Notification.Position.MIDDLE);
return;
}
String code = generateSixDigitCode();
pendingCode = code;
codeExpiresAt = LocalDateTime.now().plusMinutes(10);
lastSentAt = LocalDateTime.now();
String subject = "Ihr VotianLT Bestätigungscode";
String body = "Ihr Bestätigungscode lautet: " + code + "\n\n" +
"Dieser Code ist 10 Minuten gültig.\n" +
"Wenn Sie diese Registrierung nicht angefragt haben, ignorieren Sie diese E-Mail.";
try {
mailUtil.sendMail(email, subject, body);
awaitingVerification = true;
// UI umstellen: Code-Eingabe anzeigen
codeField.clear();
codeField.setVisible(true);
verifyButton.setVisible(true);
resendButton.setVisible(true);
emailField.setReadOnly(true);
passwordField.setReadOnly(true);
confirmPasswordField.setReadOnly(true);
submitButton.setEnabled(false);
Notification.show("Ein Bestätigungscode wurde an " + email + " gesendet.", 4000, Notification.Position.MIDDLE);
} catch (MessagingException e) {
awaitingVerification = false;
Notification.show("Fehler beim Senden der E-Mail: " + e.getMessage(), 5000, Notification.Position.MIDDLE);
}
}
private void onVerifyCode() {
if (!awaitingVerification) {
Notification.show("Bitte starten Sie zuerst die Registrierung.", 3000, Notification.Position.MIDDLE);
return;
}
String entered = codeField.getValue() != null ? codeField.getValue().trim() : "";
if (!entered.matches("\\d{6}")) {
Notification.show("Bitte geben Sie den 6-stelligen Code ein.", 3000, Notification.Position.MIDDLE);
return;
}
if (codeExpiresAt == null || LocalDateTime.now().isAfter(codeExpiresAt)) {
Notification.show("Der Code ist abgelaufen. Bitte senden Sie einen neuen Code.", 4000, Notification.Position.MIDDLE);
return;
}
if (!entered.equals(pendingCode)) {
Notification.show("Der eingegebene Code ist ungültig.", 3000, Notification.Position.MIDDLE);
return;
}
// Code korrekt -> Benutzer erstellen
var email = emailField.getValue().trim();
var password = passwordField.getValue();
try {
// Benutzer erstellen
userService.createUser(email, password, "Benutzer", "Name");
// Erfolgsmeldung und Weiterleitung
Notification.show("Registrierung erfolgreich! Sie werden zur Anmeldung weitergeleitet.",
3000, Notification.Position.MIDDLE);
VaadinSession.getCurrent().setAttribute("flashMessage", "Registrierung erfolgreich. Bitte melden Sie sich an.");
getUI().ifPresent(ui -> ui.navigate("login"));
} catch (RuntimeException e) {
if (e.getMessage().contains("already exists")) {
Notification.show("Ein Benutzer mit dieser E-Mail-Adresse existiert bereits.",
5000, Notification.Position.MIDDLE);
emailField.focus();
} else {
Notification.show("Registrierung fehlgeschlagen: " + e.getMessage(),
5000, Notification.Position.MIDDLE);
Notification.show("Registrierung fehlgeschlagen: " + e.getMessage(), 5000, Notification.Position.MIDDLE);
}
}
private void onResendCode() {
if (emailField.isReadOnly()) {
sendVerificationCode(emailField.getValue().trim());
}
}
private String generateSixDigitCode() {
SecureRandom random = new SecureRandom();
int num = random.nextInt(1_000_000); // 0..999999
return String.format("%06d", num);
}
}