krkarma777 / online-store

SEED: An open-market platform built with JDK 17, Spring Boot, and Oracle DB, focusing on RESTful architecture and secure user experiences.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unique Constraint Violation When Recreating VerificationToken for User

krkarma777 opened this issue · comments

Description

I'm encountering a DataIntegrityViolationException when attempting to recreate a VerificationToken for a user. This occurs because the application tries to create a new token before deleting the old one, leading to a unique constraint violation in the database. This issue is critical because it prevents the successful generation of new verification tokens for users, impacting the account verification flow.

Steps to Reproduce

Attempt to generate a verification token for a user who already has one.
Observe the DataIntegrityViolationException related to a unique constraint violation.
Expected Behavior:
The application should delete any existing verification token for the user before creating a new one, ensuring no unique constraint violations occur.

Actual Behavior

The application attempts to create a new verification token without deleting the existing one first, leading to a unique constraint violation and a DataIntegrityViolationException.

Possible Solution

Modify the token generation logic to ensure that any existing token for a user is deleted before creating a new one, ideally within the same transaction to maintain database integrity.

@Service
@RequiredArgsConstructor
@Transactional
public class EmailService {

    private final JavaMailSender mailSender;
    private final VerificationTokenService verificationTokenService;
    private final UserService userService;

    public void sendVerificationEmail(User user) throws MessagingException {
        verificationTokenService.deleteByUser(user);
        String token = createVerificationToken(user).getToken();
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");

        helper.setFrom("admin@seed.com");
        helper.setTo(user.getEmail());
        helper.setSubject(user.getRealName() + "님, Seed 인증 메일입니다.");

        String mailContent = ...

        helper.setText(mailContent, true); // true를 설정하여 HTML 컨텐츠로 인식하도록 합니다.

        mailSender.send(message);
    }
    public void sendUserIdEmail(User user) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");

        helper.setFrom("admin@seed.com");
        helper.setTo(user.getEmail());
        helper.setSubject(user.getRealName() + "님, Seed 아이디 찾기 결과입니다.");

        String mailContent = ...

        helper.setText(mailContent, true); // true를 설정하여 HTML 컨텐츠로 인식하도록 합니다.

        mailSender.send(message);
    }

    public VerificationToken createVerificationToken(User user) {
        VerificationToken myToken = new VerificationToken();
        myToken.setUser(user);
        String token = UUID.randomUUID().toString();
        myToken.setToken(token);
        myToken.setExpiryDate(LocalDateTime.now().plusHours(24)); // 24시간 후 만료
        return verificationTokenService.save(myToken);
    }

    public boolean verifyToken(String token) {
        VerificationToken verificationToken = verificationTokenService.findByToken(token).orElse(null);
        if (verificationToken == null || verificationToken.isExpired()) {
            return false;
        }
        User user = verificationToken.getUser();
        user.setStatus(UserStatus.ACTIVE);
        userService.save(user);
        verificationTokenService.delete(verificationToken);
        return true;
    }
}
    @Transactional
    public void deleteByUser(User user) {
        verificationTokenRepository.findByUser(user).ifPresent(verificationTokenRepository::delete);
    }