using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Domain.Entities.EmailVerification.ValueObject; using SharedKernel.Results; using Microsoft.EntityFrameworkCore; namespace Application.Features.Api.MyPage.VerifyEmail; internal sealed class Handler(IAppDbContext db) : IQueryHandler { public async Task Handle(Query request, CancellationToken ct) { if (string.IsNullOrWhiteSpace(request.Token)) { return Result.Failure(Error.Problem("MyPage.TokenRequired", "인증 토큰은 필수입니다.")); } var verifyToken = await db.EmailVerifyToken.FirstOrDefaultAsync(t => t.Token == request.Token && t.Type == VerificationType.ChangedEmail, ct); if (verifyToken is null) { return Result.Failure(Error.NotFound("MyPage.TokenNotFound", "유효하지 않은 인증 토큰입니다.")); } if (verifyToken.IsVerified) { return Result.Failure(Error.Problem("MyPage.AlreadyVerified", "이미 인증된 토큰입니다.")); } if (verifyToken.Expiration < DateTime.UtcNow) { return Result.Failure(Error.Problem("MyPage.TokenExpired", "인증 토큰이 만료되었습니다.")); } var member = await db.Member.FirstOrDefaultAsync(m => m.Email == verifyToken.Email, ct); if (member is null) { return Result.Failure(Error.NotFound("MyPage.MemberNotFound", "회원 정보를 찾을 수 없습니다.")); } verifyToken.MarkVerified(); member.MarkEmailVerified(); await db.SaveChangesAsync(ct); return Result.Success(); } }