using Application.Abstractions.Identity; using Application.Abstractions.Identity.Models; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; namespace Infrastructure.Persistence.Identity { public sealed class IdentityUserWriter(UserManager userManager) : IIdentityUserWriter { public async Task UpdateUserAsync(ApplicationUserDto a, CancellationToken ct) { if (string.IsNullOrWhiteSpace(a.ID)) { throw new InvalidOperationException("ID는 필수입니다."); } var user = await userManager.FindByIdAsync(a.ID); if (user is null) { throw new InvalidOperationException("사용자 정보를 찾을 수 없습니다."); } // 이메일 중복 확인(본인 제외) if (!string.IsNullOrWhiteSpace(a.Email)) { var exists = await userManager.Users.AsNoTracking().AnyAsync(u => u.Email == a.Email && u.Id != a.ID, ct); if (exists) { throw new InvalidOperationException("이미 존재하는 이메일 주소입니다."); } } user.SetFullName(a.Name); user.SetEmail(a.Email); user.SetPhoneNumber(a.Phone); user.SetDeleted(a.IsDeleted); user.SetEmailConfirmed(a.EmailConfirmed); user.SetLockoutEnd(a.LockoutEnd); // 비밀번호 변경(입력되었을 때만) if (!string.IsNullOrWhiteSpace(a.NewPassword)) { if (a.NewPassword != a.ConfirmPassword) { throw new InvalidOperationException("두 비밀번호가 서로 일치하지 않습니다."); } var token = await userManager.GeneratePasswordResetTokenAsync(user); var reset = await userManager.ResetPasswordAsync(user, token, a.NewPassword); if (!reset.Succeeded) { throw new InvalidOperationException(string.Join(Environment.NewLine, reset.Errors.Select(x => x.Description))); } } var updated = await userManager.UpdateAsync(user); if (!updated.Succeeded) { throw new InvalidOperationException(string.Join(Environment.NewLine, updated.Errors.Select(x => x.Description))); } } public async Task UpdateUserRolesAsync(string userID, UserRolesDto? b, CancellationToken ct) { if (string.IsNullOrWhiteSpace(userID)) { throw new InvalidOperationException("ID는 필수입니다."); } var user = await userManager.FindByIdAsync(userID); if (user is null) { throw new InvalidOperationException("사용자 정보를 찾을 수 없습니다."); } var userRoles = await userManager.GetRolesAsync(user); foreach (var role in b?.Roles ?? Enumerable.Empty()) { var roleName = role.DisplayValue?.Trim(); if (string.IsNullOrWhiteSpace(roleName)) { continue; } // 현재 사용자의 역할에 포함되어 있으나 선택되지 않은 경우 제거 if (userRoles.Contains(roleName, StringComparer.OrdinalIgnoreCase) && !role.IsSelected) { var removed = await userManager.RemoveFromRoleAsync(user, roleName); if (!removed.Succeeded) { throw new InvalidOperationException(string.Join(Environment.NewLine, removed.Errors.Select(e => e.Description))); } } // 현재 사용자의 역할에 포함되지 않았으나 선택된 경우 추가 if (!userRoles.Contains(roleName, StringComparer.OrdinalIgnoreCase) && role.IsSelected) { var added = await userManager.AddToRoleAsync(user, roleName); if (!added.Succeeded) { throw new InvalidOperationException(string.Join(Environment.NewLine, added.Errors.Select(e => e.Description))); } } } } } }