예제 #1
0
        public SurveyResult Score(
            User user,
            string[] answers)
        {
            if (answers.Length != Questions.Count)
            {
                throw new ArgumentOutOfRangeException("answers", "Count of answers must equal the count of Questions in order to score the survey.");
            }

            // create a result structure
            var r = new SurveyResult
            {
                User = user.Document.Id,
                Survey = Document.Id,
                Title = Content.Title,
                Taken = DateTime.UtcNow,
                PointsEarned = Points,
                Answers = new List<SurveyResultAnswer>(),
            };

            // score questions 1 by 1
            for (var i = 0; i < Questions.Count; i++)
            {
                var q = Questions[i];
                r.Answers.Add(new SurveyResultAnswer
                {
                    Question = q.Title,
                    Answer = q.Freeform ? answers[i] : q.Answers[int.Parse(answers[i])].Title,
                });
            }

            return r;
        }
 public void User_can_set_password()
 {
     var u = new User();
     u.SetPassword("asdf");
     Assert.That(u.PasswordHash.Length, Is.GreaterThan(0));
     Assert.That(u.PasswordSalt.Length, Is.GreaterThan(0));
 }
예제 #3
0
        public static UserEditModel FromDomain(User u, UserActivitySummary logins, IAccountingService accounting)
        {
            var x = new UserEditModel
                       {
                            Manager = u.Manager,
                            Group = u.Group,
                            ManagedGroups = u.ManagedGroups,
                            State = u.State,
                            DateBirth = u.DateBirth,
                            DateHired = u.DateHired,
                            Email = u.Email,
                            Title = u.Title,
                            EmployeeId = u.EmployeeId,
                            FirstName = u.FirstName,
                            LastName = u.LastName,
                            HomeAddress = u.HomeAddress,
                            WorkAddress = u.WorkAddress,
                            HomePhone = u.HomePhone,
                            WorkPhone = u.WorkPhone,
                            MobilePhone = u.MobilePhone,
                            Custom = u.Custom,
                            Permissions = (u.Permissions ?? new UserPermissions()),
                            

                            // display only fields
                            Login = u.Login,
                            DateAcceptedTermsOfService = u.DateAcceptedTermsOfService,
                            DateRegistered = u.DateRegistered,
                            DateActivated = u.DateActivated,
                            DateSuspended = u.DateSuspended,
                            DateTerminated = u.DateTerminated,
                      };
            x.AddBudgets(u, accounting);
            return x;
        }
예제 #4
0
 public EmailSendAttempt SendWelcome(RequestContext request, User u)
 {
     var template = LoadTemplate(
         "template-user-welcome",
         request.HttpContext.Server.MapPath("~/Messages/UserWelcome.template")
     );
     var url = new UrlHelper(request).Action(MVC.Public.Login.Index());
     var e = Builder.Transform(
         template,
         new TemplateData
             {
                 {"login", u.Login},
                 {"program", Application.ProgramName},
                 {"url", url.ToAbsoluteUrl(request.HttpContext.Request).ToString() },
             },
         request.HttpContext.Request
     );
     e.Recipient = new EmailAddress { Address = u.Email, Name = u.DisplayName };
    
     var attempt = Sender.Send(e);
     if (attempt.Success)
     {
         u.LastWeclomeEmailSent = DateTime.UtcNow;
         UserRepository.Save(u);
     }
     return attempt;
 }
예제 #5
0
 public void User_state_doesnt_set_dates_when_previous_state_is_unset(
     [Values(UserState.Active, UserState.Registered, UserState.Suspended, UserState.Terminated)] UserState target)
 {
     var u = new User { State = target };
     Assert.That(u.StateChanged, Is.EqualTo(new DateTime()));
     Assert.That(u.DateRegistered.HasValue, Is.False);
     Assert.That(u.DateActivated.HasValue, Is.False);
     Assert.That(u.DateSuspended.HasValue, Is.False);
     Assert.That(u.DateTerminated.HasValue, Is.False);
 }
        public void User_sets_unique_password_hash_even_for_same_password()
        {
            var u1 = new User();
            var u2 = new User();

            u1.SetPassword("asdf");
            u2.SetPassword("asdf");

            Assert.That(User.CompareHash(u1.PasswordHash, u2.PasswordHash), Is.False);
        }
        public void Apply(ProfileElements e, User u)
        {
            if (e.Email)
            {
                u.Email = Email;
            }
            if (e.Name)
            {
                u.FirstName = FirstName;
                u.LastName = LastName; 
            }
            if (e.DateOfBirth) 
            {
                u.DateBirth = DateBirth;
            }
            if (e.DateOfHire)
            {
                u.DateHired = DateHired;
            }
            if (e.HomeAddress)
            {
                u.HomeAddress = HomeAddress;
            }
            if (e.WorkAddress)
            { 
                u.WorkAddress = WorkAddress;
            }
            if (e.HomePhone)
            {
                u.HomePhone = HomePhone;
            }
            if (e.WorkPhone)
            {
                u.WorkPhone = WorkPhone;
            }
            if (e.MobilePhone)
            {
                u.MobilePhone = MobilePhone;
            }
            if (e.CustomFields)
            { 
                u.Custom = Custom;
            }
            if (e.Password &&
                !String.IsNullOrEmpty(Password) &&
                !String.IsNullOrEmpty(PasswordConfirmation) &&
                Password == PasswordConfirmation)
            {
                u.SetPassword(Password);
            }

            u.LastUpdatedProfile = DateTime.UtcNow;
        }
예제 #8
0
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);

            CurrentUser = Users[filterContext.HttpContext.User.Identity.Name];
            ViewData["currentUser"] = CurrentUser;

            // we need to have at least dashboard permissions to access this area
            if (null ==  CurrentUser.Permissions ||
                false == CurrentUser.Permissions.Dashboard)
            {
                throw new HttpException((int)HttpStatusCode.Forbidden, "You do not have permission to access the dashboard.");
            }
        }
예제 #9
0
 public GameResult Score(User currentUser, int time, int score)
 {
     return new GameResult
                {
                    User = currentUser.Document.Id,
                    Game = this.Document.Id,
                    Title = Content.Title,
                    Taken = DateTime.UtcNow,
                    Time = time,
                    Score = score,
                    PointsEarned = null == TimeLimit
                     ? this.Award
                     : time <= TimeLimit ? this.Award : null,
                };
 }
예제 #10
0
        public AvailabilityResult IsAllowedAccess(User u, DateTime date)
        {
            // disallow access based on enabled & date range settings
            if (!Enabled)
            {
                return AvailabilityResult.No(
                    "This resource is not enabled.",
                    "This resource is currently disabled. Please ask an administrator to enabled this resource or to remove any links referencing it.");
            }

            // if the availability is left blank, allow access by default
            return null == Availability
                ? AvailabilityResult.Ok
                : Availability.IsAllowedAccess(u, date);
        }
예제 #11
0
        public void User_state_sets_dates_when_changed(
            [Values(UserState.Active, UserState.Registered, UserState.Suspended, UserState.Terminated)] UserState source,
            [Values(UserState.Active, UserState.Suspended, UserState.Terminated)] UserState target)
        {
            if (source == target) return;

            var u = new User {State = source};
            var d = u.StateChanged;
            u.State = target;
            Assert.That(u.StateChanged, Is.GreaterThan(d));
            switch (target)
            {
                case UserState.Registered: Assert.That(u.DateRegistered.HasValue, Is.True); break;
                case UserState.Active:     Assert.That(u.DateActivated.HasValue, Is.True); break;
                case UserState.Suspended:  Assert.That(u.DateSuspended.HasValue, Is.True); break;
                case UserState.Terminated: Assert.That(u.DateTerminated.HasValue, Is.True); break;
            }
        }
예제 #12
0
        public static BudgetDistributionViewModel Create(Ledger managerBudget, User employee, Ledger employeePoints)
        {
            var last = managerBudget.Debits
                .Where(x => x.Credit == employeePoints.Account.Document.Id)
                .OrderBy(x => x.Date)
                .Select(x => (DateTime?)x.Date)
                .LastOrDefault();

            return new BudgetDistributionViewModel
            {
                Id = employee.Document.Id,
                DisplayName = employee.DisplayName,
                Balance = employeePoints.Balance,
                LastBudgetDistribution = last,
                LastBudgetDistributionText = last.HasValue ? last.Value.ToShortDateString() : "Never",
                Wishlist = employee.Wishlist,
            };
        }
예제 #13
0
 public User CreateUser()
 {
     var u = new User
     {
         Login = Login,
         Email = Email,
         FirstName = FirstName,
         LastName = LastName,
         State = UserState.Registered,
         StateChanged = DateTime.UtcNow,
         DateRegistered = DateTime.UtcNow,
         Document = new Document { Id = Document.For<User>(Login.ToSlug()) }
     };
     u.State = Activate ? UserState.Active : UserState.Registered;
     u.SetPassword(Password);
     if (!Activate)
     {
         u.SetActivationCode();
     }
     return u;
 }
예제 #14
0
 public static ProfileEditModel FromDomain(ProfileElements elements, string[] custom, User u)
 {
     return new ProfileEditModel()
     {
         Elements = elements,
         Login = u.Login,
         Email = u.Email,
         FirstName = u.FirstName,
         LastName = u.LastName,
         DateBirth = u.DateBirth,
         DateHired = u.DateHired,
         HomeAddress = u.HomeAddress,
         WorkAddress = u.WorkAddress,
         HomePhone = u.HomePhone,
         WorkPhone = u.WorkPhone,
         MobilePhone = u.MobilePhone,
         Custom = custom.ToDictionary(
             x => x,
             x => (u.Custom != null && u.Custom.ContainsKey(x)) ? u.Custom[x] : ""),
     };
 }
예제 #15
0
        /// <summary>
        /// Determine if a user is allowed access to this resource, at a given point in time.
        /// </summary>
        /// <param name="u">User</param>
        /// <param name="date">Date</param>
        /// <returns>
        /// False, unless either the given user is in the Users list, the user's current group is
        /// in the Groups list, or the AvailableToPublic or AvailableToAllUsers flags are set,  and
        /// the supplied date is within the From and To properties of the Availability and the 
        /// Resource is Enabled.
        /// </returns>
        public AvailabilityResult IsAllowedAccess(User u, DateTime date)
        {
            // disallow access based on date range settings
            if (From.HasValue && date < From.Value)
            {
                return AvailabilityResult.No(
                    "This resource is not yet available.",
                    "This resource will become available on " + From.Value.ToShortDateString() + ". Please check back then.");
            }
            if (To.HasValue && date > To.Value)
            {
                return AvailabilityResult.No(
                    "This resource is no longer available.",
                    "This resource was made unavaible on " + To.Value.ToShortDateString() + ". Please ask your adminstrator to remove any links to this resource.");
            }

            // allow access based on the group membership & mode
            var isInUsers = null != u && null != Users && Users.Contains(u.Document.Id);
            var isInGroups = null != u && null != Groups && null != u.Group && Groups.Contains(u.Group);
            switch (Mode)
            {
                case AvailabilityMode.AvailableToPublic: return AvailabilityResult.Ok;
                case AvailabilityMode.AvailableToAllUsers:
                    if (null != u) return AvailabilityResult.Ok;
                    break;
                case AvailabilityMode.AvailableOnlyTo:
                    if (isInUsers || isInGroups) return AvailabilityResult.Ok;
                    break;
                case AvailabilityMode.AvailableToEveryoneBut:
                    if (!isInUsers && !isInGroups) return AvailabilityResult.Ok;
                    break;
            }

            return AvailabilityResult.No(
                "You do not have access to this resource.",
                "Please ask your adminstrator to grant access to this resource.");
        }
예제 #16
0
        public void Apply(User u, IAccountingService accounting)
        {
            if (!String.IsNullOrEmpty(Password))
            {
                u.SetPassword(Password);
            }
            u.Manager = Manager;
            u.Group = Group;
            u.ManagedGroups = ManagedGroups;
            u.State = State;
            u.DateBirth = DateBirth;
            u.DateHired = DateHired;
            u.Title = Title;
            u.EmployeeId = EmployeeId;
            u.Email = Email;
            u.FirstName = FirstName;
            u.LastName = LastName;
            u.HomeAddress = HomeAddress;
            u.WorkAddress = WorkAddress;
            u.HomePhone = HomePhone;
            u.WorkPhone = WorkPhone;
            u.MobilePhone = MobilePhone;
            u.Custom = Custom;
            u.Permissions = Permissions;

            accounting.SetUserBudget(u, null == Budget ? null : Budget.ToBudget());
        }   
예제 #17
0
 public void AddBudgets(User u, IAccountingService accounting)
 {
     PointsLedger = accounting.GetPointsLedger(u);
     BudgetLedger = accounting.GetBudgetLedger(u);
     Budget = (null != BudgetLedger &&
     null != BudgetLedger.Account)
         ? BudgetEditModel.FromDomain(BudgetLedger.Account.Budget)
         : new BudgetEditModel();
 }
예제 #18
0
 public void AddBudgets(User u, IAccountingService accounting)
 {
     PointsLedger = accounting.GetPointsLedger(u);
     BudgetLedger = accounting.GetBudgetLedger(u);
 }
예제 #19
0
        public virtual ActionResult Randomizer(RandomizerModel model)
        {
            // keep all the users in a local structure
            var r = new Random();
            var all = new Dictionary<string, User>();
            var execs = new List<User>();
            var managers = new List<User>();
            var groups = Groups.All().WithDocuments().ToList();

            // load up all the quizes and awards that we could do
            var quizzes = Quizzes.All().WithDocuments();
			// var awards = Awards.All().WithDocuments();

            // load up a random slice of about 10% of all products
            var products =
                Catalog.GetCategories(Application.DefaultCatalog)
                       .Products
                       .Where(x => r.NextDouble() < 0.10)
                       .ToArray();
            var averageprice = (int)products.Average(x => x.Price);

            var start = (model.From ?? DateTime.Now.AddYears(-1));
            var end = (model.To ?? DateTime.Now);
            var days = (int)(end-start).TotalDays;

            var dobstart = new DateTime(1955, 1, 1);
            const int dobdays = 365*35;

            for (var n=all.Count; n<model.Users; n++)
            {
                // create basic user properties
                var first = Firstnames[(int)(Math.Pow(r.NextDouble(), r.NextDouble()) * Firstnames.Length)];
                var last = Lastnames[(int)(Math.Pow(r.NextDouble(), r.NextDouble()) * Lastnames.Length)];
                var login = (first[0] + last).ToSlug();
                var u = new User {
                  Document = new Document { Id = Document.For<User>(login) },
                  Login = login,
                  FirstName = first,
                  LastName = last,
                  Email = String.Format("{0}.{1}@{2}", first.ToSlug(), last.ToSlug(), model.EmailDomain),
                  State = UserState.Active,
                  DateBirth = dobstart.AddDays(r.Next(1, dobdays)),
                  DateHired = end.AddDays(-1 * r.Next(1, 3000)),
                  DateActivated = start.AddDays(r.Next(0, days)),
                };
                u.SetPassword("asdf");

                // place into group/management hierarchy.. execs in charge of a group, with
                // several managers in each group with employers reporting to them.
                if (groups.Count > 2)
                {
                    if (execs.Count < groups.Count)
                    {
                        // there's 1 exec for each group
                        var g = groups[execs.Count];
                        u.Group = g.Document.Id;
                        u.ManagedGroups = new[] { u.Group };
                        u.Title = "VP of " + g.Name;
                        execs.Add(u);

                        // execs get a large budget
                        Accounting.GetBudgetLedger(u, true,
                            new Budget {
                                RefreshLimit = 3000,
                                RefreshInterval = BudgetRefreshInterval.Monthly,
                            });
                    }
                    else if (managers.Count < 3 * groups.Count)
                    {
                        // there are a few managers in each group        
                        u.Group = groups[r.Next(0, groups.Count - 1)].Document.Id;
                        u.Manager = execs.Where(x => x.Group == u.Group).First().Document.Id;
                        u.Title = "Supervisor";
                        managers.Add(u);

                        // managers get a modest budget
                        Accounting.GetBudgetLedger(u, true,
                            new Budget {
                                RefreshLimit = r.NextDouble() < 0.50 ? 1500 : 2000,
                                RefreshInterval = BudgetRefreshInterval.Monthly,
                            });                    
                    }
                    else
                    {
                        // assign the user to a random manager (and place in his group)
                        var m = managers[r.Next(0, managers.Count-1)];
                        u.Manager = m.Document.Id;
                        u.Group = m.Group;
                    }
                }
                
                try
                {
                    Users.Save(u);
                    all.Add(u.Document.Id, u);
                }
                catch
                {
                }
            }

            // refresh budgets every day
            for (var n=0; n<days; n++)
            {
                Accounting.RefreshBudgets(start.AddDays(days));
            }

            foreach (var u in all.Values)
            {
                // some users just don't do anything
                var active = r.NextDouble() < 0.95;
                if (active)
                {
                    // avg number of days between logins
                    var frequency = r.Next(7, 60);     
                    var d = start;
                    while (true)
                    {
                        // users are fairly predictable, within about 25% tolerance on either side
                        d = d.AddDays(r.Next(
                            (int)(frequency - (frequency * 0.25)),
                            (int)(frequency + (frequency * 0.25))
                        ));
                        if (d > end) break;

                        // lets meet the bobs
                        if (r.NextDouble() < 0.05)
                        {
                            u.State = UserState.Terminated;
                            u.DateTerminated = d;
                            u.StateChanged = d; 
                            break;
                        }

                        // usually they log in because they got some points
                        var ledger = Accounting.GetPointsLedger(u);
                        if (r.NextDouble() < 0.60)
                        {
                            Accounting.CreateTransaction(
                                Application.GeneralControlAccount,
                                ledger.Account.Document.Id,
                                r.Next(averageprice/10, averageprice/2),
                                "Congrulations on your sale!",
                                "Sales",
                                d.AddHours(-1 * r.Next(2, 72)),
                                null);
                        }

                        // sometimes we forget our password
                        if (r.NextDouble() < 0.05)
                        {
                            u.IncrementLogins(false, Request, d);

                            // and we try again
                            if (r.NextDouble() < 0.75)
                            {
                                d = d.AddMinutes(1);
                                u.IncrementLogins(false, Request, d);
                            }
                           
                            // and again
                            if (r.NextDouble() < 0.75)
                            {
                                d = d.AddMinutes(1);
                                u.IncrementLogins(false, Request, d);
                            }

                            // and again, and /again/
                            // the time for honoring yourself will soon be over

                            // but then we usually reset it and get logged in
                            if (r.NextDouble() < 0.80)
                            {
                                d = d.AddMinutes(5);
                            }
                            else
                            {
                                break;
                            }
                        }
                        
                        // login!
                        u.IncrementLogins(true, Request, d);

                        // if this is their first login, make sure they accept the terms of service
                        if (!u.DateAcceptedTermsOfService.HasValue)
                        {
                            u.DateAcceptedTermsOfService = d;
                        }

                        // try taking a quiz!
                        if (r.NextDouble() < 0.20)
                        {
                            foreach (var q in quizzes)
                            {
                                if (q.CanUserTakeQuiz(u, d, QuizResults.GetResults(q, u)).Available)
                                {
                                    // most quizzes are easy
                                    var qr = q.Score(
                                        u, 
                                        q.Questions.Select(x => {
                                            var correct = (r.NextDouble() < 0.95);
                                            return x.Answers.IndexOf(x.Answers.First(y => y.Correct == correct));
                                        }).ToArray()
                                    );
                                    qr.Taken = d.AddMinutes(5);
                                    if (qr.Passed && qr.PointsEarned.HasValue && qr.PointsEarned > 0)
                                    {
                                        var tx = Accounting.CreateProgramAward(q, null, u, qr.PointsEarned.Value, q.Content.Title);
                                        qr.Transaction = tx.Document.Id;
                                    }
                                    QuizResults.Save(qr);
                                    break;
                                }
                            }
                        }

                        // send an award
                        if (r.NextDouble() < 0.10)
                        {
                        }

                        // if we have at least enough points to buy something 'average', try to place an order
                        if (ledger.Balance > averageprice)
                        {
                            var cart = new List<CatalogProduct>();
                            while (true)
                            {
                                var p = products[r.Next(0, products.Length-1)];
                                if (cart.Sum(x => x.Price) + p.Price < ledger.Balance)
                                {
                                    cart.Add(p);
                                }
                                else
                                {
                                    break;
                                }
                            }
                            if (cart.Count > 0)
                            {
                                var o = new Order
                                {   
                                    User = u.Document.Id,
                                    State = OrderStateMachine.Create(),
                                    ShippingName = u.DisplayName,
                                    ShippingAddress = new Address { Address1 = "123 Main St.", City = "Minneapolis", State = "MN", PostalCode = "55456" },
                                    ShippingPhone = new Phone { Number = "(952)555-7834" },
                                    Items = cart.Select(x => new OrderItem
                                    {
                                        ProductId = x.Id,
                                        ProductName = x.Name,
                                        OptionName = x.Options[0].Name,
                                        OptionSku =  x.Options[1].Sku,
                                        Description = x.Description,
                                        UnitPrice = x.Price,
                                        Quantity = 1,
                                        Stock = x.Stock,
                                        State = OrderItemStateMachine.Create(),
                                    }).ToArray(),
                                };
                                o.State[0].Changed = d.AddMinutes(15);
                                var tx = Accounting.CreateOrderPayment(u, o);
                                o.Transaction = tx.Document.Id;
                                Orders.Save(o);
                            }
                        }

                        // distribute budget
                        var budgetLedger = Accounting.GetBudgetLedger(u);
                        if (null != budgetLedger &&
                            null != budgetLedger.Account &&
                            null != budgetLedger.Account.Budget &&
                            r.NextDouble() < 0.50)
                        {
                            var budgetBalance = budgetLedger.Balance;
                            if (budgetBalance > budgetLedger.Account.Budget.RefreshLimit.Value * 0.15)
                            {
                                // pick a random user that reports to us
                                var reports = all.Values.Where(x => x.Manager == u.Document.Id).ToList();
                                if (reports.Count > 0)
                                {
                                    var awardee = reports[r.Next(0, reports.Count-1)];
                                    Accounting.CreateBudgetTransfer(
                                        u,
                                        awardee,
                                        r.Next((int)(budgetBalance * 0.10), (int)(budgetBalance * 0.85)),
                                        "Budget Award");
                                }
                            }
                        }

                    }
                }
                Users.Save(u);
            }
            
            Notifier.Notify(Severity.Success, "Randomized!", "Random activity succesfully created. You may want to compact the database.", null);
            return this.RedirectToAction<UserController>(c => c.Index());
        }
예제 #20
0
 public static void ValidateLogin(
     User u,
     string login,
     IUserRepository users,
     ModelStateDictionary state)
 {
     if (!String.IsNullOrEmpty(login) &&
         (null == u || u.Login != login))
     {
         var same = users.Where(x => x.Login).Eq(login).List();
         if (same.Rows.Length > 0 &&
             (null == u || same.Rows.First().Id != u.Document.Id))
         {
             // there's already a user with this login address (besides the current one)
             state.AddModelError("Login", "Login name already in use.");
         }
     }
 }
예제 #21
0
 public void User_can_check_password()
 {
     var u = new User();
     u.SetPassword("asdf");
     Assert.That(u.CheckPassword("asdf"), Is.True);
 }
예제 #22
0
 public void User_password_is_case_sensitive()
 {
     var u = new User();
     u.SetPassword("asdf");
     Assert.That(u.CheckPassword("asdF"), Is.False);
 }
예제 #23
0
 public EmailSendAttempt SendReset(RequestContext request, User u, string password)
 {
     var template = LoadTemplate(
         "template-user-reset",
         request.HttpContext.Server.MapPath("~/Messages/UserReset.template")
     );
     var url = new UrlHelper(request).Action(MVC.Public.Login.Index());
     var e = Builder.Transform(
         template,
         new TemplateData
             {
                 {"login", u.Login},
                 {"program", Application.ProgramName},
                 {"password", password},
                 {"url", url.ToAbsoluteUrl(request.HttpContext.Request).ToString() },
             },
         request.HttpContext.Request
     );
     e.Recipient = new EmailAddress { Address = u.Email, Name = u.DisplayName };
     return Sender.Send(e);
 }
예제 #24
0
 public void User_state_cant_transition_back_to_registered(
     [Values(UserState.Active, UserState.Suspended, UserState.Terminated)] UserState source)
 {
     var u = new User { State = source };
     Assert.Throws<InvalidOperationException>(() => u.State = UserState.Registered);
 }
예제 #25
0
 public static void ValidateEmail(
     User u,
     string email,
     IUserRepository users,
     ModelStateDictionary state)
 {
     if (!String.IsNullOrEmpty(email) &&
         (null == u || u.Email != email))
     {
         var same = users.Where(x => x.Email).Eq(email).List();
         if (same.Rows.Length > 0 &&
             (null == u || same.Rows.First().Id != u.Document.Id))
         {
             // there's already a user with this email address (besides the current one)
             state.AddModelError("Email", "Email address already in use.");
         }
     }
 }