Handler.cs 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. using Application.Abstractions.Messaging;
  2. using Application.Abstractions.Data;
  3. using SharedKernel.Results;
  4. using Domain.Entities.Members;
  5. using MemberEntity = Domain.Entities.Members.Member;
  6. using ChannelEntity = Domain.Entities.Members.Channel;
  7. using Microsoft.EntityFrameworkCore;
  8. namespace Application.Features.Admin.Member.List.Create;
  9. public sealed class Handler(IAppDbContext db) : ICommandHandler<Command, Result>
  10. {
  11. public async Task<Result> Handle(Command request, CancellationToken ct)
  12. {
  13. // 이메일 중복 체크
  14. if (await db.Member.AnyAsync(x => x.Email == request.Email, ct))
  15. {
  16. return Result.Failure(Error.Conflict("Member.DuplicateEmail", "이미 등록된 이메일입니다."));
  17. }
  18. // 별명 중복 체크
  19. if (request.Name is not null && await db.Member.AnyAsync(x => x.Name == request.Name, ct))
  20. {
  21. return Result.Failure(Error.Conflict("Member.DuplicateName", "이미 등록된 별명입니다."));
  22. }
  23. // 회원 생성
  24. var member = MemberEntity.Create(request.Email);
  25. await db.Member.AddAsync(member, ct);
  26. await db.SaveChangesAsync(ct);
  27. // 비밀번호 해싱 (PBKDF2). 평문은 절대 저장하지 않는다. 미입력 시 null.
  28. string? passwordHash = string.IsNullOrWhiteSpace(request.Password) ? null : MemberEntity.HashPassword(request.Password);
  29. // 기본 정보 업데이트
  30. await db.Member.Where(x => x.ID == member.ID).ExecuteUpdateAsync(s => s
  31. .SetProperty(x => x.MemberGradeID, request.MemberGradeID)
  32. .SetProperty(x => x.Name, request.Name)
  33. .SetProperty(x => x.PasswordHash, passwordHash)
  34. .SetProperty(x => x.PasswordUpdatedAt, DateTime.UtcNow)
  35. .SetProperty(x => x.FirstName, request.FirstName)
  36. .SetProperty(x => x.LastName, request.LastName)
  37. .SetProperty(x => x.Intro, request.Intro)
  38. .SetProperty(x => x.Summary, request.Summary)
  39. .SetProperty(x => x.Phone, request.Phone)
  40. .SetProperty(x => x.Birthday, request.Birthday)
  41. .SetProperty(x => x.Gender, request.Gender)
  42. .SetProperty(x => x.Thumb, request.ThumbUrl)
  43. .SetProperty(x => x.Icon, request.IconUrl)
  44. .SetProperty(x => x.IsEmailVerified, request.IsEmailVerified)
  45. .SetProperty(x => x.IsAuthCertified, request.IsAuthCertified)
  46. .SetProperty(x => x.IsDenied, request.IsDenied)
  47. .SetProperty(x => x.IsAdmin, request.IsAdmin)
  48. .SetProperty(x => x.IsWithdraw, request.IsWithdraw),
  49. ct);
  50. // MemberApprove 생성
  51. await db.MemberApprove.AddAsync(
  52. MemberApprove.Create(member.ID)
  53. , ct);
  54. // YouTube 채널 정보가 있는 경우
  55. if (!string.IsNullOrWhiteSpace(request.YouTubeSID) &&
  56. !string.IsNullOrWhiteSpace(request.YouTubeName) &&
  57. !string.IsNullOrWhiteSpace(request.YouTubeUrl))
  58. {
  59. await db.Channel.AddAsync(ChannelEntity.Create(
  60. member.ID,
  61. request.YouTubeSID,
  62. request.YouTubeName,
  63. request.YouTubeUrl
  64. ), ct);
  65. }
  66. await db.SaveChangesAsync(ct);
  67. return Result.Success();
  68. }
  69. }