public async Task <IActionResult> CreateAsync(UserViewModel <TUser> userModel)
        {
            var roles = await _userRoleRepository.ListAsync();

            // populate the role list data not returned in post request
            foreach (var userRole in userModel.User.Roles)
            {
                var role = roles.Where(r => r.ID == userRole.ID).FirstOrDefault();
                userRole.Name         = role.Name;
                userRole.DisplayTitle = role.DisplayTitle;
            }

            string email = userModel.User.Email;

            // validate user e-mail address
            if (email.HasValue())
            {
                if (!_emailValidatorService.IsValidEmail(email))
                {
                    ModelState.AddModelError("InvalidEmail", _localizer[UserErrorMessages.InvalidEmail]);
                }

                var userSpecification = new UserSpecification()
                {
                    Email = email
                };

                var duplicateUser = await _userRepository.ReadAsync(userSpecification);

                if (duplicateUser != null)
                {
                    ModelState.AddModelError("DuplicateUser", _localizer[UserErrorMessages.DuplicateUser]);
                }
            }

            if (!ModelState.IsValid)
            {
                return(PartialView("_Editor", userModel));
            }

            // persist new user to data store
            var newUserID = await _userRepository.CreateAsync(userModel.User, UserID);

            if (newUserID == 0)
            {
                return(NoContent());
            }

            // publish user creation and invitation events so notification services can be called
            userModel.User.ID = newUserID;
            var userDTO          = new UserDTO(userModel.User);
            var userCreatedEvent = new UserCreated(userDTO);
            await _mediator.Publish(userCreatedEvent);

            var uri = Url.Action("ReadAsync", "User", new { id = newUserID });

            return(Created(uri, newUserID));
        }
        public async Task <IActionResult> ForgotPassword(ForgotPasswordViewModel data)
        {
            ViewData["Email"] = data.Email;

            if (!ModelState.IsValid)
            {
                return(PartialView(data));
            }

            if (!_emailValidatorService.IsValidEmail(data.Email))
            {
                ModelState.AddModelError("InvalidEmail", _localizer[AuthenticationErrorMessages.InvalidEmail]);
                return(PartialView(data));
            }

            var userSpecification = new UserSpecification()
            {
                Email = data.Email
            };

            AuthenticationUser = await _userRepository.ReadAsync(userSpecification);

            if (AuthenticationUser is null)
            {
                ModelState.AddModelError("UserDoesNotExist", _localizer[AuthenticationErrorMessages.UserDoesNotExist]);
                return(PartialView(data));
            }

            string token     = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
            var    userDTO   = new UserDTO(AuthenticationUser);
            var    saveToken = await _userPasswordRepository.SavePasswordTokenAsync(userDTO, token);

            if (!saveToken)
            {
                ModelState.AddModelError("ReminderFailed", _localizer[AuthenticationErrorMessages.PasswordReminderFailed]);
                return(PartialView(data));
            }

            var domain = Request.Host.Value;

            domain += (Request.PathBase.Value.HasValue()) ? Request.PathBase.Value : string.Empty;
            var emailSubject = _forgotPasswordEmail.Subject();
            var emailBody    = _forgotPasswordEmail.Body(AuthenticationUser, domain, emailSubject, token);

            await _emailSenderService.SendEmailAsync(data.Email, emailSubject, emailBody);

            data.SendReminderSuccess = true;

            return(PartialView(data));
        }
        public async Task <IActionResult> SetPassword(SetPasswordViewModel data)
        {
            ViewData["Email"] = data.Email;

            if (!ModelState.IsValid)
            {
                return(PartialView(data));
            }

            if (!_emailValidatorService.IsValidEmail(data.Email))
            {
                ModelState.AddModelError("InvalidEmail", _localizer[AuthenticationErrorMessages.InvalidEmail]);
                return(PartialView(data));
            }

            if (data.NewPassword.HasValue() && data.ConfirmNewPassword.HasValue() &&
                data.NewPassword != data.ConfirmNewPassword)
            {
                ModelState.AddModelError("PasswordsDoNotMatch", _localizer[AuthenticationErrorMessages.PasswordsDoNotMatch]);
                return(PartialView(data));
            }

            var tokenResult = await _userPasswordRepository.ValidatePasswordTokenAsync(data.Email, data.Token);

            if (tokenResult == TokenVerificationResult.Invalid)
            {
                ModelState.AddModelError("InvalidToken", _localizer[AuthenticationErrorMessages.InvalidToken]);
                return(PartialView(data));
            }

            if (tokenResult == TokenVerificationResult.Expired)
            {
                ModelState.AddModelError("ExpiredToken", _localizer[AuthenticationErrorMessages.ExpiredToken]);
                return(PartialView(data));
            }

            var userSpecification = new UserSpecification()
            {
                Email = data.Email
            };

            AuthenticationUser = await _userRepository.ReadAsync(userSpecification);

            if (AuthenticationUser is null)
            {
                ModelState.AddModelError("UserDoesNotExist", _localizer[AuthenticationErrorMessages.UserDoesNotExist]);
                return(PartialView(data));
            }

            var passwordValidationErrors = _passwordValidatorService.ValidatePassword(data.NewPassword);

            if (passwordValidationErrors.Count > 0)
            {
                ModelState.AddModelError(
                    key: "PasswordValidationErrors",
                    errorMessage: _localizer[_passwordValidatorService.GetPasswordValidationErrorMessage()]
                    );
                return(PartialView(data));
            }

            string hashedPassword = _passwordHasherService.HashPassword(AuthenticationUser, data.NewPassword);
            var    userDTO        = new UserDTO(AuthenticationUser);
            var    setPassword    = await _userPasswordRepository.SetPasswordAsync(userDTO, hashedPassword);

            if (!setPassword)
            {
                ModelState.AddModelError("PasswordSetFailed", _localizer[AuthenticationErrorMessages.PasswordSetFailed]);
                return(PartialView());
            }

            data.SetPasswordSuccess = true;

            return(PartialView(data));
        }