Handler.cs 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Kyc;
  3. using Application.Abstractions.Messaging;
  4. using Domain.Entities.Developers.ValueObject;
  5. using Microsoft.EntityFrameworkCore;
  6. using SharedKernel.Results;
  7. namespace Application.Features.Api.Developers.Profile.CompleteKyc;
  8. internal sealed class Handler(IAppDbContext db, INiceAuthClient nice) : ICommandHandler<Command, Result>
  9. {
  10. public async Task<Result> Handle(Command request, CancellationToken ct)
  11. {
  12. var session = await db.NiceAuthSession
  13. .AsTracking()
  14. .Include(c => c.Developer)
  15. .FirstOrDefaultAsync(c => c.SessionToken == request.SessionToken, ct);
  16. if (session is null)
  17. {
  18. return Result.Failure(Error.NotFound(
  19. "Nice.SessionNotFound",
  20. "본인인증 세션을 찾을 수 없습니다."));
  21. }
  22. if (!session.CanProcessCallback())
  23. {
  24. // 이미 Completed/Failed/Expired 처리된 세션 — 결과는 그대로 두고 안내
  25. return session.Status == NiceAuthSessionStatus.Completed
  26. ? Result.Success()
  27. : Result.Failure(Error.Problem(
  28. "Nice.SessionFinalized",
  29. "본인인증 세션이 이미 종료되었습니다."));
  30. }
  31. if (session.IsExpired(DateTime.UtcNow))
  32. {
  33. session.MarkExpired();
  34. await db.SaveChangesAsync(ct);
  35. return Result.Failure(Error.Problem(
  36. "Nice.AuthFailedOrExpired",
  37. "본인인증 유효시간이 만료되었습니다. 다시 시도해 주세요."));
  38. }
  39. if (session.Developer is null)
  40. {
  41. session.MarkFailed("Developer 정보 누락");
  42. await db.SaveChangesAsync(ct);
  43. return Result.Failure(Error.NotFound(
  44. "Developer.NotFound",
  45. "개발자 정보를 찾을 수 없습니다."));
  46. }
  47. session.MarkWebTransactionReceived(request.WebTransactionID);
  48. var userResult = await nice.GetResultAsync(
  49. session.RequestNo,
  50. session.TransactionID,
  51. request.WebTransactionID,
  52. session.Ticket,
  53. session.Iterators,
  54. ct);
  55. if (userResult.IsFailure)
  56. {
  57. session.MarkFailed(userResult.Error.Code);
  58. await db.SaveChangesAsync(ct);
  59. return Result.Failure(userResult.Error);
  60. }
  61. var user = userResult.Value;
  62. // CI 가 다른 Developer 와 이미 묶여 있으면 중복가입 차단
  63. var ciTaken = await db.Developer
  64. .AsNoTracking()
  65. .AnyAsync(c => c.ID != session.DeveloperID && c.KycCi == user.Ci, ct);
  66. if (ciTaken)
  67. {
  68. session.MarkFailed("CI 중복");
  69. await db.SaveChangesAsync(ct);
  70. return Result.Failure(Error.Conflict(
  71. "Developer.KycCiTaken",
  72. "해당 명의로 이미 가입된 개발자 계정이 있습니다."));
  73. }
  74. session.Developer.MarkKycVerified(user.Ci, user.Di);
  75. session.MarkCompleted();
  76. await db.SaveChangesAsync(ct);
  77. return Result.Success();
  78. }
  79. }