|  |  | 1 |  | using LGDXRobotCloud.API.Exceptions; | 
|  |  | 2 |  | using LGDXRobotCloud.API.Services.Common; | 
|  |  | 3 |  | using LGDXRobotCloud.Data.DbContexts; | 
|  |  | 4 |  | using LGDXRobotCloud.Data.Entities; | 
|  |  | 5 |  | using LGDXRobotCloud.Data.Models.Business.Administration; | 
|  |  | 6 |  | using LGDXRobotCloud.Utilities.Enums; | 
|  |  | 7 |  | using LGDXRobotCloud.Utilities.Helpers; | 
|  |  | 8 |  | using Microsoft.AspNetCore.Identity; | 
|  |  | 9 |  | using Microsoft.EntityFrameworkCore; | 
|  |  | 10 |  |  | 
|  |  | 11 |  | namespace LGDXRobotCloud.API.Services.Administration; | 
|  |  | 12 |  |  | 
|  |  | 13 |  | public interface IUserService | 
|  |  | 14 |  | { | 
|  |  | 15 |  |   Task<(IEnumerable<LgdxUserListBusinessModel>, PaginationHelper)> GetUsersAsync(string? name, int pageNumber, int pageS | 
|  |  | 16 |  |   Task<LgdxUserBusinessModel> GetUserAsync(Guid id); | 
|  |  | 17 |  |   Task<LgdxUserBusinessModel> CreateUserAsync(LgdxUserCreateAdminBusinessModel lgdxUserCreateAdminBusinessModel); | 
|  |  | 18 |  |   Task<bool> UpdateUserAsync(Guid id, LgdxUserUpdateAdminBusinessModel lgdxUserUpdateAdminBusinessModel); | 
|  |  | 19 |  |   Task<bool> UnlockUserAsync(Guid id); | 
|  |  | 20 |  |   Task<bool> DeleteUserAsync(Guid id, string operatorId); | 
|  |  | 21 |  | } | 
|  |  | 22 |  |  | 
|  | 23 | 23 |  | public class UserService( | 
|  | 23 | 24 |  |     IActivityLogService activityLogService, | 
|  | 23 | 25 |  |     IEmailService emailService, | 
|  | 23 | 26 |  |     LgdxContext context, | 
|  | 23 | 27 |  |     UserManager<LgdxUser> userManager | 
|  | 23 | 28 |  |   ) : IUserService | 
|  |  | 29 |  | { | 
|  | 23 | 30 |  |   private readonly IActivityLogService _activityLogService = activityLogService ?? throw new ArgumentNullException(nameo | 
|  | 23 | 31 |  |   private readonly IEmailService _emailService = emailService ?? throw new ArgumentNullException(nameof(emailService)); | 
|  | 23 | 32 |  |   private readonly LgdxContext _context = context ?? throw new ArgumentNullException(nameof(context)); | 
|  | 23 | 33 |  |   private readonly UserManager<LgdxUser> _userManager = userManager ?? throw new ArgumentNullException(nameof(userManage | 
|  |  | 34 |  |  | 
|  |  | 35 |  |   public async Task<(IEnumerable<LgdxUserListBusinessModel>, PaginationHelper)> GetUsersAsync(string? name, int pageNumb | 
|  | 4 | 36 |  |   { | 
|  | 4 | 37 |  |     var query = _context.Users as IQueryable<LgdxUser>; | 
|  | 4 | 38 |  |     if (!string.IsNullOrWhiteSpace(name)) | 
|  | 3 | 39 |  |     { | 
|  | 3 | 40 |  |       name = name.Trim().ToUpper(); | 
|  | 3 | 41 |  |       query = query.Where(u => u.NormalizedUserName!.Contains(name.ToUpper())); | 
|  | 3 | 42 |  |     } | 
|  | 4 | 43 |  |     var itemCount = await query.CountAsync(); | 
|  | 4 | 44 |  |     var PaginationHelper = new PaginationHelper(itemCount, pageNumber, pageSize); | 
|  | 4 | 45 |  |     var users = await query.AsNoTracking() | 
|  | 4 | 46 |  |       .OrderBy(t => t.Id) | 
|  | 4 | 47 |  |       .Skip(pageSize * (pageNumber - 1)) | 
|  | 4 | 48 |  |       .Take(pageSize) | 
|  | 4 | 49 |  |       .Select(t => new LgdxUserListBusinessModel { | 
|  | 4 | 50 |  |         Id = Guid.Parse(t.Id!), | 
|  | 4 | 51 |  |         Name = t.Name!, | 
|  | 4 | 52 |  |         UserName = t.UserName!, | 
|  | 4 | 53 |  |         TwoFactorEnabled = t.TwoFactorEnabled, | 
|  | 4 | 54 |  |         AccessFailedCount = t.AccessFailedCount, | 
|  | 4 | 55 |  |       }) | 
|  | 4 | 56 |  |       .ToListAsync(); | 
|  | 4 | 57 |  |     return (users, PaginationHelper); | 
|  | 4 | 58 |  |   } | 
|  |  | 59 |  |  | 
|  |  | 60 |  |   public async Task<LgdxUserBusinessModel> GetUserAsync(Guid id) | 
|  | 2 | 61 |  |   { | 
|  | 2 | 62 |  |     var user = await _userManager.FindByIdAsync(id.ToString()) ?? throw new LgdxNotFound404Exception(); | 
|  | 1 | 63 |  |     var roles = await _userManager.GetRolesAsync(user); | 
|  | 1 | 64 |  |     return new LgdxUserBusinessModel { | 
|  | 1 | 65 |  |       Id = Guid.Parse(user.Id), | 
|  | 1 | 66 |  |       Name = user.Name!, | 
|  | 1 | 67 |  |       UserName = user.UserName!, | 
|  | 1 | 68 |  |       Email = user.Email!, | 
|  | 1 | 69 |  |       Roles = roles, | 
|  | 1 | 70 |  |       TwoFactorEnabled = user.TwoFactorEnabled, | 
|  | 1 | 71 |  |       AccessFailedCount = user.AccessFailedCount, | 
|  | 1 | 72 |  |       LockoutEnd = user.LockoutEnd?.DateTime, | 
|  | 1 | 73 |  |     }; | 
|  | 1 | 74 |  |   } | 
|  |  | 75 |  |  | 
|  |  | 76 |  |   public async Task<LgdxUserBusinessModel> CreateUserAsync(LgdxUserCreateAdminBusinessModel lgdxUserCreateAdminBusinessM | 
|  | 5 | 77 |  |   { | 
|  | 5 | 78 |  |     var user = new LgdxUser { | 
|  | 5 | 79 |  |       Id = Guid.CreateVersion7().ToString(), | 
|  | 5 | 80 |  |       Email = lgdxUserCreateAdminBusinessModel.Email, | 
|  | 5 | 81 |  |       EmailConfirmed = true, | 
|  | 5 | 82 |  |       LockoutEnabled = true, | 
|  | 5 | 83 |  |       Name = lgdxUserCreateAdminBusinessModel.Name, | 
|  | 5 | 84 |  |       NormalizedEmail = lgdxUserCreateAdminBusinessModel.Email.ToUpper(), | 
|  | 5 | 85 |  |       NormalizedUserName = lgdxUserCreateAdminBusinessModel.UserName.ToUpper(), | 
|  | 5 | 86 |  |       SecurityStamp = Guid.CreateVersion7().ToString(), | 
|  | 5 | 87 |  |       UserName = lgdxUserCreateAdminBusinessModel.UserName | 
|  | 5 | 88 |  |     }; | 
|  | 5 | 89 |  |     if (!string.IsNullOrWhiteSpace(lgdxUserCreateAdminBusinessModel.Password)) | 
|  | 3 | 90 |  |     { | 
|  | 3 | 91 |  |       var result = await _userManager.CreateAsync(user, lgdxUserCreateAdminBusinessModel.Password); | 
|  | 3 | 92 |  |       if (!result.Succeeded) | 
|  | 1 | 93 |  |       { | 
|  | 1 | 94 |  |         throw new LgdxIdentity400Expection(result.Errors); | 
|  |  | 95 |  |       } | 
|  | 2 | 96 |  |     } | 
|  |  | 97 |  |     else | 
|  | 2 | 98 |  |     { | 
|  | 2 | 99 |  |       var result = await _userManager.CreateAsync(user); | 
|  | 2 | 100 |  |       if (!result.Succeeded) | 
|  | 1 | 101 |  |       { | 
|  | 1 | 102 |  |         throw new LgdxIdentity400Expection(result.Errors); | 
|  |  | 103 |  |       } | 
|  | 1 | 104 |  |     } | 
|  |  | 105 |  |  | 
|  |  | 106 |  |     // Add Roles | 
|  | 3 | 107 |  |     var roleToAdd = lgdxUserCreateAdminBusinessModel.Roles; | 
|  | 3 | 108 |  |     var roleAddingResult = await _userManager.AddToRolesAsync(user, roleToAdd); | 
|  | 3 | 109 |  |     if (!roleAddingResult.Succeeded) | 
|  | 1 | 110 |  |     { | 
|  | 1 | 111 |  |       throw new LgdxIdentity400Expection(roleAddingResult.Errors); | 
|  |  | 112 |  |     } | 
|  |  | 113 |  |  | 
|  |  | 114 |  |     // Send Email | 
|  | 2 | 115 |  |     if (string.IsNullOrWhiteSpace(lgdxUserCreateAdminBusinessModel.Password)) | 
|  | 1 | 116 |  |     { | 
|  |  | 117 |  |       // No password is specified | 
|  | 1 | 118 |  |       var token = await _userManager.GeneratePasswordResetTokenAsync(user!); | 
|  | 1 | 119 |  |       await _emailService.SendWellcomePasswordSetEmailAsync( | 
|  | 1 | 120 |  |         lgdxUserCreateAdminBusinessModel.Email, | 
|  | 1 | 121 |  |         lgdxUserCreateAdminBusinessModel.Name, | 
|  | 1 | 122 |  |         lgdxUserCreateAdminBusinessModel.UserName, | 
|  | 1 | 123 |  |         token | 
|  | 1 | 124 |  |       ); | 
|  | 1 | 125 |  |     } | 
|  |  | 126 |  |     else | 
|  | 1 | 127 |  |     { | 
|  |  | 128 |  |       // Password is specified | 
|  | 1 | 129 |  |       await _emailService.SendWelcomeEmailAsync( | 
|  | 1 | 130 |  |         lgdxUserCreateAdminBusinessModel.Email, | 
|  | 1 | 131 |  |         lgdxUserCreateAdminBusinessModel.Name, | 
|  | 1 | 132 |  |         lgdxUserCreateAdminBusinessModel.UserName | 
|  | 1 | 133 |  |       ); | 
|  | 1 | 134 |  |     } | 
|  |  | 135 |  |  | 
|  | 2 | 136 |  |     await _activityLogService.CreateActivityLogAsync(new ActivityLogCreateBusinessModel | 
|  | 2 | 137 |  |     { | 
|  | 2 | 138 |  |       EntityName = nameof(LgdxUser), | 
|  | 2 | 139 |  |       EntityId = user.Id, | 
|  | 2 | 140 |  |       Action = ActivityAction.Create, | 
|  | 2 | 141 |  |     }); | 
|  |  | 142 |  |  | 
|  | 2 | 143 |  |     return new LgdxUserBusinessModel | 
|  | 2 | 144 |  |     { | 
|  | 2 | 145 |  |       Id = Guid.Parse(user.Id), | 
|  | 2 | 146 |  |       Name = user.Name!, | 
|  | 2 | 147 |  |       UserName = user.UserName!, | 
|  | 2 | 148 |  |       Email = user.Email!, | 
|  | 2 | 149 |  |       Roles = lgdxUserCreateAdminBusinessModel.Roles, | 
|  | 2 | 150 |  |       TwoFactorEnabled = user.TwoFactorEnabled, | 
|  | 2 | 151 |  |       AccessFailedCount = user.AccessFailedCount, | 
|  | 2 | 152 |  |     }; | 
|  | 2 | 153 |  |   } | 
|  |  | 154 |  |  | 
|  |  | 155 |  |   public async Task<bool> UpdateUserAsync(Guid id, LgdxUserUpdateAdminBusinessModel lgdxUserUpdateAdminBusinessModel) | 
|  | 5 | 156 |  |   { | 
|  | 5 | 157 |  |     var user = await _userManager.FindByIdAsync(id.ToString()) ?? throw new LgdxNotFound404Exception(); | 
|  |  | 158 |  |  | 
|  | 4 | 159 |  |     user.Name = lgdxUserUpdateAdminBusinessModel.Name; | 
|  | 4 | 160 |  |     user.UserName = lgdxUserUpdateAdminBusinessModel.UserName; | 
|  | 4 | 161 |  |     user.Email = lgdxUserUpdateAdminBusinessModel.Email; | 
|  | 4 | 162 |  |     user.NormalizedEmail = lgdxUserUpdateAdminBusinessModel.Email.ToUpper(); | 
|  | 4 | 163 |  |     user.NormalizedUserName = lgdxUserUpdateAdminBusinessModel.UserName.ToUpper(); | 
|  |  | 164 |  |  | 
|  | 4 | 165 |  |     var result = await _userManager.UpdateAsync(user); | 
|  | 4 | 166 |  |     if (!result.Succeeded) | 
|  | 1 | 167 |  |     { | 
|  | 1 | 168 |  |       throw new LgdxIdentity400Expection(result.Errors); | 
|  |  | 169 |  |     } | 
|  |  | 170 |  |  | 
|  | 3 | 171 |  |     var roles = await _userManager.GetRolesAsync(user); | 
|  | 3 | 172 |  |     var roleToAdd = lgdxUserUpdateAdminBusinessModel.Roles.Except(roles); | 
|  | 3 | 173 |  |     result = await _userManager.AddToRolesAsync(user, roleToAdd); | 
|  | 3 | 174 |  |     if (!result.Succeeded) | 
|  | 1 | 175 |  |     { | 
|  | 1 | 176 |  |       throw new LgdxIdentity400Expection(result.Errors); | 
|  |  | 177 |  |     } | 
|  | 2 | 178 |  |     var roleToRemove = roles.Except(lgdxUserUpdateAdminBusinessModel.Roles); | 
|  | 2 | 179 |  |     result = await _userManager.RemoveFromRolesAsync(user, roleToRemove); | 
|  | 2 | 180 |  |     if (!result.Succeeded) | 
|  | 1 | 181 |  |     { | 
|  | 1 | 182 |  |       throw new LgdxIdentity400Expection(result.Errors); | 
|  |  | 183 |  |     } | 
|  |  | 184 |  |  | 
|  | 1 | 185 |  |     await _activityLogService.CreateActivityLogAsync(new ActivityLogCreateBusinessModel | 
|  | 1 | 186 |  |     { | 
|  | 1 | 187 |  |       EntityName = nameof(LgdxUser), | 
|  | 1 | 188 |  |       EntityId = user.Id, | 
|  | 1 | 189 |  |       Action = ActivityAction.Update, | 
|  | 1 | 190 |  |     }); | 
|  |  | 191 |  |  | 
|  | 1 | 192 |  |     return true; | 
|  | 1 | 193 |  |   } | 
|  |  | 194 |  |  | 
|  |  | 195 |  |   public async Task<bool> UnlockUserAsync(Guid id) | 
|  | 3 | 196 |  |   { | 
|  | 3 | 197 |  |     var user = await _userManager.FindByIdAsync(id.ToString()) ?? throw new LgdxNotFound404Exception(); | 
|  |  | 198 |  |  | 
|  | 2 | 199 |  |     user.AccessFailedCount = 0; | 
|  | 2 | 200 |  |     user.LockoutEnd = null; | 
|  |  | 201 |  |  | 
|  | 2 | 202 |  |     var result = await _userManager.UpdateAsync(user); | 
|  | 2 | 203 |  |     if (!result.Succeeded) | 
|  | 1 | 204 |  |     { | 
|  | 1 | 205 |  |       throw new LgdxIdentity400Expection(result.Errors); | 
|  |  | 206 |  |     } | 
|  |  | 207 |  |  | 
|  | 1 | 208 |  |     await _activityLogService.CreateActivityLogAsync(new ActivityLogCreateBusinessModel | 
|  | 1 | 209 |  |     { | 
|  | 1 | 210 |  |       EntityName = nameof(LgdxUser), | 
|  | 1 | 211 |  |       EntityId = user.Id, | 
|  | 1 | 212 |  |       Action = ActivityAction.UserUnlocked, | 
|  | 1 | 213 |  |     }); | 
|  |  | 214 |  |  | 
|  | 1 | 215 |  |     return true; | 
|  | 1 | 216 |  |   } | 
|  |  | 217 |  |  | 
|  |  | 218 |  |   public async Task<bool> DeleteUserAsync(Guid id, string operatorId) | 
|  | 4 | 219 |  |   { | 
|  | 4 | 220 |  |     var user = await _userManager.FindByIdAsync(id.ToString()) ?? throw new LgdxNotFound404Exception(); | 
|  | 3 | 221 |  |     if (user.Id == operatorId) | 
|  | 1 | 222 |  |     { | 
|  | 1 | 223 |  |       throw new LgdxValidation400Expection(nameof(id), "Cannot delete yourself."); | 
|  |  | 224 |  |     } | 
|  | 2 | 225 |  |     var result = await _userManager.DeleteAsync(user); | 
|  | 2 | 226 |  |     if (!result.Succeeded) | 
|  | 1 | 227 |  |     { | 
|  | 1 | 228 |  |       throw new LgdxIdentity400Expection(result.Errors); | 
|  |  | 229 |  |     } | 
|  |  | 230 |  |  | 
|  | 1 | 231 |  |     await _activityLogService.CreateActivityLogAsync(new ActivityLogCreateBusinessModel | 
|  | 1 | 232 |  |     { | 
|  | 1 | 233 |  |       EntityName = nameof(LgdxUser), | 
|  | 1 | 234 |  |       EntityId = user.Id, | 
|  | 1 | 235 |  |       Action = ActivityAction.Delete, | 
|  | 1 | 236 |  |     }); | 
|  |  | 237 |  |  | 
|  | 1 | 238 |  |     return true; | 
|  | 1 | 239 |  |   } | 
|  |  | 240 |  | } |