using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.WebUtilities; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using MTWorkHR.Application.Identity; using MTWorkHR.Application.Mapper; using MTWorkHR.Application.Models; using MTWorkHR.Core.Global; using MTWorkHR.Core.IRepositories; using MTWorkHR.Core.UnitOfWork; using MTWorkHR.Identity.Entities; using MTWorkHR.Application.Services.Interfaces; using MTWorkHR.Core.Email; using MTWorkHR.Core.Entities; using MTWorkHR.Infrastructure.UnitOfWorks; namespace MTWorkHR.Application.Services { public class UserService : IUserService { private readonly RoleManager _roleManager; private readonly ApplicationUserManager _userManager; private readonly IUnitOfWork _unitOfWork; private readonly IUserRoleRepository> _userRole; private readonly AppSettingsConfiguration _configuration; private readonly IMailSender _emailSender; private readonly GlobalInfo _globalInfo; private readonly IFileService _fileService; public UserService(ApplicationUserManager userManager, IUnitOfWork unitOfWork , RoleManager roleManager, GlobalInfo globalInfo, AppSettingsConfiguration configuration, IMailSender emailSender , IUserRoleRepository> userRole, IFileService fileService) { _userManager = userManager; _unitOfWork = unitOfWork; _roleManager = roleManager; _userRole = userRole; _configuration = configuration; _emailSender = emailSender; _globalInfo = globalInfo; _fileService = fileService; } public async Task GetById(string id) { var entity = await _userManager.Users .Include(x => x.UserRoles) .Include(x => x.UserAddress) .Include(x => x.UserAttachments) .FirstOrDefaultAsync(x => x.Id == id); var response = MapperObject.Mapper.Map(entity); return response; } public async Task> GetAll() { var employees = await _userManager.GetUsersInRoleAsync("Employee"); return employees.Select(e => new UserDto { Email = e.Email, FirstName = e.FirstName, LastName = e.LastName, Id = e.Id }).ToList(); } public async Task Delete(string id) { var user = await _userManager.FindByIdAsync(id); if (user != null) { user.IsDeleted = true; await _userManager.UpdateAsync(user); } } public async Task Create(UserDto input) { var emailExists = await _userManager.FindByEmailAsync(input.Email); if (emailExists != null) throw new AppException(ExceptionEnum.RecordAlreadyExist); var phoneExists = await _userManager.FindByAnyAsync(input.PhoneNumber); if (phoneExists != null) throw new AppException(ExceptionEnum.RecordAlreadyExist); var userExists = await _userManager.FindByAnyAsync(input.UserName); if (userExists != null) throw new AppException(ExceptionEnum.RecordAlreadyExist); //loop for given list of attachment, and move each file from Temp path to Actual path // _fileService.UploadFiles(files); if (!await _fileService.CopyFileToActualFolder(input.UserAttachments.ToList())) throw new AppException(ExceptionEnum.CouldNotMoveFiles); var user = MapperObject.Mapper.Map(input); _unitOfWork.BeginTran(); //saving user var result = await _userManager.CreateAsync(user, input.Password); if (!result.Succeeded) throw new AppException(ExceptionEnum.RecordCreationFailed); input.Id = user.Id; //saving userRoles var userRoles = MapperObject.Mapper.Map>>(input.UserRoles); foreach (var role in userRoles) { role.UserId = user.Id; if (await _roleManager.FindByIdAsync(role.RoleId) == null) throw new AppException(ExceptionEnum.RecordNotExist); var roleOb = input.UserRoles?.FirstOrDefault(r => r.RoleId == role.RoleId); var roleName = roleOb != null ? roleOb.RoleName : "Employee"; await _userManager.AddToRoleAsync(user, roleName); } // await _userRole.AddRangeAsync(userRoles); await _unitOfWork.CompleteAsync(); _unitOfWork.CommitTran(); try { var resultPassReset = await GetConfirmEmailURL(user.Id); var sendMailResult = await _emailSender.SendEmail(new EmailMessage { Subject = "Register Confirmation", To = input.Email, Body = "Please Set Your Password (this link will expired after 24 hours)" , url = resultPassReset.Item1, userId = user.Id }); if (!sendMailResult) { throw new AppException("User created, but could not send the email!"); } } catch { throw new AppException("User created, but could not send the email!"); } return input; } public async Task ConfirmEmail(ForgetPasswordDto input) { var user = await _userManager.FindByEmailAsync(input.Email); if (user == null) throw new AppException(ExceptionEnum.RecordNotExist); var result = await _userManager.ConfirmEmailAsync(user, input.Token); return result.Succeeded; } private async Task> GetResetPasswordURL(string userId) { var user = await _userManager.Users.FirstOrDefaultAsync(x => !x.IsDeleted && x.Id.Equals(userId)); if (user == null) throw new AppException(ExceptionEnum.RecordNotExist); string code = await _userManager.GeneratePasswordResetTokenAsync(user); var route = "auth/ConfirmEmail"; var origin = _configuration.JwtSettings.Audience; var endpointUri = new Uri(string.Concat($"{origin}/", route)); var userURL = QueryHelpers.AddQueryString(endpointUri.ToString(), "userId", user.Id); var passwordResetURL = QueryHelpers.AddQueryString(userURL.ToString(), "token", code); return new Tuple(passwordResetURL, user.Email); } private async Task> GetConfirmEmailURL(string userId) { var user = await _userManager.Users.FirstOrDefaultAsync(x => !x.IsDeleted && x.Id.Equals(userId)); if (user == null) throw new AppException(ExceptionEnum.RecordNotExist); string token = await _userManager.GenerateEmailConfirmationTokenAsync(user); var route = "auth/ConfirmEmail"; var origin = _configuration.JwtSettings.Audience; var endpointUri = new Uri(string.Concat($"{origin}/", route)); var userURL = QueryHelpers.AddQueryString(endpointUri.ToString(), "userId", user.Id); var confirmEmailUrl = QueryHelpers.AddQueryString(userURL.ToString(), "token", token); return new Tuple(confirmEmailUrl, user.Email); } public async Task Update(UserDto input) { try { var entity = await _userManager.Users.FirstOrDefaultAsync(x => x.Id == input.Id); if (entity == null) throw new AppException(ExceptionEnum.RecordNotExist); MapperObject.Mapper.Map(input, entity); _unitOfWork.BeginTran(); //saving user var result = await _userManager.UpdateAsync(entity); if (!result.Succeeded) throw new AppException(ExceptionEnum.RecordUpdateFailed); //**saving userRoles //add new user roles var exsitedRolesIds = await _userRole.GetUserRoleIdsByUserID(input.Id); if (input.UserRoles == null) input.UserRoles = new List(); var newAddedRoles = MapperObject.Mapper.Map>>(input.UserRoles.Where(x => !exsitedRolesIds.Contains(x.RoleId))); newAddedRoles.ForEach(x => x.UserId = input.Id); await _userRole.AddRangeAsync(newAddedRoles); //delete removed roles var rolesIds = input.UserRoles.Select(x => x.RoleId).ToArray(); var removedRoles = await _userRole.GetRemovedUserRoleIdsByUserID(input.Id, rolesIds); await _userRole.DeleteAsync(removedRoles.AsEnumerable()); await _unitOfWork.CompleteAsync(); _unitOfWork.CommitTran(); } catch (Exception e) { throw e; } return input; } public Task UpdateWithoutChildren(UserDto input) { throw new NotImplementedException(); } public async Task IsExpiredToken(ForgetPasswordDto input) { var user = await _userManager.Users.IgnoreQueryFilters().FirstOrDefaultAsync(x => x.Id == input.UserId); if (user == null) throw new AppException(ExceptionEnum.RecordNotExist); var purpose = UserManager.ResetPasswordTokenPurpose; var result = await _userManager.VerifyUserTokenAsync(user, "Default", purpose, input.Token); return !result; } public async Task ForgetPassword(ForgetPasswordDto model) { var user = await _userManager.Users.IgnoreQueryFilters().FirstOrDefaultAsync(x => x.Id == model.UserId); if (user == null) throw new AppException(ExceptionEnum.RecordNotExist); var result = await _userManager.ResetPasswordAsync(user, model.Token, model.Password); return result.Succeeded; } public async Task ResetPassword(ResetPasswordDto input) { var user = await _userManager.FindByIdAsync(_globalInfo.UserId); if (user == null) throw new AppException(ExceptionEnum.RecordNotExist); if (!await _userManager.CheckPasswordAsync(user, input.OldPassword)) throw new AppException(ExceptionEnum.WrongCredentials); var token = await _userManager.GeneratePasswordResetTokenAsync(user); var result = await _userManager.ResetPasswordAsync(user, token, input.NewPassword); if (!result.Succeeded) throw new AppException(ExceptionEnum.RecordUpdateFailed); return true; } public async Task ForgetPasswordMail(string userId) { var resultPassReset = await GetResetPasswordURL(userId); await _emailSender.SendEmail(new EmailMessage { Subject = "Register Confirmation", To = resultPassReset.Item2, Body = "Forget Your Password, link will expired after 24 hours", url = resultPassReset.Item1, userId = userId }); } public async Task StopUser(string userId) { var entity = await _userManager.Users.FirstOrDefaultAsync(x => x.Id == userId); if (entity == null) throw new AppException(ExceptionEnum.RecordNotExist); if (!entity.IsStopped) { entity.IsStopped = true; await _unitOfWork.CompleteAsync(); } } public async Task ActiveUser(string userId) { var entity = await _userManager.Users.FirstOrDefaultAsync(x => x.Id == userId); if (entity == null) throw new AppException(ExceptionEnum.RecordNotExist); entity.IsStopped = false; entity.AccessFailedCount = 0; entity.LockoutEnabled = false; entity.LockoutEnd = null; await _unitOfWork.CompleteAsync(); } } }