Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package com.empress.usermanagementapi.controller;

import com.empress.usermanagementapi.entity.PasswordResetToken;
import com.empress.usermanagementapi.entity.User;
import com.empress.usermanagementapi.service.UserService;
import com.empress.usermanagementapi.service.EmailService;
import com.empress.usermanagementapi.service.PasswordResetService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
Expand All @@ -20,17 +17,11 @@ public class ForgotPasswordController {
private static final Logger log = LoggerFactory.getLogger(ForgotPasswordController.class);

private final UserService userService;
private final EmailService emailService;
private final PasswordResetService passwordResetService;

@Value("${app.base-url}")
private String baseUrl;

public ForgotPasswordController(UserService userService,
EmailService emailService,
PasswordResetService passwordResetService) {
this.userService = userService;
this.emailService = emailService;
this.passwordResetService = passwordResetService;
}

Expand Down Expand Up @@ -64,15 +55,8 @@ public String handleForm(@RequestParam String username,
return "forgot-password";
}

// User exists, create token + send email
PasswordResetToken tokenEntity =
passwordResetService.createPasswordResetTokenForEmail(trimmedEmail);
String token = tokenEntity.getToken();

String resetLink = baseUrl + "/reset-password?token=" + token;

try {
emailService.sendPasswordResetEmail(trimmedEmail, resetLink);
passwordResetService.createTokenAndSendResetEmail(trimmedEmail);
} catch (Exception e) {
log.error("Failed to send password reset email to: {}", trimmedEmail, e);
model.addAttribute("error", "Failed to send password reset email. Please try again later.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
import com.empress.usermanagementapi.entity.Role;
import com.empress.usermanagementapi.entity.User;
import com.empress.usermanagementapi.model.RegistrationRequest;
import com.empress.usermanagementapi.service.EmailService;
import com.empress.usermanagementapi.service.EmailVerificationService;
import com.empress.usermanagementapi.service.UserService;
import com.empress.usermanagementapi.util.LoggingUtil;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
Expand All @@ -37,17 +35,11 @@ public class RegistrationController {

private final UserService userService;
private final EmailVerificationService emailVerificationService;
private final EmailService emailService;

@Value("${app.base-url}")
private String baseUrl;

public RegistrationController(UserService userService,
EmailVerificationService emailVerificationService,
EmailService emailService) {
EmailVerificationService emailVerificationService) {
this.userService = userService;
this.emailVerificationService = emailVerificationService;
this.emailService = emailService;
}

/**
Expand Down Expand Up @@ -123,22 +115,7 @@ public String registerSubmit(
created.getId(),
created.getUsername());

// create verification token
String token = emailVerificationService.createTokenForUser(created);
log.debug("Email verification token created - userId: {}", created.getId());

String verifyLink = baseUrl + "/verify-email?token=" + token;

try {
emailService.sendVerificationEmail(created.getEmail(), verifyLink);
log.info("Verification email sent - userId: {}", created.getId());
} catch (Exception e) {
// for now just log; account is created even if email fails
log.error("Failed to send verification email - userId: {}, error: {}",
created.getId(),
e.getMessage());
System.err.println("Failed to send verification email: " + e.getMessage());
}
emailVerificationService.createTokenAndSendVerificationEmail(created);
} else {
log.warn("User creation returned null or invalid user");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.empress.usermanagementapi.util.LoggingUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
Expand All @@ -20,11 +21,17 @@ public class EmailVerificationService {

private final EmailVerificationTokenRepository tokenRepo;
private final UserRepository userRepo;
private final EmailService emailService;

@Value("${app.base-url}")
private String baseUrl;

public EmailVerificationService(EmailVerificationTokenRepository tokenRepo,
UserRepository userRepo) {
UserRepository userRepo,
EmailService emailService) {
this.tokenRepo = tokenRepo;
this.userRepo = userRepo;
this.emailService = emailService;
}

// create or refresh a token for this user and return the token string
Expand Down Expand Up @@ -65,6 +72,29 @@ public String createTokenForUser(User user) {
return newTokenValue;
}

/**
* Creates a verification token and sends the verification email.
*
* The account is already created at this point, so email delivery failures are logged
* without rolling back registration. This preserves the existing registration behavior
* while keeping email orchestration inside the service layer.
*/
public void createTokenAndSendVerificationEmail(User user) {
String token = createTokenForUser(user);
log.debug("Email verification token created - userId: {}", user.getId());

String verifyLink = baseUrl + "/verify-email?token=" + token;

try {
emailService.sendVerificationEmail(user.getEmail(), verifyLink);
log.info("Verification email sent - userId: {}", user.getId());
} catch (Exception e) {
log.error("Failed to send verification email - userId: {}, error: {}",
user.getId(),
e.getMessage());
}
}

/**
* @return null on success, or an error message on failure
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.empress.usermanagementapi.util.LoggingUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

Expand All @@ -22,13 +23,19 @@ public class PasswordResetService {
private final PasswordResetTokenRepository tokenRepo;
private final UserRepository userRepo;
private final PasswordEncoder passwordEncoder;
private final EmailService emailService;

@Value("${app.base-url}")
private String baseUrl;

public PasswordResetService(PasswordResetTokenRepository tokenRepo,
UserRepository userRepo,
PasswordEncoder passwordEncoder) {
PasswordEncoder passwordEncoder,
EmailService emailService) {
this.tokenRepo = tokenRepo;
this.userRepo = userRepo;
this.passwordEncoder = passwordEncoder;
this.emailService = emailService;
}

public PasswordResetToken createPasswordResetTokenForEmail(String email) {
Expand Down Expand Up @@ -70,6 +77,19 @@ public PasswordResetToken createPasswordResetTokenForEmail(String email) {
return saved;
}

/**
* Creates a password reset token and sends the reset email.
*
* Callers only need to validate who is allowed to request a reset; this service owns
* the token creation and email-delivery workflow. Email delivery failures are allowed
* to propagate so the controller can show the user that the reset email was not sent.
*/
public void createTokenAndSendResetEmail(String email) {
PasswordResetToken tokenEntity = createPasswordResetTokenForEmail(email);
String resetLink = baseUrl + "/reset-password?token=" + tokenEntity.getToken();
emailService.sendPasswordResetEmail(email, resetLink);
}

public String validatePasswordResetToken(String token) {
String cleanToken = token == null ? null : token.trim();

Expand Down
Loading