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.Application.Services.Interfaces; using MTWorkHR.Core.Email; using MTWorkHR.Core.Entities; using MTWorkHR.Infrastructure.UnitOfWorks; using MTWorkHR.Infrastructure.Entities; using static Org.BouncyCastle.Crypto.Engines.SM2Engine; using System.Web; using System.Data; using MTWorkHR.Core.IDto; using System.Linq.Dynamic.Core; using MTWorkHR.Core.Entities.Base; using MTWorkHR.Infrastructure.EmailService; using Countries.NET.Database; 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; private readonly IOTPService _oTPService; public UserService(ApplicationUserManager userManager, IUnitOfWork unitOfWork , RoleManager roleManager, GlobalInfo globalInfo, AppSettingsConfiguration configuration, IMailSender emailSender , IUserRoleRepository> userRole, IFileService fileService, IOTPService oTPService) { _userManager = userManager; _unitOfWork = unitOfWork; _roleManager = roleManager; _userRole = userRole; _configuration = configuration; _emailSender = emailSender; _globalInfo = globalInfo; _fileService = fileService; _oTPService = oTPService; } 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(PagingInputDto pagingInput) //{ // 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 virtual async Task> GetAll(UserPagingInputDto PagingInputDto) { var query = _userManager.Users .Include(u => u.Qualification).Include(u => u.JobTitle).Include(u => u.University).Include(u => u.Industry).Include(u => u.Country) .AsQueryable(); if (PagingInputDto.Filter != null) { var filter = PagingInputDto.Filter; query = query.Where(u => u.UserName.Contains(filter) || u.Email.Contains(filter) || u.FirstName.Contains(filter) || u.LastName.Contains(filter) || u.FavoriteName.Contains(filter) || u.PhoneNumber.Contains(filter)); } if (PagingInputDto.IndustryId != null) { query = query.Where(u => u.IndustryId == PagingInputDto.IndustryId); } if (PagingInputDto.QualificationId != null) { query = query.Where(u => u.QualificationId == PagingInputDto.QualificationId); } if (PagingInputDto.JobTitleId != null) { query = query.Where(u => u.JobTitleId == PagingInputDto.JobTitleId); } if (PagingInputDto.UniversityId != null) { query = query.Where(u => u.UniversityId == PagingInputDto.UniversityId); } if (PagingInputDto.CountryId != null) { query = query.Where(u => u.CountryId == PagingInputDto.CountryId); } var order = query.OrderBy(PagingInputDto.OrderByField + " " + PagingInputDto.OrderType); var page = order.Skip((PagingInputDto.PageNumber * PagingInputDto.PageSize) - PagingInputDto.PageSize).Take(PagingInputDto.PageSize); var total = await query.CountAsync(); var list = MapperObject.Mapper .Map>(await page.ToListAsync()); var response = new PagingResultDto { Result = list, Total = total }; return response; } public async Task> GetAllEmployees() { 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> GetAllCompanyEmployees() { var employees = await _userManager.GetUsersInRoleAsync("Employee"); var res = employees.Where(e => _globalInfo.CompanyId == null || e.CompanyId == _globalInfo.CompanyId).ToList(); var response = MapperObject.Mapper.Map>(res); return response; } 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 (input.UserAttachments == null ) input.UserAttachments = new List(); if(input.CVAttach != null) { input.UserAttachments.Add(new AttachmentDto { FileData = input.CVAttach, OriginalName = input.CVAttach?.Name,FileName = input.CVAttach?.FileName, AttachmentTypeId = 1 }); } if (input.PassportAttach != null) { input.UserAttachments.Add(new AttachmentDto { FileData = input.PassportAttach, OriginalName = input.PassportAttach?.Name, FileName = input.PassportAttach?.FileName, AttachmentTypeId = 2 }); } if (input.EduCertificateAttach != null) { input.UserAttachments.Add(new AttachmentDto { FileData = input.EduCertificateAttach, OriginalName = input.EduCertificateAttach?.Name, FileName = input.EduCertificateAttach?.FileName, AttachmentTypeId = 3 }); } if (input.ExperienceCertificateAttach != null) { input.UserAttachments.Add(new AttachmentDto { FileData = input.ExperienceCertificateAttach, OriginalName = input.ExperienceCertificateAttach?.Name, FileName = input.ExperienceCertificateAttach?.FileName, AttachmentTypeId = 4 }); } if (input.ProfCertificateAttach != null) { input.UserAttachments.Add(new AttachmentDto { FileData = input.ProfCertificateAttach, OriginalName = input.ProfCertificateAttach?.Name, FileName = input.ProfCertificateAttach?.FileName, AttachmentTypeId = 5 }); } if (!await _fileService.CopyFileToActualFolder(input.UserAttachments.ToList())) throw new AppException(ExceptionEnum.CouldNotMoveFiles); var user = MapperObject.Mapper.Map(input); if(user.UserType == 0) { user.UserType = (int)UserTypeEnum.Employee;//default if not selected } _unitOfWork.BeginTran(); //saving user var result = await _userManager.CreateAsync(user, input.Password); if (!result.Succeeded) { if(result.Errors != null && result.Errors.Count() > 0) { var msg = result.Errors.Select(a => a.Description ).Aggregate((a,b) => a + " /r/n " + b); throw new AppException(msg); } throw new AppException(ExceptionEnum.RecordCreationFailed); } input.Id = user.Id; //saving userRoles if(input.UserRoles == null || input.UserRoles.Count == 0) { var employeeRole = await _roleManager.FindByNameAsync("Employee"); if (employeeRole != null) { await _userManager.AddToRoleAsync(user, "Employee"); } } else { 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(ConfirmEmailDto input) { var user = await _userManager.FindByIdAsync(input.UserId); 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); string codeHtmlVersion = HttpUtility.UrlEncode(token); 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", codeHtmlVersion); 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 async Task IsExpiredToken(ConfirmEmailDto 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 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 email) //Begin forget password { var foundUser = await _userManager.FindByEmailAsync(email); if (foundUser != null) { string oneTimePassword = await _oTPService.RandomOneTimePassword(foundUser.Id); await _oTPService.SentOTPByMail(foundUser.Id, foundUser.Email, oneTimePassword); ForgetPasswordResponseDto res = new ForgetPasswordResponseDto { UserId = foundUser.Id}; return res; } else { throw new AppException(ExceptionEnum.RecordNotExist); } } public async Task VerifyOTP(VerifyOTPDto input) { if (! await _oTPService.VerifyOTP(input.UserId, input.OTP)) throw new AppException(ExceptionEnum.WrongOTP); return true; } public async Task ForgetPassword(ForgetPasswordDto input) { var user = await _userManager.Users.IgnoreQueryFilters().FirstOrDefaultAsync(x => x.Id == input.UserId); if (user == null) throw new AppException(ExceptionEnum.RecordNotExist); string resetToken = await _userManager.GeneratePasswordResetTokenAsync(user); var result = await _userManager.ResetPasswordAsync(user, resetToken, input.Password); if (!result.Succeeded) { if (result.Errors != null && result.Errors.Count() > 0) { var msg = result.Errors.Select(a => a.Description).Aggregate((a, b) => a + " /r/n " + b); throw new AppException(msg); } throw new AppException(ExceptionEnum.RecordCreationFailed); } return result.Succeeded; } 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(); } } }