/// <summary>
        /// Changes the users password
        /// </summary>
        /// <param name="data"></param>
        /// <returns>
        /// If the password is being reset it will return the newly reset password, otherwise will return an empty value
        /// </returns>
        public ModelWithNotifications <string> PostChangePassword(ChangingPasswordModel data)
        {
            var userProvider = Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider();

            //TODO: WE need to support this! - requires UI updates, etc...
            if (userProvider.RequiresQuestionAndAnswer)
            {
                throw new NotSupportedException("Currently the user editor does not support providers that have RequiresQuestionAndAnswer specified");
            }

            var passwordChangeResult = Members.ChangePassword(Security.CurrentUser.Username, data, userProvider);

            if (passwordChangeResult.Success)
            {
                //even if we weren't resetting this, it is the correct value (null), otherwise if we were resetting then it will contain the new pword
                var result = new ModelWithNotifications <string>(passwordChangeResult.Result.ResetPassword);
                result.AddSuccessNotification(ui.Text("user", "password"), ui.Text("user", "passwordChanged"));
                return(result);
            }

            //it wasn't successful, so add the change error to the model state, we've name the property alias _umb_password on the form
            // so that is why it is being used here.
            ModelState.AddPropertyError(
                passwordChangeResult.Result.ChangeError,
                string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix));

            throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState));
        }
        private async Task <bool> ValidateMemberDataAsync(MemberSave contentItem)
        {
            if (contentItem.Name.IsNullOrWhiteSpace())
            {
                ModelState.AddPropertyError(
                    new ValidationResult("Invalid user name", new[] { "value" }),
                    $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}login");
                return(false);
            }

            if (contentItem.Password != null && !contentItem.Password.NewPassword.IsNullOrWhiteSpace())
            {
                IdentityResult validPassword = await _memberManager.ValidatePasswordAsync(contentItem.Password.NewPassword);

                if (!validPassword.Succeeded)
                {
                    ModelState.AddPropertyError(
                        new ValidationResult("Invalid password: "******"value" }),
                        $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}password");
                    return(false);
                }
            }

            IMember?byUsername = _memberService.GetByUsername(contentItem.Username);

            if (byUsername != null && byUsername.Key != contentItem.Key)
            {
                ModelState.AddPropertyError(
                    new ValidationResult("Username is already in use", new[] { "value" }),
                    $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}login");
                return(false);
            }

            IMember?byEmail = _memberService.GetByEmail(contentItem.Email);

            if (byEmail != null && byEmail.Key != contentItem.Key)
            {
                ModelState.AddPropertyError(
                    new ValidationResult("Email address is already in use", new[] { "value" }),
                    $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}email");
                return(false);
            }

            return(true);
        }
        public async Task <ActionResult> EditEmail(EditEmailViewModel model)
        {
            if (ModelState.IsValid)
            {
                var user = _userService.Get(IdentityHelpers.GetUserId(User.Identity));

                if (_userService.IsPasswordMatchForUser(user.UserID, model.Password))
                {
                    String originalEmail = user.Email;

                    //Check if the new email address is already assosciated with another account
                    if (_userService.GetByEmail(model.NewEmailAddress) != null)
                    {
                        _userService.SetEmailAddress(user.UserID, model.NewEmailAddress);

                        _uow.Save();

                        //Send notification email
                        String subject = "Account Email Changed";
                        String body    = "This email is to inform you that the email address associated with your account has been changed.";

                        var message = new MailMessage("*****@*****.**", originalEmail, subject, body);

                        await _emailService.SendMessageAsync(message);

                        ViewBag.SuccessMessage = "Your email address has been changed.";

                        ModelState.Clear();

                        return(View());
                    }

                    ModelState.AddPropertyError <EditEmailViewModel>(m => m.NewEmailAddress, "An account with this email already exists.");
                }
                else
                {
                    ModelState.AddPropertyError <EditEmailViewModel>(m => m.Password, "Invalid password.");

                    return(View(model));
                }
            }

            //We got this far, some.panel .panel-default failed
            return(View(model));
        }
        public async Task <ActionResult> ForgotPassword(ForgotPasswordViewModel model)
        {
            if (ModelState.IsValid)
            {
                var user = _userService.GetByEmailWithMembership(model.Email);

                if (user != null)
                {
                    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
                    {
                        try
                        {
                            var verificationToken = _userService.GeneratePasswordVerificationToken(user.UserID);

                            _uow.Save();

                            String changePasswordLink = Url.Action("EditPasswordForgot", "Account", new { confirmationToken = verificationToken }, Request.Url.Scheme);

                            String subject = "Forgotten Password Request";
                            String body    = "A forgotten password request has been made, please enter this link in your browser's address bar "
                                             + "to recover your account."
                                             + changePasswordLink;

                            await _userService.SendEmailAsync(user.UserID, subject, body);

                            scope.Complete();

                            ViewBag.SuccessMessage = "An email has been sent detailing how to recover your account.";

                            return(View());
                        }
                        catch (Exception)
                        {
                            throw;
                        }
                    }
                }

                ModelState.AddPropertyError <ForgotPasswordViewModel>(m => m.Email, "Invalid Email.");
            }

            return(View(model));
        }
Example #5
0
        /// <summary>
        /// This is going to create the user with the membership provider and check for validation
        /// </summary>
        /// <param name="contentItem"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        /// <remarks>
        /// Depending on if the Umbraco membership provider is active or not, the process differs slightly:
        ///
        /// * If the umbraco membership provider is used - we create the membership user first with the membership provider, since
        ///     it's the umbraco membership provider, this writes to the umbraco tables. When that is complete we re-fetch the IMember
        ///     model data from the db. In this case we don't care what the provider user key is.
        /// * If we're using a non-umbraco membership provider - we check if there is a 'Member' member type - if so
        ///     we create an empty IMember instance first (of type 'Member'), this gives us a unique ID (GUID)
        ///     that we then use to create the member in the custom membership provider. This acts as the link between Umbraco data and
        ///     the custom membership provider data. This gives us the ability to eventually have custom membership properties but still use
        ///     a custom membership provider. If there is no 'Member' member type, then we will simply just create the membership provider member
        ///     with no link to our data.
        ///
        /// If this is successful, it will go and re-fetch the IMember from the db because it will now have an ID because the Umbraco provider
        /// uses the umbraco data store - then of course we need to re-map it to the saved property values.
        /// </remarks>
        private MembershipUser CreateWithMembershipProvider(MemberSave contentItem, out MembershipCreateStatus status)
        {
            MembershipUser membershipUser;

            switch (MembershipScenario)
            {
            case MembershipScenario.NativeUmbraco:
                //We are using the umbraco membership provider, create the member using the membership provider first.
                var umbracoMembershipProvider = (UmbracoMembershipProviderBase)_provider;
                // TODO: We are not supporting q/a - passing in empty here
                membershipUser = umbracoMembershipProvider.CreateUser(
                    contentItem.ContentTypeAlias, contentItem.Username,
                    contentItem.Password.NewPassword,
                    contentItem.Email, "", "",
                    contentItem.IsApproved,
                    Guid.NewGuid(),     //since it's the umbraco provider, the user key here doesn't make any difference
                    out status);

                break;

            case MembershipScenario.CustomProviderWithUmbracoLink:
                //We are using a custom membership provider, we'll create an empty IMember first to get the unique id to use
                // as the provider user key.
                //create it - this persisted item has already been set in the MemberBinder based on the 'Member' member type:
                Services.MemberService.Save(contentItem.PersistedContent);

                // TODO: We are not supporting q/a - passing in empty here
                membershipUser = _provider.CreateUser(
                    contentItem.Username,
                    contentItem.Password.NewPassword,
                    contentItem.Email,
                    "TEMP",                           //some membership provider's require something here even if q/a is disabled!
                    "TEMP",                           //some membership provider's require something here even if q/a is disabled!
                    contentItem.IsApproved,
                    contentItem.PersistedContent.Key, //custom membership provider, we'll link that based on the IMember unique id (GUID)
                    out status);

                break;

            case MembershipScenario.StandaloneCustomProvider:
                // we don't have a member type to use so we will just create the basic membership user with the provider with no
                // link back to the umbraco data

                var newKey = Guid.NewGuid();
                // TODO: We are not supporting q/a - passing in empty here
                membershipUser = _provider.CreateUser(
                    contentItem.Username,
                    contentItem.Password.NewPassword,
                    contentItem.Email,
                    "TEMP",     //some membership provider's require something here even if q/a is disabled!
                    "TEMP",     //some membership provider's require something here even if q/a is disabled!
                    contentItem.IsApproved,
                    newKey,
                    out status);

                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            // TODO: Localize these!
            switch (status)
            {
            case MembershipCreateStatus.Success:

                //map the key back
                contentItem.Key = membershipUser.ProviderUserKey.TryConvertTo <Guid>().Result;
                contentItem.PersistedContent.Key = contentItem.Key;

                //if the comments are there then we need to save them
                if (contentItem.Comments.IsNullOrWhiteSpace() == false)
                {
                    membershipUser.Comment = contentItem.Comments;
                    _provider.UpdateUser(membershipUser);
                }

                RefetchMemberData(contentItem, LookupType.ByUserName);

                break;

            case MembershipCreateStatus.InvalidUserName:
                ModelState.AddPropertyError(
                    new ValidationResult("Invalid user name", new[] { "value" }),
                    string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                break;

            case MembershipCreateStatus.InvalidPassword:
                ModelState.AddPropertyError(
                    new ValidationResult("Invalid password", new[] { "value" }),
                    string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                break;

            case MembershipCreateStatus.InvalidQuestion:
            case MembershipCreateStatus.InvalidAnswer:
                throw new NotSupportedException("Currently the member editor does not support providers that have RequiresQuestionAndAnswer specified");

            case MembershipCreateStatus.InvalidEmail:
                ModelState.AddPropertyError(
                    new ValidationResult("Invalid email", new[] { "value" }),
                    string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                break;

            case MembershipCreateStatus.DuplicateUserName:
                ModelState.AddPropertyError(
                    new ValidationResult("Username is already in use", new[] { "value" }),
                    string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                break;

            case MembershipCreateStatus.DuplicateEmail:
                ModelState.AddPropertyError(
                    new ValidationResult("Email address is already in use", new[] { "value" }),
                    string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                break;

            case MembershipCreateStatus.InvalidProviderUserKey:
                ModelState.AddPropertyError(
                    //specify 'default' just so that it shows up as a notification - is not assigned to a property
                    new ValidationResult("Invalid provider user key"), "default");
                break;

            case MembershipCreateStatus.DuplicateProviderUserKey:
                ModelState.AddPropertyError(
                    //specify 'default' just so that it shows up as a notification - is not assigned to a property
                    new ValidationResult("Duplicate provider user key"), "default");
                break;

            case MembershipCreateStatus.ProviderError:
            case MembershipCreateStatus.UserRejected:
                ModelState.AddPropertyError(
                    //specify 'default' just so that it shows up as a notification - is not assigned to a property
                    new ValidationResult("User could not be created (rejected by provider)"), "default");
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(membershipUser);
        }
Example #6
0
        /// <summary>
        /// Update the membership user using the membership provider (for things like email, etc...)
        /// If a password change is detected then we'll try that too.
        /// </summary>
        /// <param name="contentItem"></param>
        /// <returns>
        /// If the password has been reset then this method will return the reset/generated password, otherwise will return null.
        /// </returns>
        private string UpdateWithMembershipProvider(MemberSave contentItem)
        {
            //Get the member from the provider

            var membershipUser = _provider.GetUser(contentItem.PersistedContent.Key, false);

            if (membershipUser == null)
            {
                //This should never happen! so we'll let it YSOD if it does.
                throw new InvalidOperationException("Could not get member from membership provider " + _provider.Name + " with key " + contentItem.PersistedContent.Key);
            }

            var shouldReFetchMember = false;
            var providedUserName    = contentItem.PersistedContent.Username;

            //if the user doesn't have access to sensitive values, then we need to check if any of the built in member property types
            //have been marked as sensitive. If that is the case we cannot change these persisted values no matter what value has been posted.
            //There's only 3 special ones we need to deal with that are part of the MemberSave instance
            if (Security.CurrentUser.HasAccessToSensitiveData() == false)
            {
                var memberType          = Services.MemberTypeService.Get(contentItem.PersistedContent.ContentTypeId);
                var sensitiveProperties = memberType
                                          .PropertyTypes.Where(x => memberType.IsSensitiveProperty(x.Alias))
                                          .ToList();

                foreach (var sensitiveProperty in sensitiveProperties)
                {
                    //if found, change the value of the contentItem model to the persisted value so it remains unchanged
                    switch (sensitiveProperty.Alias)
                    {
                    case Constants.Conventions.Member.Comments:
                        contentItem.Comments = contentItem.PersistedContent.Comments;
                        break;

                    case Constants.Conventions.Member.IsApproved:
                        contentItem.IsApproved = contentItem.PersistedContent.IsApproved;
                        break;

                    case Constants.Conventions.Member.IsLockedOut:
                        contentItem.IsLockedOut = contentItem.PersistedContent.IsLockedOut;
                        break;
                    }
                }
            }

            //Update the membership user if it has changed
            try
            {
                var requiredUpdating = Members.UpdateMember(membershipUser, _provider,
                                                            contentItem.Email.Trim(),
                                                            contentItem.IsApproved,
                                                            comment: contentItem.Comments);

                if (requiredUpdating.Success)
                {
                    //re-map these values
                    shouldReFetchMember = true;
                }
            }
            catch (Exception ex)
            {
                Logger.Warn <MemberController>(ex, "Could not update member, the provider returned an error");
                ModelState.AddPropertyError(
                    //specify 'default' just so that it shows up as a notification - is not assigned to a property
                    new ValidationResult("Could not update member, the provider returned an error: " + ex.Message + " (see log for full details)"), "default");
            }

            //if they were locked but now they are trying to be unlocked
            if (membershipUser.IsLockedOut && contentItem.IsLockedOut == false)
            {
                try
                {
                    var result = _provider.UnlockUser(membershipUser.UserName);
                    if (result == false)
                    {
                        //it wasn't successful - but it won't really tell us why.
                        ModelState.AddModelError("custom", "Could not unlock the user");
                    }
                    else
                    {
                        shouldReFetchMember = true;
                    }
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("custom", ex);
                }
            }
            else if (membershipUser.IsLockedOut == false && contentItem.IsLockedOut)
            {
                //NOTE: This should not ever happen unless someone is mucking around with the request data.
                //An admin cannot simply lock a user, they get locked out by password attempts, but an admin can un-approve them
                ModelState.AddModelError("custom", "An admin cannot lock a user");
            }

            //password changes ?
            if (contentItem.Password == null)
            {
                //If the provider has changed some values, these values need to be reflected in the member object
                //that will get mapped to the display object
                if (shouldReFetchMember)
                {
                    RefetchMemberData(contentItem, LookupType.ByKey);
                    RestoreProvidedUserName(contentItem, providedUserName);
                }

                return(null);
            }

            var passwordChangeResult = Members.ChangePassword(membershipUser.UserName, contentItem.Password, _provider);

            if (passwordChangeResult.Success)
            {
                //If the provider has changed some values, these values need to be reflected in the member object
                //that will get mapped to the display object
                if (shouldReFetchMember)
                {
                    RefetchMemberData(contentItem, LookupType.ByKey);
                    RestoreProvidedUserName(contentItem, providedUserName);
                }

                //even if we weren't resetting this, it is the correct value (null), otherwise if we were resetting then it will contain the new pword
                return(passwordChangeResult.Result.ResetPassword);
            }

            //it wasn't successful, so add the change error to the model state
            ModelState.AddPropertyError(
                passwordChangeResult.Result.ChangeError,
                string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix));

            return(null);
        }
Example #7
0
        /// <summary>
        /// Update the membership user using the membership provider (for things like email, etc...)
        /// If a password change is detected then we'll try that too.
        /// </summary>
        /// <param name="contentItem"></param>
        /// <returns>
        /// If the password has been reset then this method will return the reset/generated password, otherwise will return null.
        /// </returns>
        private string UpdateWithMembershipProvider(MemberSave contentItem)
        {
            //Get the member from the provider

            var membershipUser = _provider.GetUser(contentItem.PersistedContent.Key, false);

            if (membershipUser == null)
            {
                //This should never happen! so we'll let it YSOD if it does.
                throw new InvalidOperationException("Could not get member from membership provider " + _provider.Name + " with key " + contentItem.PersistedContent.Key);
            }

            var shouldReFetchMember = false;
            var providedUserName    = contentItem.PersistedContent.Username;

            //Update the membership user if it has changed
            try
            {
                var requiredUpdating = Members.UpdateMember(membershipUser, _provider,
                                                            contentItem.Email.Trim(),
                                                            contentItem.IsApproved,
                                                            comment: contentItem.Comments);

                if (requiredUpdating.Success)
                {
                    //re-map these values
                    shouldReFetchMember = true;
                }
            }
            catch (Exception ex)
            {
                LogHelper.WarnWithException <MemberController>("Could not update member, the provider returned an error", ex);
                ModelState.AddPropertyError(
                    //specify 'default' just so that it shows up as a notification - is not assigned to a property
                    new ValidationResult("Could not update member, the provider returned an error: " + ex.Message + " (see log for full details)"), "default");
            }

            //if they were locked but now they are trying to be unlocked
            if (membershipUser.IsLockedOut && contentItem.IsLockedOut == false)
            {
                try
                {
                    var result = _provider.UnlockUser(membershipUser.UserName);
                    if (result == false)
                    {
                        //it wasn't successful - but it won't really tell us why.
                        ModelState.AddModelError("custom", "Could not unlock the user");
                    }
                    else
                    {
                        shouldReFetchMember = true;
                    }
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("custom", ex);
                }
            }
            else if (membershipUser.IsLockedOut == false && contentItem.IsLockedOut)
            {
                //NOTE: This should not ever happen unless someone is mucking around with the request data.
                //An admin cannot simply lock a user, they get locked out by password attempts, but an admin can un-approve them
                ModelState.AddModelError("custom", "An admin cannot lock a user");
            }

            //password changes ?
            if (contentItem.Password == null)
            {
                //If the provider has changed some values, these values need to be reflected in the member object
                //that will get mapped to the display object
                if (shouldReFetchMember)
                {
                    RefetchMemberData(contentItem, LookupType.ByKey);
                    RestoreProvidedUserName(contentItem, providedUserName);
                }

                return(null);
            }

            var passwordChangeResult = Members.ChangePassword(membershipUser.UserName, contentItem.Password, _provider);

            if (passwordChangeResult.Success)
            {
                //If the provider has changed some values, these values need to be reflected in the member object
                //that will get mapped to the display object
                if (shouldReFetchMember)
                {
                    RefetchMemberData(contentItem, LookupType.ByKey);
                    RestoreProvidedUserName(contentItem, providedUserName);
                }

                //even if we weren't resetting this, it is the correct value (null), otherwise if we were resetting then it will contain the new pword
                return(passwordChangeResult.Result.ResetPassword);
            }

            //it wasn't successful, so add the change error to the model state
            ModelState.AddPropertyError(
                passwordChangeResult.Result.ChangeError,
                string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix));

            return(null);
        }
        /// <summary>
        /// Create a member from the supplied member content data
        ///
        /// All member password processing and creation is done via the identity manager
        /// </summary>
        /// <param name="contentItem">Member content data</param>
        /// <returns>The identity result of the created member</returns>
        private async Task <ActionResult <bool> > CreateMemberAsync(MemberSave contentItem)
        {
            IMemberType?memberType = _memberTypeService.Get(contentItem.ContentTypeAlias);

            if (memberType == null)
            {
                throw new InvalidOperationException($"No member type found with alias {contentItem.ContentTypeAlias}");
            }

            var identityMember = MemberIdentityUser.CreateNew(
                contentItem.Username,
                contentItem.Email,
                memberType.Alias,
                contentItem.IsApproved,
                contentItem.Name);

            IdentityResult created = await _memberManager.CreateAsync(identityMember, contentItem.Password?.NewPassword);

            if (created.Succeeded == false)
            {
                MemberDisplay?forDisplay = _umbracoMapper.Map <MemberDisplay>(contentItem.PersistedContent);
                foreach (IdentityError error in created.Errors)
                {
                    switch (error.Code)
                    {
                    case nameof(IdentityErrorDescriber.InvalidUserName):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;

                    case nameof(IdentityErrorDescriber.PasswordMismatch):
                    case nameof(IdentityErrorDescriber.PasswordRequiresDigit):
                    case nameof(IdentityErrorDescriber.PasswordRequiresLower):
                    case nameof(IdentityErrorDescriber.PasswordRequiresNonAlphanumeric):
                    case nameof(IdentityErrorDescriber.PasswordRequiresUniqueChars):
                    case nameof(IdentityErrorDescriber.PasswordRequiresUpper):
                    case nameof(IdentityErrorDescriber.PasswordTooShort):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;

                    case nameof(IdentityErrorDescriber.InvalidEmail):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;

                    case nameof(IdentityErrorDescriber.DuplicateUserName):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;

                    case nameof(IdentityErrorDescriber.DuplicateEmail):
                        ModelState.AddPropertyError(
                            new ValidationResult(error.Description, new[] { "value" }),
                            string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
                        break;
                    }
                }
                return(ValidationProblem(forDisplay, ModelState));
            }

            // now re-look up the member, which will now exist
            IMember?member = _memberService.GetByEmail(contentItem.Email);

            if (member is null)
            {
                return(false);
            }

            // map the save info over onto the user
            member = _umbracoMapper.Map <MemberSave, IMember>(contentItem, member);

            int creatorId = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.Id ?? -1;

            member.CreatorId = creatorId;

            // assign the mapped property values that are not part of the identity properties
            string[] builtInAliases = ConventionsHelper.GetStandardPropertyTypeStubs(_shortStringHelper).Select(x => x.Key).ToArray();
            foreach (ContentPropertyBasic property in contentItem.Properties)
            {
                if (builtInAliases.Contains(property.Alias) == false)
                {
                    member.Properties[property.Alias]?.SetValue(property.Value);
                }
            }

            // now the member has been saved via identity, resave the member with mapped content properties
            _memberService.Save(member);
            contentItem.PersistedContent = member;

            ActionResult <bool> rolesChanged = await AddOrUpdateRoles(contentItem.Groups, identityMember);

            if (!rolesChanged.Value && rolesChanged.Result != null)
            {
                return(rolesChanged.Result);
            }

            return(true);
        }