/// <summary>
 /// Converts the user to membership user.
 /// </summary>
 /// <param name="user">The user.</param>
 /// <param name="providerUserKey">The provider user key.</param>
 /// <returns></returns>
 private MembershipUser ConvertUserToMembershipUser(User user)
 {
     return new MembershipUser(Name, user.Username, user.Id, user.Email, user.PasswordQuestion,
                               user.Id.ToString(), user.IsApproved, false, user.UtcCreated.DateTime, user.LastLoginDate.DateTime,
                               user.LastActivityDate.DateTime, user.LastPasswordChangeDate.DateTime, DateTime.MinValue);
 }
        /// <summary>
        /// Processes the submit.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="entity">The entity.</param>
        /// <returns></returns>
        protected ActionResult ProcessSubmit(UserEditorModel model, User entity)
        {
            Mandate.ParameterNotNull(model, "model");

            //bind it's data
            model.BindModel(this);
          
            //if there's model errors, return the view
            if (!ModelState.IsValid)
            {
                AddValidationErrorsNotification();
                return View("Edit", model);
            }

            //persist the data
            using (var uow = Hive.Create<ISecurityStore>())
            {
                // Map the user
                if (entity == null)
                {
                    //map to new entity, set default date values
                    model.LastPasswordChangeDate = DateTime.UtcNow;
                    model.LastActivityDate = DateTime.UtcNow;
                    model.LastLoginDate = DateTime.UtcNow;
                    entity = BackOfficeRequestContext.Application.FrameworkContext.TypeMappers.Map<UserEditorModel, User>(model);
                }
                else
                {
                    //map to existing entity
                    BackOfficeRequestContext.Application.FrameworkContext.TypeMappers.Map(model, entity);
                }

                uow.Repositories.AddOrUpdate(entity);

                // Remove any removed user groups
                foreach (var relation in uow.Repositories.GetParentRelations(entity.Id, FixedRelationTypes.UserGroupRelationType)
                    .Where(x => !model.UserGroups.Contains(x.SourceId)))
                {
                    uow.Repositories.RemoveRelation(relation);
                }

                // Add any new user groups
                var existingRelations = uow.Repositories.GetParentRelations(entity.Id, FixedRelationTypes.UserGroupRelationType).Select(x => x.SourceId).ToArray();
                foreach (var userGroupId in model.UserGroups.Where(x => !existingRelations.Contains(x)))
                {
                    uow.Repositories.AddRelation(new Relation(FixedRelationTypes.UserGroupRelationType, userGroupId, entity.Id));
                }

                uow.Complete();

                //we may have changed the user data, so we need to ensure that the latest user data exists in the Identity object so we'll re-issue a forms auth ticket here
                if (HttpContext.User.Identity.Name.InvariantEquals(entity.Username))
                {
                    HttpContext.CreateUmbracoAuthTicket(entity);
                }

                Notifications.Add(new NotificationMessage(
                       "User.Save.Message".Localize(this),
                       "User.Save.Title".Localize(this),
                       NotificationType.Success));

                //add path for entity for SupportsPathGeneration (tree syncing) to work
                GeneratePathsForCurrentEntity(uow.Repositories.GetEntityPaths<TypedEntity>(entity.Id, FixedRelationTypes.DefaultRelationType));

                return RedirectToAction("Edit", new { id = entity.Id });
            }

            

        }
        internal static User GetUmbracoUser(IUmbracoApplicationContext appContext, IGroupUnit<ISecurityStore> uow, string username, bool userIsOnline)
        {
            // TODO: Enable type of extension method GetEntityByRelationType to be passed all the way to the provider
            // so that it can use the typemappers collection to map back to a User

            // APN: I changed SingleOrDefault to FirstOrDefault to guard against YSODs if somehow a duplicate user gets into the store [31/Jan]
            var userEntity = uow.Repositories
                .GetEntityByRelationType<TypedEntity>(
                    FixedRelationTypes.DefaultRelationType, FixedHiveIds.UserVirtualRoot)
                .FirstOrDefault(x => x.Attribute<string>(UserSchema.UsernameAlias) == username);


            if (userEntity == null) return null;

            var user = new User();
            user.SetupFromEntity(userEntity);

            if (userIsOnline)
            {
                user.LastActivityDate = DateTime.UtcNow;

                uow.Repositories.AddOrUpdate(user);
                uow.Complete();
            }

            return user;
        }
        /// <summary>
        /// Validates the user internal.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="password">The password.</param>
        /// <returns></returns>
        private bool ValidateUserInternal(User user, string password)
        {
            if (user != null && user.IsApproved)
            {
                var salt = user.PasswordSalt;
                var transformedPassword = TransformPassword(password, ref salt);
                if (string.Compare(transformedPassword, user.Password) == 0)
                {
                    return true;
                }
            }

            return false;
        }
        public ActionResult CreateUserForm(CreateNewUserModel model)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            // Create user entity
            var admin = new User()
            {
                Name = model.Name,
                Username = model.Username,
                Password = model.Password,
                Email = model.Email,
                StartContentHiveId = FixedHiveIds.ContentVirtualRoot,
                StartMediaHiveId = FixedHiveIds.MediaVirtualRoot,
                Applications = new List<string>(new[] { "content", "media", "settings", "developer", "users" }),
                IsApproved = true,
                SessionTimeout = 60
            };

            using (var uow = _requestContext.Application.Hive.OpenWriter<IContentStore>())
            {
                // Find admin usergroup
                var adminUserGroup = uow.Repositories.GetEntityByRelationType<UserGroup>(
                                    FixedRelationTypes.DefaultRelationType, FixedHiveIds.UserGroupVirtualRoot)
                                    .Where(y => y.Name == "Administrator")
                                    .FirstOrDefault();

                // Add user to admin role
                if (adminUserGroup != null)
                    admin.RelationProxies.EnlistParent(adminUserGroup, FixedRelationTypes.UserGroupRelationType);

                // Save user
                uow.Repositories.AddOrUpdate(admin);

                // Comit user
                uow.Complete();
            }

            //TODO: Subscribe user to newsletter
            if(model.SignUpForNewsletter)
            {
                try
                {
                    new WebClient()
                        .UploadValues("http://umbraco.org/base/Ecom/SubmitEmail/installer.aspx", new NameValueCollection()
                    {
                        {
                            "name",
                            model.Name
                        },
                        {
                            "email",
                            model.Email
                        }
                    });
                }
                catch(Exception ex)
                {
                    LogHelper.TraceIfEnabled<InstallController>("Unable to subscribe user to newsletter: {0}", () => ex.Message);
                }
            }

            return RedirectToAction("StarterKit");
        }
        /// <summary>
        /// Adds a new membership user to the data source.
        /// </summary>
        /// <param name="username">The user name for the new user.</param>
        /// <param name="password">The password for the new user.</param>
        /// <param name="email">The e-mail address for the new user.</param>
        /// <param name="passwordQuestion">The password question for the new user.</param>
        /// <param name="passwordAnswer">The password answer for the new user</param>
        /// <param name="isApproved">Whether or not the new user is approved to be validated.</param>
        /// <param name="providerUserKey">The unique identifier from the membership data source for the user.</param>
        /// <param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"/> enumeration value indicating whether the user was created successfully.</param>
        /// <returns>
        /// A <see cref="T:System.Web.Security.MembershipUser"/> object populated with the information for the newly created user.
        /// </returns>
        public override MembershipUser CreateUser(string username, string password, string email,
            string passwordQuestion, string passwordAnswer, bool isApproved,
            object providerUserKey, out MembershipCreateStatus status)
        {
            try
            {
                // Validate the username
                if (!ValidateUserName(username, HiveId.Empty))
                {
                    status = MembershipCreateStatus.DuplicateUserName;
                    return null;
                }

                // Validate the email address
                if (RequiresUniqueEmail && !ValidateEmail(email, HiveId.Empty))
                {
                    status = MembershipCreateStatus.DuplicateEmail;
                    return null;
                }

                // Validate the password
                var e = new ValidatePasswordEventArgs(username, password, true);

                base.OnValidatingPassword(e);

                if (e.Cancel || !ValidatePassword(password))
                {
                    status = MembershipCreateStatus.InvalidPassword;
                    return null;
                }

                using (var uow = _hive.Create())
                {
                    var salt = "";
                    var transformedPassword = TransformPassword(password, ref salt);

                    var user = new User
                    {
                        Name = username,
                        Username = username,
                        Password = transformedPassword,
                        PasswordSalt = salt,
                        Email = email,
                        PasswordQuestion = passwordQuestion,
                        PasswordAnswer = passwordAnswer,
                        IsApproved = isApproved,
                        LastActivityDate = DateTime.UtcNow,
                        LastPasswordChangeDate = DateTime.UtcNow,
                        LastLoginDate = DateTime.UtcNow
                    };

                    uow.Repositories.AddOrUpdate(user);
                    uow.Complete();

                    status = MembershipCreateStatus.Success;

                    return ConvertUserToMembershipUser(user);
                }
            }
            catch (Exception e)
            {
                status = MembershipCreateStatus.ProviderError;
            }

            return null;
        }
        /// <summary>
        /// Creates the Umbraco authentication ticket
        /// </summary>
        /// <param name="http"></param>
        /// <param name="user"></param>
        public static void CreateUmbracoAuthTicket(this HttpContextBase http, User user)
        {
            var roles = Roles.Providers.GetBackOfficeRoleProvider().GetRolesForUser(user.Username);
            var userData = new UserData
            {
                Id = user.Id.ToString(),
                Roles = roles,
                SessionTimeout = user.SessionTimeout,
                Username = user.Username,
                RealName = user.Name,
                StartContentNode = user.StartContentHiveId.IsNullValueOrEmpty() ? HiveId.Empty.ToString() : user.StartContentHiveId.ToString(),
                StartMediaNode = user.StartMediaHiveId.IsNullValueOrEmpty() ? HiveId.Empty.ToString() : user.StartMediaHiveId.ToString(),
                AllowedApplications = user.Applications.ToArray()
            };

            http.CreateUmbracoAuthTicket(userData);
        }
        public void Get_Entity_By_Relation_Type()
        {
            var admin = new User()
                {
                    Name = "Admin",
                    Username = "******",
                    Email = "*****@*****.**",
                    Password = "******"
                };

            var myUser = new User()
            {
                Name = "A User",
                Username = "******",
                Email = "*****@*****.**",
                Password = "******"
            };

            using (var writer = ProviderSetup.UnitFactory.Create())
            {
                writer.EntityRepository.AddOrUpdate(new SystemRoot());
                writer.EntityRepository.AddOrUpdate(FixedEntities.UserVirtualRoot);
                writer.EntityRepository.AddOrUpdate(admin);
                writer.EntityRepository.AddOrUpdate(myUser);
                writer.Complete();
            }

            PostWriteCallback.Invoke();
            
            using (var reader = ProviderSetup.UnitFactory.Create())
            {
                var user = reader.EntityRepository.GetEntityByRelationType<User>(FixedRelationTypes.DefaultRelationType, FixedHiveIds.UserVirtualRoot).ToArray();
                Assert.AreEqual(2, user.Count());
            }            
        }
        public void Committing_Both_Entity_And_Schema_Results_In_No_Group_Overlap()
        {
            var userGuidForDebugging = Guid.Parse("00000000-0000-0000-0000-000000000BFC");
            var userGroup = new UserGroup();
            var user = new User() { Id = new HiveId(userGuidForDebugging) };
            var actualGroups =
                userGroup.EntitySchema.AttributeGroups
                    .Concat(userGroup.AttributeGroups)
                    .Concat(userGroup.Attributes.Select(x => x.AttributeDefinition.AttributeGroup))
                    .Concat(userGroup.EntitySchema.AttributeDefinitions.Select(x => x.AttributeGroup))
                    .Distinct();

            Assert.AreEqual(1, actualGroups.Count());

            using (var writer = ProviderSetup.UnitFactory.Create())
            {
                writer.EntityRepository.AddOrUpdate(new SystemRoot());
                writer.EntityRepository.AddOrUpdate(FixedEntities.UserVirtualRoot);
                writer.EntityRepository.AddOrUpdate(FixedEntities.UserGroupVirtualRoot);
                writer.EntityRepository.Schemas.AddOrUpdate(FixedSchemas.UserGroup);
                writer.EntityRepository.AddOrUpdate(user);
                writer.EntityRepository.AddOrUpdate(userGroup);                
                writer.Complete();
            }

            using (var writer = ProviderSetup.UnitFactory.Create())
            {
                var foundGroup =
                    writer.EntityRepository.GetEntityByRelationType<UserGroup>(
                        FixedRelationTypes.DefaultRelationType, FixedHiveIds.UserGroupVirtualRoot)
                        .Where(y => y.Name == userGroup.Name)
                        .FirstOrDefault();
                user.RelationProxies.EnlistParent(foundGroup, FixedRelationTypes.UserGroupRelationType);
                writer.EntityRepository.AddOrUpdate(user);
                writer.Complete();
            }
            
            using (var reader = ProviderSetup.UnitFactory.Create())
            {
                var output = reader.EntityRepository.Get<UserGroup>(true, userGroup.Id);
                Assert.AreEqual(1, output.Count());
                Assert.AreEqual(1, output.Single().AttributeGroups.Count());
                Assert.AreEqual(1, output.Single().EntitySchema.AttributeGroups.Count);
                Assert.AreEqual(1, output.Single().EntitySchema.AttributeDefinitions.Select(x => x.AttributeGroup).Distinct().Count());
                var allGroups = reader.EntityRepository.Schemas.GetAll<AttributeGroup>();
                Assert.AreEqual(1, allGroups.Count(x => x.Alias == FixedGroupDefinitions.UserGroupDetailsAlias));
                Assert.AreEqual(1, allGroups.Count(x => x.Alias == FixedGroupDefinitions.UserDetailsAlias));
            }
        }
        public void Ensures_InvalidOperationException_When_Adding_Entity_With_Relations_Without_Adding_Related_Entities()
        {
            var admin = new User()
            {
                Name = "Admin",
                Username = "******",
                Email = "*****@*****.**",
                Password = "******"
            };

            Assert.Throws<InvalidOperationException>(() =>
                {
                    using (var writer = ProviderSetup.UnitFactory.Create())
                    {
                        writer.EntityRepository.AddOrUpdate(admin);
                        writer.Complete();
                    }
                });
        }
        public void Create_User_With_All_Ids_Asssigned_To_All_Objects()
        {
            var user = new User();

            // Act
            using (var writer = ProviderSetup.UnitFactory.Create())
            {
                writer.EntityRepository.AddOrUpdate(new SystemRoot());
                writer.EntityRepository.AddOrUpdate(FixedEntities.UserVirtualRoot);
                writer.EntityRepository.AddOrUpdate(user);
                writer.Complete();
            }

            foreach(var a in user.Attributes)
            {
                Assert.IsFalse(a.Id.IsNullValueOrEmpty());
            }
            foreach(var g in user.AttributeGroups)
            {
                Assert.IsFalse(g.Id.IsNullValueOrEmpty());
            }
            Assert.IsFalse(user.EntitySchema.Id.IsNullValueOrEmpty());
            foreach(var d in user.EntitySchema.AttributeDefinitions)
            {
                Assert.IsFalse(d.Id.IsNullValueOrEmpty());
            }
            foreach(var g in user.EntitySchema.AttributeGroups)
            {
                Assert.IsFalse(g.Id.IsNullValueOrEmpty());
            }
        }