| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- using Application.Abstractions.Crypto;
- using Application.Abstractions.Data;
- using Application.Abstractions.Messaging;
- using Microsoft.EntityFrameworkCore;
- using SharedKernel.Results;
- using MemberAddressEntity = Domain.Entities.Store.MemberAddress;
- namespace Application.Features.Api.MyPage.Address.Save;
- public sealed class Handler(IAppDbContext db, IFieldEncryptor encryptor) : ICommandHandler<Command, Result<int>>
- {
- private const int MaxAddressesPerMember = 5;
- public async Task<Result<int>> Handle(Command request, CancellationToken ct)
- {
- // 입력 검증
- if (string.IsNullOrWhiteSpace(request.RecipientName))
- {
- return Result.Failure<int>(Error.Problem("Address.RecipientRequired", "수령인명은 필수입니다."));
- }
- if (string.IsNullOrWhiteSpace(request.Phone))
- {
- return Result.Failure<int>(Error.Problem("Address.PhoneRequired", "연락처는 필수입니다."));
- }
- if (string.IsNullOrWhiteSpace(request.ZipCode) || request.ZipCode.Length > 10)
- {
- return Result.Failure<int>(Error.Problem("Address.InvalidZipCode", "우편번호가 잘못되었습니다."));
- }
- if (string.IsNullOrWhiteSpace(request.Address1) || string.IsNullOrWhiteSpace(request.Address2))
- {
- return Result.Failure<int>(Error.Problem("Address.RequiredFields", "주소를 정확히 입력해주세요."));
- }
- // 암호화
- var recipientEnc = encryptor.Encrypt(request.RecipientName);
- var recipientHash = encryptor.Hash(request.RecipientName);
- var phoneEnc = encryptor.Encrypt(request.Phone);
- var addr1Enc = encryptor.Encrypt(request.Address1);
- var addr2Enc = encryptor.Encrypt(request.Address2);
- var keyVersion = encryptor.CurrentKeyVersion;
- // IsDefault 처리: true 라면 다른 주소의 IsDefault 모두 false 로
- if (request.IsDefault)
- {
- var others = await db.MemberAddress
- .Where(a => a.MemberID == request.MemberID && a.IsDefault)
- .ToListAsync(ct);
- foreach (var o in others)
- {
- if (request.ID.HasValue && o.ID == request.ID.Value)
- {
- continue;
- }
- o.UnsetDefault();
- }
- }
- if (!request.ID.HasValue || request.ID.Value == 0)
- {
- // 신규 — 회원당 최대 개수 검증
- var count = await db.MemberAddress.CountAsync(a => a.MemberID == request.MemberID, ct);
- if (count >= MaxAddressesPerMember)
- {
- return Result.Failure<int>(Error.Problem("Address.MaxExceeded", $"주소는 회원당 최대 {MaxAddressesPerMember}개까지 등록 가능합니다."));
- }
- // 첫 주소는 자동 default
- var isDefault = request.IsDefault || count == 0;
- var newAddress = MemberAddressEntity.Create(
- memberID: request.MemberID,
- recipientNameEncrypted: recipientEnc,
- recipientNameHash: recipientHash,
- phoneEncrypted: phoneEnc,
- zipCode: request.ZipCode,
- address1Encrypted: addr1Enc,
- address2Encrypted: addr2Enc,
- keyVersion: keyVersion,
- isDefault: isDefault
- );
- db.MemberAddress.Add(newAddress);
- await db.SaveChangesAsync(ct);
- return Result.Success(newAddress.ID);
- }
- // 수정
- var existing = await db.MemberAddress
- .FirstOrDefaultAsync(a => a.ID == request.ID.Value && a.MemberID == request.MemberID, ct);
- if (existing is null)
- {
- return Result.Failure<int>(Error.NotFound("Address.NotFound", "수정할 주소를 찾을 수 없습니다."));
- }
- existing.Update(
- recipientNameEncrypted: recipientEnc,
- recipientNameHash: recipientHash,
- phoneEncrypted: phoneEnc,
- zipCode: request.ZipCode,
- address1Encrypted: addr1Enc,
- address2Encrypted: addr2Enc,
- keyVersion: keyVersion
- );
- if (request.IsDefault && !existing.IsDefault)
- {
- existing.SetAsDefault();
- }
- else if (!request.IsDefault && existing.IsDefault)
- {
- existing.UnsetDefault();
- }
- await db.SaveChangesAsync(ct);
- return Result.Success(existing.ID);
- }
- }
|