const EmailVerificationRepository = require('../../repositories/email/EmailVerificationRepository'); const MailService = require('./MailService'); const { logger } = require('../../middleware/logger'); class EmailVerificationService { static async sendVerificationEmail(user, unitOfWork) { logger.info('EmailVerificationService.sendVerificationEmail:start', { userId: user.id, email: user.email }); const emailVerificationRepo = new EmailVerificationRepository(unitOfWork); try { // Check if already verified const status = await unitOfWork.connection.query( 'SELECT email_verified FROM user_status WHERE user_id = ?', [user.id] ); if (status[0][0] && status[0][0].email_verified) { logger.warn('EmailVerificationService.sendVerificationEmail:already_verified', { userId: user.id }); throw new Error('Email already verified'); } // Generate 6-digit code and expiry const code = Math.floor(100000 + Math.random() * 900000).toString(); const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes // Upsert code in DB await emailVerificationRepo.upsertCode(user.id, code, expiresAt); logger.info('EmailVerificationService.sendVerificationEmail:code_upserted', { userId: user.id }); // Send email await MailService.sendVerificationCodeEmail({ email: user.email, code, expiresAt }); logger.info('EmailVerificationService.sendVerificationEmail:email_sent', { userId: user.id, email: user.email }); logger.info('EmailVerificationService.sendVerificationEmail:success', { userId: user.id }); return true; } catch (error) { logger.error('EmailVerificationService.sendVerificationEmail:error', { userId: user.id, error: error.message }); throw error; } } static async verifyCode(userId, code, unitOfWork) { logger.info('EmailVerificationService.verifyCode:start', { userId, code }); const emailVerificationRepo = new EmailVerificationRepository(unitOfWork); try { // Get latest, unexpired, unverified code const record = await emailVerificationRepo.getByUserId(userId); if ( !record || record.verified_at || new Date(record.expires_at) < new Date() || record.verification_code !== code ) { logger.warn('EmailVerificationService.verifyCode:invalid_or_expired', { userId, code }); // Optionally increment attempts if (record) { await emailVerificationRepo.incrementAttempts(record.id); } return { success: false, error: 'Invalid or expired code' }; } // Mark as verified await emailVerificationRepo.setVerified(record.id); logger.info('EmailVerificationService.verifyCode:code_verified', { userId }); // Update user_status await unitOfWork.connection.query( `UPDATE user_status SET email_verified = 1, email_verified_at = NOW() WHERE user_id = ?`, [userId] ); logger.info('EmailVerificationService.verifyCode:user_status_updated', { userId }); // Check if all steps are complete and set status to 'pending' if so const UserStatusService = require('../status/UserStatusService'); await UserStatusService.checkAndSetPendingIfComplete(userId, unitOfWork); logger.info('EmailVerificationService.verifyCode:pending_check_complete', { userId }); logger.info('EmailVerificationService.verifyCode:success', { userId }); return { success: true }; } catch (error) { logger.error('EmailVerificationService.verifyCode:error', { userId, error: error.message }); throw error; } } } module.exports = EmailVerificationService;