private void UpdateLocation(Guid?locationGuid, PersonCacher personCacher, LocationCacher locationCacher, ref bool saveNeeded) { if (locationGuid == null) { return; } var location = locationCacher.AllForThisElection.FirstOrDefault(l => l.LocationGuid == locationGuid); if (location == null) { return; } var oldCount = location.BallotsCollected; var newCount = personCacher.AllForThisElection.Count( p => p.VotingLocationGuid == location.LocationGuid && !String.IsNullOrEmpty(p.VotingMethod)); if (oldCount == newCount) { return; } Db.Location.Attach(location); location.BallotsCollected = newCount; locationCacher.UpdateItemAndSaveCache(location); saveNeeded = true; }
private IEnumerable <Person> PeopleInCurrentElectionQuery() { var peopleInCurrentElection = new PersonCacher(Db).AllForThisElection; // && p.VotingLocationGuid == UserSession.CurrentLocationGuid return(IncludeAbsentees ? peopleInCurrentElection.Where(p => !string.IsNullOrEmpty(p.VotingMethod)).ToList() : peopleInCurrentElection.Where(p => p.VotingMethod == VotingMethodEnum.InPerson).ToList()); }
protected Ballot CreateAndRegisterBallot() { var currentLocationGuid = UserSession.CurrentLocationGuid; if (!currentLocationGuid.HasContent()) { var locationModel = new LocationModel(); currentLocationGuid = locationModel.GetLocations_Physical().First().LocationGuid; UserSession.CurrentLocationGuid = currentLocationGuid; } var computerCode = UserSession.CurrentComputerCode; var ballotCacher = new BallotCacher(Db); var firstBallot = ballotCacher.AllForThisElection.Any(); var ballot = new Ballot { BallotGuid = Guid.NewGuid(), LocationGuid = currentLocationGuid, ComputerCode = computerCode, BallotNumAtComputer = NextBallotNumAtComputer(), StatusCode = BallotStatusEnum.Empty, Teller1 = UserSession.GetCurrentTeller(1), Teller2 = UserSession.GetCurrentTeller(2) }; Db.Ballot.Add(ballot); if (firstBallot) { var locationCacher = new LocationCacher(Db); var location = locationCacher.AllForThisElection.FirstOrDefault(l => l.LocationGuid == currentLocationGuid); if (location != null && location.BallotsCollected.AsInt() == 0) { var ballotSources = new PersonCacher(Db) .AllForThisElection .Count(p => !string.IsNullOrEmpty(p.VotingMethod) && p.VotingLocationGuid == currentLocationGuid); location.BallotsCollected = ballotSources; locationCacher.UpdateItemAndSaveCache(location); } } Db.SaveChanges(); ballotCacher.UpdateItemAndSaveCache(ballot); SessionKey.CurrentBallotId.SetInSession(ballot.C_RowId); return(ballot); //TODO: used to be view }
public object GetTies(int tieBreakGroup) { var results = new ResultCacher(Db).AllForThisElection; var persons = new PersonCacher(Db).AllForThisElection; var ties = results .Where(r => r.TieBreakGroup == tieBreakGroup) .Join(persons, r => r.PersonGuid, p => p.PersonGuid, (r, p) => new { r, p }) .Select(j => new { name = j.p.FullNameFL, isResolved = j.r.IsTieResolved.AsBoolean() }) .OrderBy(x => x.name); return(ties); }
private void UpdateLocationCounts(Guid?newVoteLocationGuid, Guid?oldVoteLocationGuid, PersonCacher personCacher) { // would be great to throw this into a remote queue to be processed later var locationCacher = new LocationCacher(Db); var saveNeeded = false; UpdateLocation(newVoteLocationGuid, personCacher, locationCacher, ref saveNeeded); if (oldVoteLocationGuid != null && oldVoteLocationGuid != newVoteLocationGuid) { UpdateLocation(oldVoteLocationGuid, personCacher, locationCacher, ref saveNeeded); } if (saveNeeded) { Db.SaveChanges(); } }
private IEnumerable <Person> PeopleInCurrentElectionQuery() { var peopleInCurrentElection = new PersonCacher(Db).AllForThisElection; var withAbsentees = new[] { VotingMethodEnum.InPerson, VotingMethodEnum.DroppedOff, VotingMethodEnum.MailedIn, //VotingMethodEnum.Registered, -- not registered (should not be used with RollCall) VotingMethodEnum.CalledIn, VotingMethodEnum.Online, VotingMethodEnum.Imported, VotingMethodEnum.Custom1, VotingMethodEnum.Custom2, VotingMethodEnum.Custom3, }.Select(vm => vm.Value).ToList(); return(IncludeAbsentees ? peopleInCurrentElection.Where(p => withAbsentees.Contains(p.VotingMethod)).ToList() : peopleInCurrentElection.Where(p => p.VotingMethod == VotingMethodEnum.InPerson).ToList()); }
private void UpgradeOldData() { var Db = GetNewDbContext(); var personCacher = new PersonCacher(Db); var testInfo = personCacher.AllForThisElection.Select(p => new { p.CombinedInfo }).FirstOrDefault(); if (testInfo == null) { return; } if (testInfo.CombinedInfo.HasContent() && !testInfo.CombinedInfo.Contains("^")) { return; } // fix all data var voteCacher = new VoteCacher(Db); var people = personCacher.AllForThisElection; var votes = voteCacher.AllForThisElection; var peopleModel = new PeopleModel(); var saveNeeded = false; foreach (var person in people) { AutoFix(person, votes, peopleModel, ref saveNeeded); } if (saveNeeded) { Db.SaveChanges(); new LogHelper().Add("Updated person combined infos"); } personCacher.DropThisCache(); voteCacher.DropThisCache(); }
/// <summary> /// Process each person record, preparing it BEFORE the election starts. Altered... too dangerous to wipe information! /// </summary> public void SetInvolvementFlagsToDefault() { var Db = SharedDbContext; var personCacher = new PersonCacher(Db); personCacher.DropThisCache(); var peopleInElection = personCacher.AllForThisElection; var reason = new ElectionModel().GetDefaultIneligibleReason(); var counter = 0; foreach (var person in peopleInElection) { SetInvolvementFlagsToDefault(person, reason); if (counter++ > 500) { Db.SaveChanges(); counter = 0; } } Db.SaveChanges(); }
public JsonResult GetForVoter() { var currentElection = UserSession.CurrentElection; if (currentElection == null) { return(new { Error = "Election not selected" }.AsJsonResult()); } var selectionProcess = currentElection.OnlineSelectionProcess.AsEnum(OnlineSelectionProcessEnum.Random); switch (selectionProcess) { case OnlineSelectionProcessEnum.List: case OnlineSelectionProcessEnum.Both: // okay break; default: // empty list return(new { people = new List <string>() }.AsJsonResult()); } var rnd = new Random(); var allForThisElection = new PersonCacher(Db).AllForThisElection; var maxRnd = allForThisElection.Count * 100; return(new { people = allForThisElection .Select(p => { var irg = p.IneligibleReasonGuid; string descriptionFor = null; if (irg != null) { if (p.CanReceiveVotes.GetValueOrDefault()) { // if they can receive votes, ignore any other status they may have (e.g. not a delegate) irg = null; } if (irg != null) { descriptionFor = IneligibleReasonEnum.DescriptionFor(irg.Value); } } return new { Id = p.C_RowId, Name = p.FullName, IRG = descriptionFor, p.OtherInfo, p.Area, sort = rnd.Next(maxRnd) }; }) .OrderBy(p => p.sort) }.AsJsonResult()); }
public JsonResult RegisterVotingMethod(int personId, string voteType, long lastRowVersion, bool forceDeselect) { var Db = GetNewDbContext(); if (UserSession.CurrentElectionStatus == ElectionTallyStatusEnum.Finalized) { return(new { Message = UserSession.FinalizedNoChangesMessage }.AsJsonResult()); } var locationModel = new LocationModel(); if (locationModel.HasLocations && UserSession.CurrentLocation == null) { return(new { Message = "Must select your location first!" }.AsJsonResult()); } if (UserSession.GetCurrentTeller(1).HasNoContent()) { return(new { Message = "Must select \"Teller at Keyboard\" first!" }.AsJsonResult()); } if (!VotingMethodEnum.Exists(voteType)) { return(new { Message = "Invalid type" }.AsJsonResult()); } var personCacher = new PersonCacher(Db); var person = personCacher.AllForThisElection.SingleOrDefault(p => p.Id == personId); if (person == null) { return(new { Message = "Unknown person" }.AsJsonResult()); } var timeOffset = UserSession.TimeOffsetServerAhead; Db.Person.Attach(person); person.Teller1 = UserSession.GetCurrentTeller(1); person.Teller2 = UserSession.GetCurrentTeller(2); var votingMethodRemoved = false; Guid?oldVoteLocationGuid = null; Guid?newVoteLocationGuid = null; if (person.VotingMethod == voteType || forceDeselect) { oldVoteLocationGuid = person.VotingLocationGuid; // it is already set this way...turn if off person.VotingMethod = null; person.VotingLocationGuid = null; person.RegistrationTime = DateTime.Now; votingMethodRemoved = true; var log = person.RegistrationLogAsList; log.Add(new[] { ShowRegistrationTime(timeOffset, person), "De-selected", ShowTellers(person), LocationName(UserSession.CurrentLocationGuid), }.JoinedAsString("; ", true)); person.RegistrationLogAsList = log; } else { person.VotingMethod = voteType; oldVoteLocationGuid = person.VotingLocationGuid; person.VotingLocationGuid = UserSession.CurrentLocationGuid; person.RegistrationTime = DateTime.Now; newVoteLocationGuid = person.VotingLocationGuid; var log = person.RegistrationLogAsList; log.Add(new[] { ShowRegistrationTime(timeOffset, person), VotingMethodEnum.TextFor(person.VotingMethod), ShowTellers(person), LocationName(person.VotingLocationGuid), }.JoinedAsString("; ", true)); person.RegistrationLogAsList = log; // make number for every method except Registered var needEnvNum = person.EnvNum == null && voteType != VotingMethodEnum.Registered; if (needEnvNum) { person.EnvNum = new ElectionModel().GetNextEnvelopeNumber(); } } personCacher.UpdateItemAndSaveCache(person); UpdateFrontDeskListing(person, votingMethodRemoved); if (lastRowVersion == 0) { lastRowVersion = person.C_RowVersionInt.AsLong() - 1; } UpdateLocationCounts(newVoteLocationGuid, oldVoteLocationGuid, personCacher); Db.SaveChanges(); return(true.AsJsonResult()); }
public bool CreateBallotForOnlineVoter(List <OnlineRawVote> poolList, out string errorMessage) { //{Id: 0, First:"", Last:"", OtherInfo:""} // double check var numberToElect = UserSession.CurrentElection.NumberToElect; if (poolList.Count != numberToElect) { errorMessage = $"Invalid number of votes ({poolList.Count}). Need {numberToElect}."; return(false); } var ballotCacher = new BallotCacher(Db); var voteCacher = new VoteCacher(Db); var locationHelper = new LocationModel(Db); var location = locationHelper.GetOnlineLocation(); // create ballot var ballot = new Ballot { BallotGuid = Guid.NewGuid(), LocationGuid = location.LocationGuid, ComputerCode = ComputerModel.ComputerCodeForOnline, BallotNumAtComputer = 0, // maxNum + 1, // will reset later StatusCode = BallotStatusEnum.Empty, }; Db.Ballot.Add(ballot); Db.SaveChanges(); ballotCacher.UpdateItemAndSaveCache(ballot); // add Votes var nextVoteNum = 0; foreach (var rawVote in poolList) { Vote vote; if (rawVote.Id > 0) { var person = new PersonCacher(Db).AllForThisElection.FirstOrDefault(b => b.C_RowId == rawVote.Id); if (person == null) { errorMessage = $"Error converting pool id {rawVote.Id} to person."; return(false); } vote = new Vote { BallotGuid = ballot.BallotGuid, PositionOnBallot = ++nextVoteNum, StatusCode = VoteStatusCode.Ok, PersonGuid = person.PersonGuid, PersonCombinedInfo = person.CombinedInfo, SingleNameElectionCount = 1, // okay if set for normal election too InvalidReasonGuid = person.CanReceiveVotes.AsBoolean(true) ? null : person.IneligibleReasonGuid }; } else { // "random" vote vote = new Vote { BallotGuid = ballot.BallotGuid, PositionOnBallot = ++nextVoteNum, StatusCode = VoteStatusCode.OnlineRaw, SingleNameElectionCount = 1, OnlineVoteRaw = JsonConvert.SerializeObject(rawVote), }; // attempt to match if it is exact... var matched = new PersonCacher(Db).AllForThisElection // match on first and last name only .Where(p => p.FirstName.ToLower() == rawVote.First.ToLower() && p.LastName.ToLower() == rawVote.Last.ToLower()) // don't match if our list has "otherInfo" for this person - there might be some special considerations .Where(p => p.OtherInfo.HasNoContent()) .ToList(); if (matched.Count == 1) { // found one exact match var person = matched[0]; vote.StatusCode = VoteStatusCode.Ok; vote.PersonGuid = person.PersonGuid; vote.PersonCombinedInfo = person.CombinedInfo; vote.InvalidReasonGuid = person.CanReceiveVotes.AsBoolean(true) ? null : person.IneligibleReasonGuid; } } Db.Vote.Add(vote); Db.SaveChanges(); voteCacher.UpdateItemAndSaveCache(vote); } var votes = voteCacher.AllForThisElection; BallotAnalyzerLocal.UpdateBallotStatus(ballot, VoteInfosFor(ballot, votes), true); ballotCacher.UpdateItemAndSaveCache(ballot); Db.SaveChanges(); errorMessage = ""; return(true); }
private object GetVoteUpdates(int lastVoteId, VoteCacher voteCacher, bool isSingleName, PersonCacher personCacher) { if (lastVoteId == 0) { // single name elections return(null); } // ignores vote and ballot status - count how many times the name has been written on ballots var peopleInRecentVotes = voteCacher .AllForThisElection .Where(v => v.C_RowId > lastVoteId && v.PersonGuid != null) .Select(v => v.PersonGuid) .Distinct(); var counts = voteCacher .AllForThisElection .Where(v => peopleInRecentVotes.Contains(v.PersonGuid)) .GroupBy(v => v.PersonGuid) .Join(personCacher.AllForThisElection, votes => votes.Key, p => p.PersonGuid, (votes, p) => new { votes, p }) .Select(g => new { Id = g.p.C_RowId, Count = g.votes.Sum(v => isSingleName ? v.SingleNameElectionCount : 1) }) .ToList(); return(counts); }
public JsonResult SaveVote(int personId, int voteId, Guid?invalidReason, int lastVid, int count, bool verifying) { if (UserSession.CurrentElectionStatus == ElectionTallyStatusEnum.Finalized) { return(new { Message = UserSession.FinalizedNoChangesMessage }.AsJsonResult()); } var locationModel = new LocationModel(); if (locationModel.HasMultiplePhysicalLocations && UserSession.CurrentLocation == null) { return(new { Message = "Must select your location first!" }.AsJsonResult()); } if (UserSession.GetCurrentTeller(1).HasNoContent()) { return(new { Message = "Must select \"Teller at Keyboard\" first!" }.AsJsonResult()); } var isSingleName = UserSession.CurrentElection.IsSingleNameElection; var ballot = GetCurrentBallot(); if (ballot == null) { // don't have an active Ballot! return(new { Updated = false, Error = "Invalid ballot" }.AsJsonResult()); } Db.Ballot.Attach(ballot); var voteCacher = new VoteCacher(Db); var personCacher = new PersonCacher(Db); if (voteId != 0) { // update existing record // find info about the existing Vote var vote = voteCacher.AllForThisElection.SingleOrDefault(v => v.C_RowId == voteId); if (vote == null) { // problem... client has a vote number, but we didn't find... return(new { Updated = false, Error = "Invalid vote id" }.AsJsonResult()); } if (vote.BallotGuid != ballot.BallotGuid) { // problem... client is focused on a different ballot! return(new { Updated = false, Error = "Invalid vote/ballot id" }.AsJsonResult()); } Db.Vote.Attach(vote); vote.SingleNameElectionCount = count; var person1 = personCacher.AllForThisElection.SingleOrDefault(p => p.C_RowId == personId); vote.PersonCombinedInfo = person1?.CombinedInfo; if (UserSession.CurrentLocation.IsVirtual) { // changing person on an online ballot if (person1 == null) { vote.PersonGuid = null; } else { vote.PersonGuid = person1.PersonGuid; invalidReason = person1.IneligibleReasonGuid; } vote.StatusCode = invalidReason == null ? VoteStatusCode.Ok : VoteStatusCode.Spoiled; } DetermineInvalidReasonGuid(invalidReason, vote); vote.StatusCode = VoteAnalyzer.DetermineStatus(new VoteInfo(vote, UserSession.CurrentElection, ballot, UserSession.CurrentLocation, person1)); Db.SaveChanges(); var votes = voteCacher.UpdateItemAndSaveCache(vote).AllForThisElection; var ballotStatusInfo = BallotAnalyzerLocal.UpdateBallotStatus(ballot, VoteInfosFor(ballot, votes), true); var sum = _helper.BallotCount(ballot.LocationGuid, isSingleName, null, votes); ballot.Teller1 = UserSession.GetCurrentTeller(1); ballot.Teller2 = UserSession.GetCurrentTeller(2); new BallotCacher(Db).UpdateItemAndSaveCache(ballot); Db.SaveChanges(); var ballotCounts = isSingleName ? new VoteCacher().AllForThisElection .Where(v => v.BallotGuid == ballot.BallotGuid) .Sum(v => v.SingleNameElectionCount) : 0; var ballotCountNames = isSingleName ? new VoteCacher().AllForThisElection .Count(v => v.BallotGuid == ballot.BallotGuid) : 0; return(new { Updated = true, BallotStatus = ballotStatusInfo.Status.Value, BallotStatusText = ballotStatusInfo.Status.DisplayText, ballotStatusInfo.SpoiledCount, LocationBallotsEntered = sum, BallotId = ballot.C_RowId, SingleBallotCount = ballotCounts, SingleBallotNames = ballotCountNames, VoteUpdates = GetVoteUpdates(lastVid, voteCacher, isSingleName, personCacher), LastVid = vote.C_RowId, vote.InvalidReasonGuid, Name = person1?.C_FullName, person1?.Area, vote = CurrentVotesForJs(GetCurrentBallot(), new List <Vote> { vote }).First() }.AsJsonResult()); } // make a new Vote record var location = new LocationCacher(Db).AllForThisElection.Single(l => l.LocationGuid == ballot.LocationGuid); if (location.IsVirtual) { return(new { Updated = false, Error = "Cannot add votes to an online ballot" }.AsJsonResult()); } var invalidReasonGuid = DetermineInvalidReasonGuid(invalidReason); var person = personCacher.AllForThisElection.SingleOrDefault(p => p.C_RowId == personId); var ok = person != null || (invalidReason != null && invalidReasonGuid != Guid.Empty); if (ok) { var nextVoteNum = 1 + voteCacher.AllForThisElection.Where(v => v.BallotGuid == ballot.BallotGuid) .OrderByDescending(v => v.PositionOnBallot) .Take(1) .Select(b => b.PositionOnBallot) .SingleOrDefault(); var vote = new Vote { BallotGuid = ballot.BallotGuid, PositionOnBallot = nextVoteNum, StatusCode = VoteStatusCode.Ok, SingleNameElectionCount = count }; if (person != null) { vote.PersonGuid = person.PersonGuid; vote.PersonCombinedInfo = person.CombinedInfo; vote.InvalidReasonGuid = person.CanReceiveVotes.AsBoolean(true) ? null : person.IneligibleReasonGuid; // VoteHelperLocal.IneligibleToReceiveVotes(person.IneligibleReasonGuid, // person.CanReceiveVotes); } vote.InvalidReasonGuid = invalidReasonGuid; Db.Vote.Add(vote); Db.SaveChanges(); var votes = voteCacher.UpdateItemAndSaveCache(vote).AllForThisElection; var rawBallot = CurrentRawBallot(); var ballotStatusInfo = BallotAnalyzerLocal.UpdateBallotStatus(rawBallot, VoteInfosFor(rawBallot, votes), true); var sum = _helper.BallotCount(ballot.LocationGuid, isSingleName, null, votes); new BallotCacher(Db).UpdateItemAndSaveCache(rawBallot); Db.SaveChanges(); var ballotCounts = isSingleName ? new VoteCacher().AllForThisElection .Where(v => v.BallotGuid == ballot.BallotGuid) .Sum(v => v.SingleNameElectionCount) : 0; var ballotCountNames = isSingleName ? new VoteCacher().AllForThisElection .Count(v => v.BallotGuid == ballot.BallotGuid) : 0; return(new { Updated = true, VoteId = vote.C_RowId, pos = vote.PositionOnBallot, BallotStatus = ballotStatusInfo.Status.Value, BallotStatusText = ballotStatusInfo.Status.DisplayText, ballotStatusInfo.SpoiledCount, BallotId = ballot.C_RowId, LocationBallotsEntered = sum, SingleBallotCount = ballotCounts, SingleBallotNames = ballotCountNames, VoteUpdates = GetVoteUpdates(lastVid, voteCacher, isSingleName, personCacher), LastVid = vote.C_RowId }.AsJsonResult()); } // don't recognize person id return(new { Updated = false, Error = "Invalid person. Please try again." }.AsJsonResult()); }
public object GetCurrentResults() { try { var resultSummaryFinal = _analyzer.ResultSummaryFinal; // resultSummaries.SingleOrDefault(rs => rs.ResultType == ResultType.Final); //TODO build online checks into base analysis // don't show any details if review is needed or online ballots need to be processed var issues = new List <string>(); if (_election.OnlineCurrentlyOpen) { issues.Add("Online voting is still open. It must be Closed before analyzing ballots."); } var unprocessedOnlineBallots = _election.OnlineWhenOpen.HasValue ? Db.OnlineVotingInfo .Join(Db.Person.Where(p => p.VotingMethod == VotingMethodEnum.Online.Value), ovi => ovi.PersonGuid, p => p.PersonGuid, (ovi, p) => ovi) .Count(ovi => ovi.ElectionGuid == UserSession.CurrentElectionGuid && ovi.Status == OnlineBallotStatusEnum.Submitted) : 0; if (unprocessedOnlineBallots > 0) { issues.Add($"Online ballots waiting to be accepted: {unprocessedOnlineBallots}"); } if (resultSummaryFinal.BallotsNeedingReview != 0 || issues.Any()) { var locations = new LocationCacher(Db).AllForThisElection; var multipleLocations = locations.Count() > 1; var needReview = _analyzer.VoteInfos.Where(VoteAnalyzer.VoteNeedReview) .Join(locations, vi => vi.LocationId, l => l.C_RowId, (vi, location) => new { vi, location }) .Select(x => new { x.vi.LocationId, x.vi.BallotId, Status = BallotStatusEnum.TextFor(x.vi.BallotStatusCode), Ballot = multipleLocations ? $"{x.vi.C_BallotCode} ({x.location.Name})" : x.vi.C_BallotCode, }) .Distinct() .OrderBy(x => x.Ballot); var needReview2 = _analyzer.Ballots.Where(BallotAnalyzer.BallotNeedsReview) .Join(locations, b => b.LocationGuid, l => l.LocationGuid, (b, location) => new { b, location }) .OrderBy(x => x.b.ComputerCode) .ThenBy(x => x.b.BallotNumAtComputer) .Select(x => new { LocationId = x.location.C_RowId, BallotId = x.b.C_RowId, Status = BallotStatusEnum.TextFor(x.b.StatusCode), Ballot = multipleLocations ? $"{x.b.C_BallotCode} ({x.location.Name})" : x.b.C_BallotCode }); return(new { NeedReview = needReview.Concat(needReview2).Distinct(), _election.VotingMethods, ResultsFinal = _analyzer.ResultSummaryFinal .GetPropertiesExcept(null, new[] { "ElectionGuid" }), ResultsCalc = _analyzer.ResultSummaries.First(rs => rs.ResultType == ResultType.Calculated) .GetPropertiesExcept(null, new[] { "ElectionGuid" }), ResultsManual = (_analyzer.ResultSummaries.FirstOrDefault(rs => rs.ResultType == ResultType.Manual) ?? new ResultSummary()).GetPropertiesExcept(null, new[] { "ElectionGuid" }), OnlineIssues = issues, _election.OnlineCurrentlyOpen //ResultsFinal = // resultSummaries.First(rs => rs.ResultType == ResultType.Final) // .GetPropertiesExcept(null, new[] { "ElectionGuid" }), }); } // show vote totals var persons = new PersonCacher(Db).AllForThisElection; var vResultInfos = // TODO 2012-01-21 Glen Little: Could return fewer columns for non-tied results _analyzer.Results // new ResultCacher(Db).AllForThisElection .OrderBy(r => r.Rank) .ToList() .Select(r => new { rid = r.C_RowId, r.CloseToNext, r.CloseToPrev, r.ForceShowInOther, r.IsTied, r.IsTieResolved, PersonName = PersonNameFor(persons, r), r.Rank, //ri.RankInExtra, r.Section, r.TieBreakCount, r.TieBreakGroup, r.TieBreakRequired, r.VoteCount }).ToList(); var ties = _analyzer.ResultTies // new ResultTieCacher(Db).AllForThisElection .OrderBy(rt => rt.TieBreakGroup) .Select(rt => new { rt.TieBreakGroup, rt.NumInTie, rt.NumToElect, rt.TieBreakRequired, rt.IsResolved }).ToList(); //var spoiledVotesSummary = Db.vVoteInfoes.where return(new { Votes = vResultInfos, UserSession.CurrentElectionStatus, Ties = ties, NumToElect = _election.NumberToElect, NumExtra = _election.NumberExtra, // ShowCalledIn = _election.UseCallInButton, // _election.CustomMethods, _election.VotingMethods, ShowOnline = _election.OnlineWhenOpen.HasValue, ResultsManual = (_analyzer.ResultSummaries.FirstOrDefault(rs => rs.ResultType == ResultType.Manual) ?? new ResultSummary()) .GetPropertiesExcept(null, new[] { "ElectionGuid" }), ResultsCalc = _analyzer.ResultSummaries.First(rs => rs.ResultType == ResultType.Calculated) .GetPropertiesExcept(null, new[] { "ElectionGuid" }), ResultsFinal = _analyzer.ResultSummaries.First(rs => rs.ResultType == ResultType.Final) .GetPropertiesExcept(null, new[] { "ElectionGuid" }), }); } catch (Exception ex) { return(new { Interrupted = true, Msg = ex.GetAllMsgs("; ") + "\n" + ex.StackTrace }); } }
/// <summary> /// Mark online ballot as "submitted" or locked. /// </summary> /// <param name="locked"></param> /// <returns></returns> public JsonResult LockPool(bool locked) { var currentElection = UserSession.CurrentElection; var personGuid = UserSession.VoterInElectionPersonGuid; var onlineVotingInfo = Db.OnlineVotingInfo .SingleOrDefault(ovi => ovi.ElectionGuid == currentElection.ElectionGuid && ovi.PersonGuid == personGuid); if (onlineVotingInfo == null) { return(new { Error = "Invalid request" }.AsJsonResult()); } if (onlineVotingInfo.Status == OnlineBallotStatusEnum.Processed) { // already processed... don't do anything return(new { Error = "Ballot already processed" }.AsJsonResult()); } var now = DateTime.Now; if (currentElection.OnlineWhenOpen <= now && currentElection.OnlineWhenClose > now) { var onlineVoteHelper = new OnlineVoteHelper(); var logHelper = new LogHelper(); if (!EncryptionHelper.IsEncrypted(onlineVotingInfo.ListPool)) { // upgrade previous record onlineVoteHelper.SetListPoolEncrypted(onlineVotingInfo); } if (locked) { // ensure we have enough votes var rawPool = onlineVoteHelper.GetDecryptedListPool(onlineVotingInfo, out var errorMessage); if (rawPool == null) { logHelper.Add("LockPool but pool is empty. " + errorMessage, true); return(new { Error = "Pool is empty" }.AsJsonResult()); } if (errorMessage.HasContent()) { logHelper.Add(errorMessage, true); return(new { Error = errorMessage }.AsJsonResult()); } List <OnlineRawVote> completePool; try { completePool = JsonConvert.DeserializeObject <List <OnlineRawVote> >(rawPool); } catch (Exception e) { logHelper.Add("LockPool but pool has invalid JSON. " + e.GetBaseException().Message + "... Start of pool: " + rawPool.Left(30), true); return(new { Error = "Technical error in pool. Please edit and try again." }.AsJsonResult()); } var numVotes = completePool.Count; if (numVotes < currentElection.NumberToElect) { var msg = $"Too few votes ({numVotes})"; logHelper.Add(msg + $" Required ({currentElection.NumberToElect})", true); return(new { Error = msg }.AsJsonResult()); } } onlineVotingInfo.PoolLocked = locked; onlineVotingInfo.Status = locked ? OnlineBallotStatusEnum.Submitted : OnlineBallotStatusEnum.Draft; onlineVotingInfo.HistoryStatus += $";{onlineVotingInfo.Status} ({UserSession.VoterLoginSource})|{now.ToJSON()}".FilledWith(onlineVotingInfo.Status, now.ToJSON()); onlineVotingInfo.WhenStatus = now; var personCacher = new PersonCacher(Db); var person = personCacher.AllForThisElection.SingleOrDefault(p => p.PersonGuid == onlineVotingInfo.PersonGuid); if (person == null) { return(new { Error = "Invalid request (2)" }.AsJsonResult()); } if (!person.CanVote.AsBoolean()) { return(new { Error = "Cannot vote" }.AsJsonResult()); } Db.Person.Attach(person); var peopleModel = new PeopleModel(); var votingMethodRemoved = false; string notificationType = null; person.HasOnlineBallot = locked; if (person.VotingMethod.HasContent() && person.VotingMethod != VotingMethodEnum.Online) { // teller has set. Voter can't change it... } else { if (locked) { person.VotingMethod = VotingMethodEnum.Online; person.RegistrationTime = now; person.VotingLocationGuid = new LocationModel().GetOnlineLocation().LocationGuid; person.EnvNum = null; var log = person.RegistrationLog; log.Add(new[] { peopleModel.ShowRegistrationTime(person, true), UserSession.VoterLoginSource, VotingMethodEnum.TextFor(person.VotingMethod), }.JoinedAsString("; ", true)); person.RegistrationLog = log; // logHelper.Add("Locked ballot"); logHelper.Add("Submitted Ballot", false, UserSession.VoterId); var notificationHelper = new NotificationHelper(); var notificationSent = notificationHelper.SendWhenBallotSubmitted(person, currentElection, out notificationType, out var error); if (!notificationSent) { notificationType = null; } } else { // not online or anywhere person.VotingMethod = null; person.VotingLocationGuid = null; person.EnvNum = null; votingMethodRemoved = true; var log = person.RegistrationLog; person.RegistrationTime = now; // set time so that the log will have it log.Add(new[] { peopleModel.ShowRegistrationTime(person, true), "Cancel Online", }.JoinedAsString("; ", true)); person.RegistrationTime = null; // don't keep it visible person.RegistrationLog = log; // logHelper.Add("Unlocked ballot"); logHelper.Add("Recalled Ballot", false, UserSession.VoterId); } } Db.SaveChanges(); personCacher.UpdateItemAndSaveCache(person); peopleModel.UpdateFrontDeskListing(person, votingMethodRemoved); // okay return(new { success = true, notificationType, person.VotingMethod, ElectionGuid = UserSession.CurrentElectionGuid, person.RegistrationTime, onlineVotingInfo.WhenStatus, onlineVotingInfo.PoolLocked }.AsJsonResult()); } return(new { Error = "Closed" }.AsJsonResult()); }
public JsonResult Import(int rowId) { var file = Db.ImportFile.SingleOrDefault( fi => fi.ElectionGuid == UserSession.CurrentElectionGuid && fi.C_RowId == rowId); if (file == null) { return(new { failed = true, result = new[] { "File not found" } }.AsJsonResult()); } var columnsToRead = file.ColumnsToRead; if (columnsToRead == null) { return(new { failed = true, result = new[] { "Mapping not defined" } }.AsJsonResult()); } var start = DateTime.Now; var textReader = new StringReader(file.Contents.AsString(file.CodePage)); var csv = new CsvReader(textReader, true) { SkipEmptyLines = true }; //mapping: csv->db,csv->db var currentMappings = columnsToRead.DefaultTo("").SplitWithString(",").Select(s => s.SplitWithString("->")).ToList(); var dbFields = DbFieldsList.ToList(); var validMappings = currentMappings.Where(mapping => dbFields.Contains(mapping[1])).ToList(); if (validMappings.Count == 0) { return(new { failed = true, result = new[] { "Mapping not defined" } }.AsJsonResult()); } var mappedFields = dbFields.Where(f => validMappings.Select(m => m[1]).Contains(f)).ToList(); if (!mappedFields.Contains("LastName")) { return(new { failed = true, result = new[] { "Last Name must be mapped" } }.AsJsonResult()); } var currentPeople = new PersonCacher(Db).AllForThisElection.ToList(); var personModel = new PeopleModel(); var defaultReason = new ElectionModel().GetDefaultIneligibleReason(); var rowsProcessed = 0; var rowsSkipped = 0; var peopleAdded = 0; var peopleSkipped = 0; var peopleSkipWarningGiven = false; var hub = new ImportHub(); var peopleToLoad = new List <Person>(); var result = new List <string>(); var unexpectedReasons = new Dictionary <string, int>(); var validReasons = 0; csv.ReadNextRecord(); while (!csv.EndOfStream) { rowsProcessed++; var valuesSet = false; var namesFoundInRow = false; var query = currentPeople.AsQueryable(); var person = new Person(); var reason = defaultReason; foreach (var currentMapping in validMappings) { var dbFieldName = currentMapping[1]; var value = csv[currentMapping[0]]; switch (dbFieldName) { case "IneligibleReasonGuid": // match value to the list of Enums value = value.Trim(); if (value.HasContent()) { var match = IneligibleReasonEnum.GetFor(value); if (match != null) { reason = match; validReasons += 1; } else { // tried but didn't match a valid reason! reason = defaultReason; value = HttpUtility.HtmlEncode(value); result.Add("Invalid Eligibility Status reason on line {0}: {1}".FilledWith(rowsProcessed + 1, value)); if (unexpectedReasons.ContainsKey(value)) { unexpectedReasons[value] += 1; } else { unexpectedReasons.Add(value, 1); } } } break; default: person.SetPropertyValue(dbFieldName, value); break; } ; valuesSet = true; switch (dbFieldName) { case "LastName": query = query.Where(p => p.LastName == value); namesFoundInRow = namesFoundInRow || value.HasContent(); break; case "FirstName": query = query.Where(p => p.FirstName == value); namesFoundInRow = namesFoundInRow || value.HasContent(); break; case "OtherLastNames": query = query.Where(p => p.OtherLastNames == value); break; case "OtherNames": query = query.Where(p => p.OtherNames == value); break; case "OtherInfo": query = query.Where(p => p.OtherInfo == value); break; case "Area": query = query.Where(p => p.Area == value); break; case "BahaiId": query = query.Where(p => p.BahaiId == value); break; case "IneligibleReasonGuid": //if (reason != defaultReason) //{ // query = query.Where(p => p.IneligibleReasonGuid == reason.Value); //} break; default: throw new ApplicationException("Unexpected: " + dbFieldName); } } if (!valuesSet || !namesFoundInRow) { rowsSkipped++; result.Add("Skipping line " + rowsProcessed); } else if (query.Any()) { peopleSkipped++; if (peopleSkipped < 10) { result.Add("Duplicate on line " + (rowsProcessed + 1)); } else { if (!peopleSkipWarningGiven) { result.Add("More duplicates... (Only the first 10 are noted.)"); peopleSkipWarningGiven = true; } } } else { //get ready for DB person.ElectionGuid = UserSession.CurrentElectionGuid; person.PersonGuid = Guid.NewGuid(); personModel.SetCombinedInfoAtStart(person); personModel.SetInvolvementFlagsToDefault(person, reason); //Db.Person.Add(person); currentPeople.Add(person); peopleToLoad.Add(person); peopleAdded++; if (peopleToLoad.Count >= 500) { //Db.SaveChanges(); Db.BulkInsert(peopleToLoad); peopleToLoad.Clear(); } } if (rowsProcessed % 100 == 0) { hub.ImportInfo(rowsProcessed, peopleAdded); } csv.ReadNextRecord(); } if (peopleToLoad.Count != 0) { Db.BulkInsert(peopleToLoad); } file.ProcessingStatus = "Imported"; Db.SaveChanges(); new PersonCacher().DropThisCache(); result.AddRange(new[] { "Processed {0} data line{1}".FilledWith(rowsProcessed, rowsProcessed.Plural()), "Added {0} {1}.".FilledWith(peopleAdded, peopleAdded.Plural("people", "person")) }); if (peopleSkipped > 0) { result.Add("{0} duplicate{1} ignored.".FilledWith(peopleSkipped, peopleSkipped.Plural())); } if (rowsSkipped > 0) { result.Add("{0} line{1} skipped or blank.".FilledWith(rowsSkipped, rowsSkipped.Plural())); } if (validReasons > 0) { result.Add("{0} {1} with recognized Eligibility Status Reasons.".FilledWith(validReasons, validReasons.Plural("people", "person"))); } if (unexpectedReasons.Count > 0) { result.Add("{0} Eligibility Status Reason{1} not recognized: ".FilledWith(unexpectedReasons.Count, unexpectedReasons.Count.Plural())); foreach (var r in unexpectedReasons) { result.Add(" \"{0}\"{1}".FilledWith(r.Key, r.Value == 1 ? "" : " x" + r.Value)); } } result.Add("Import completed in " + (DateTime.Now - start).TotalSeconds.ToString("0.0") + " s."); new LogHelper().Add("Imported file #" + rowId + ": " + result.JoinedAsString(" "), true); return(new { result, count = NumberOfPeople }.AsJsonResult()); }
public JsonResult Import(int rowId) { var file = Db.ImportFile.SingleOrDefault( fi => fi.ElectionGuid == UserSession.CurrentElectionGuid && fi.C_RowId == rowId); if (file == null) { return(new { failed = true, result = new[] { "File not found" } }.AsJsonResult()); } var columnsToRead = file.ColumnsToRead; if (columnsToRead == null) { return(new { failed = true, result = new[] { "Mapping not defined" } }.AsJsonResult()); } var start = DateTime.Now; var fileString = file.Contents.AsString(file.CodePage); var firstDataRow = file.FirstDataRow.AsInt(); var numFirstRowsToSkip = firstDataRow - 2; if (numFirstRowsToSkip > 0) { // 1 based... headers on line 1, data on line 2. If 2 or less, ignore it. fileString = fileString.GetLinesAfterSkipping(numFirstRowsToSkip); } else { numFirstRowsToSkip = 0; } var textReader = new StringReader(fileString); var csv = new CsvReader(textReader, true, ',', '"', '"', '#', ValueTrimmingOptions.All, 4096, null) { // had to provide all parameters in order to set ValueTrimmingOption.All SkipEmptyLines = false, MissingFieldAction = MissingFieldAction.ReplaceByEmpty, SupportsMultiline = false, }; //mapping: csv->db,csv->db var currentMappings = columnsToRead.DefaultTo("").SplitWithString(",").Select(s => s.SplitWithString(MappingSymbol)).ToList(); var dbFields = DbFieldsList.ToList(); var validMappings = currentMappings.Where(mapping => dbFields.Contains(mapping[1])).ToList(); if (validMappings.Count == 0) { return(new { failed = true, result = new[] { "Mapping not defined" } }.AsJsonResult()); } var mappedFields = dbFields.Where(f => validMappings.Select(m => m[1]).Contains(f)).ToList(); if (!mappedFields.Contains("LastName")) { return(new { failed = true, result = new[] { "Last Name must be mapped" } }.AsJsonResult()); } if (!mappedFields.Contains("FirstName")) { return(new { failed = true, result = new[] { "First Name must be mapped" } }.AsJsonResult()); } var phoneNumberChecker = new Regex(@"\+[0-9]{4,15}"); var phoneNumberCleaner = new Regex(@"[^\+0-9]"); var emailChecker = new Regex(@".*@.*\..*"); var currentPeople = new PersonCacher(Db).AllForThisElection.ToList(); currentPeople.ForEach(p => p.TempImportLineNum = -1); var knownEmails = currentPeople.Where(p => p.Email != null).Select(p => p.Email.ToLower()).ToList(); var knownPhones = currentPeople.Where(p => p.Phone != null).Select(p => p.Phone).ToList(); var personModel = new PeopleModel(); // var defaultReason = new ElectionModel().GetDefaultIneligibleReason(); var currentLineNum = numFirstRowsToSkip > 0 ? numFirstRowsToSkip : 1; // including header row var rowsWithErrors = 0; var peopleAdded = 0; var peopleSkipped = 0; // var peopleSkipWarningGiven = false; var hub = new ImportHub(); var peopleToLoad = new List <Person>(); var result = new List <string>(); var unexpectedReasons = new Dictionary <string, int>(); // var validReasons = 0; var continueReading = true; hub.StatusUpdate("Processing", true); while (csv.ReadNextRecord() && continueReading) { if (csv.GetCurrentRawData() == null) { continue; } // currentLineNum++; currentLineNum = numFirstRowsToSkip + (int)csv.CurrentRecordIndex + 1; var valuesSet = false; var namesFoundInRow = 0; var errorInRow = false; var duplicateInFileSearch = currentPeople.AsQueryable(); var doDupQuery = false; var person = new Person { TempImportLineNum = currentLineNum }; foreach (var currentMapping in validMappings) { var csvColumnName = currentMapping[0]; var dbFieldName = currentMapping[1]; string value; try { value = csv[csvColumnName] ?? ""; } catch (Exception e) { result.Add($"~E Line {currentLineNum} - {e.Message.Split('\r')[0]}. Are there \"\" marks missing?"); errorInRow = true; continueReading = false; break; } var rawValue = HttpUtility.HtmlEncode(value); var originalValue = value; switch (dbFieldName) { case "IneligibleReasonGuid": // match value to the list of Enums value = value.Trim(); if (value.HasContent()) { if (value == "Eligible") { // leave as null } else { var match = IneligibleReasonEnum.GetFor(value); if (match != null) { person.IneligibleReasonGuid = match.Value; } else { // tried but didn't match a valid reason! errorInRow = true; result.Add($"~E Line {currentLineNum} - Invalid Eligibility Status reason: {rawValue}"); if (unexpectedReasons.ContainsKey(value)) { unexpectedReasons[value] += 1; } else { unexpectedReasons.Add(value, 1); } } } } break; case "FirstName": case "LastName": if (value.Trim() == "") { result.Add($"~E Line {currentLineNum} - {dbFieldName} must not be blank"); } else { person.SetPropertyValue(dbFieldName, value); } break; default: person.SetPropertyValue(dbFieldName, value); break; } ; valuesSet = valuesSet || value.HasContent(); if (value.HasContent()) { doDupQuery = true; switch (dbFieldName) { case "LastName": duplicateInFileSearch = duplicateInFileSearch.Where(p => p.LastName == value); namesFoundInRow++; break; case "FirstName": duplicateInFileSearch = duplicateInFileSearch.Where(p => p.FirstName == value); namesFoundInRow++; break; case "OtherLastNames": duplicateInFileSearch = duplicateInFileSearch.Where(p => p.OtherLastNames == value); break; case "OtherNames": duplicateInFileSearch = duplicateInFileSearch.Where(p => p.OtherNames == value); break; case "OtherInfo": duplicateInFileSearch = duplicateInFileSearch.Where(p => p.OtherInfo == value); break; case "Area": duplicateInFileSearch = duplicateInFileSearch.Where(p => p.Area == value); break; case "BahaiId": duplicateInFileSearch = duplicateInFileSearch.Where(p => p.BahaiId == value); break; case "Email": if (value.HasContent()) { value = value.ToLower(); if (!emailChecker.IsMatch(value)) { result.Add($"~E Line {currentLineNum} - Invalid email: {rawValue}"); errorInRow = true; } else if (knownEmails.Contains(value)) { result.Add($"~E Line {currentLineNum} - Duplicate email: {rawValue}"); errorInRow = true; } if (!errorInRow) { knownEmails.Add(value); } } break; case "Phone": if (value.HasContent()) { value = phoneNumberCleaner.Replace(value, ""); if (!value.StartsWith("+") && value.Length == 10) { // assume north american value = "+1" + value; } if (!phoneNumberChecker.IsMatch(value)) { result.Add($"~E Line {currentLineNum} - Invalid phone number: {rawValue}"); errorInRow = true; } else if (originalValue != value) { result.Add($"~W Line {currentLineNum} - Phone number adjusted from {rawValue} to {value} "); } if (value.HasContent()) { if (knownPhones.Contains(value)) { result.Add($"~E Line {currentLineNum} - Duplicate phone number: {value}"); errorInRow = true; } knownPhones.Add(value); } // update with the cleaned phone number person.SetPropertyValue(dbFieldName, value.HasContent() ? value : null); } break; case "IneligibleReasonGuid": break; default: throw new ApplicationException("Unexpected: " + dbFieldName); } } } var addRow = true; if (!valuesSet) { // don't count it as an error result.Add($"~I Line {currentLineNum} - Ignoring blank line"); addRow = false; } else if (namesFoundInRow != 2 || errorInRow) { addRow = false; rowsWithErrors++; if (namesFoundInRow != 2) { result.Add($"~E Line {currentLineNum} - First or last name missing"); } } if (doDupQuery) { var duplicates = duplicateInFileSearch.Select(p => p.TempImportLineNum).Distinct().ToList(); if (duplicates.Any()) { addRow = false; if (duplicates.All(n => n == -1)) { result.Add($"~I Line {currentLineNum} - {person.FirstName} {person.LastName} - skipped - Matching person found in existing records"); } else { peopleSkipped++; foreach (var n in duplicates.Where(n => n > 0)) { result.Add($"~E Line {currentLineNum} - {person.FirstName} {person.LastName} - Duplicate person found on line {n}"); } } } } if (addRow) { //get ready for DB person.ElectionGuid = UserSession.CurrentElectionGuid; person.PersonGuid = Guid.NewGuid(); personModel.SetCombinedInfoAtStart(person); personModel.ApplyVoteReasonFlags(person); peopleToLoad.Add(person); // result.Add($"~I Line {currentLineNum} - {person.FirstName} {person.LastName}"); -- not good for large lists! peopleAdded++; } currentPeople.Add(person); if (currentLineNum % 100 == 0) { hub.ImportInfo(currentLineNum, peopleAdded); } if (result.Count(s => s.StartsWith("~E")) == 10) { result.Add("~E Import aborted after 10 errors"); break; } } var abort = rowsWithErrors > 0 || peopleSkipped > 0; if (!abort && peopleToLoad.Count != 0) { hub.StatusUpdate("Saving"); var error = BulkInsert_CheckErrors(peopleToLoad); if (error != null) { abort = true; result.Add(error); } else { result.Add("Saved to database"); } } file.ProcessingStatus = abort ? "Import aborted" : "Imported"; Db.SaveChanges(); new PersonCacher().DropThisCache(); result.AddRange(new[] { "---------", $"Processed {currentLineNum:N0} data line{currentLineNum.Plural()}", }); // if (peopleSkipped > 0) // { // result.Add($"{peopleSkipped:N0} duplicate{peopleSkipped.Plural()} ignored."); // } if (rowsWithErrors > 0) { result.Add($"{rowsWithErrors:N0} line{rowsWithErrors.Plural("s had errors or were", " had errors or was")} blank."); } // if (validReasons > 0) // { // result.Add($"{validReasons:N0} {validReasons.Plural("people", "person")} with recognized Eligibility Status Reason{validReasons.Plural()}."); // } if (unexpectedReasons.Count > 0) { result.Add($"{unexpectedReasons.Count:N0} Eligibility Status Reason{unexpectedReasons.Count.Plural()} not recognized: "); foreach (var r in unexpectedReasons) { result.Add(" \"{0}\"{1}".FilledWith(r.Key, r.Value == 1 ? "" : " x" + r.Value)); } } result.Add("---------"); if (abort) { result.Add($"Import aborted due to errors in file. Please correct and try again."); } else { result.Add($"Added {peopleAdded:N0} {peopleAdded.Plural("people", "person")}."); result.Add($"Import completed in {(DateTime.Now - start).TotalSeconds:N1} s."); } var resultsForLog = result.Where(s => !s.StartsWith("~")); new LogHelper().Add("Imported file #" + rowId + ":\r" + resultsForLog.JoinedAsString("\r"), true); return(new { result, count = NumberOfPeople }.AsJsonResult()); }
public JsonResult SavePerson(Person personFromInput) { if (UserSession.CurrentElectionStatus == ElectionTallyStatusEnum.Finalized) { return(new { Message = UserSession.FinalizedNoChangesMessage }.AsJsonResult()); } var Db = SharedDbContext; var personInDatastore = PeopleInElection.SingleOrDefault(p => p.Id == personFromInput.Id); var changed = false; if (personInDatastore == null) { if (personFromInput.Id != -1) { return(new { Message = "Unknown ID" }.AsJsonResult()); } // create new personInDatastore = new Person { PersonGuid = Guid.NewGuid(), ElectionGuid = CurrentElectionGuid }; var reason = new ElectionModel().GetDefaultIneligibleReason(); SetInvolvementFlagsToDefault(personInDatastore, reason); Db.Person.Add(personInDatastore); PeopleInElection.Add(personInDatastore); changed = true; } else { Db.Person.Attach(personInDatastore); } if (personFromInput.IneligibleReasonGuid == Guid.Empty) { personFromInput.IneligibleReasonGuid = null; } var editableFields = new { // personFromInput.AgeGroup, personFromInput.BahaiId, personFromInput.FirstName, personFromInput.IneligibleReasonGuid, personFromInput.LastName, personFromInput.OtherInfo, personFromInput.OtherLastNames, personFromInput.OtherNames, personFromInput.Area, }.GetAllPropertyInfos().Select(pi => pi.Name).ToArray(); changed = personFromInput.CopyPropertyValuesTo(personInDatastore, editableFields) || changed; // these two may not be present, depending on the election type const string all = ElectionModel.CanVoteOrReceive.All; var canReceiveVotes = personFromInput.CanReceiveVotes.GetValueOrDefault(CurrentElection.CanReceive == all); if (personInDatastore.CanReceiveVotes != canReceiveVotes) { personInDatastore.CanReceiveVotes = canReceiveVotes; changed = true; } var canVote = personFromInput.CanVote.GetValueOrDefault(CurrentElection.CanVote == all); if (personInDatastore.CanVote != canVote) { personInDatastore.CanVote = canVote; changed = true; } if (changed) { SetCombinedInfos(personInDatastore); Db.SaveChanges(); new PersonCacher(Db).ReplaceEntireCache(PeopleInElection); UpdateFrontDeskListing(personInDatastore); } var persons = new PersonCacher(Db).AllForThisElection; return(new { Status = "Saved", Person = PersonForEdit(personInDatastore), OnFile = persons.Count(), Eligible = persons.Count(p => p.IneligibleReasonGuid == null), }.AsJsonResult()); }
public object GetCurrentResults() { //var ready = _analyzer.IsResultAvailable; var dbContext = GetNewDbContext(); try { var resultSummaryFinal = _analyzer.ResultSummaryFinal; // resultSummaries.SingleOrDefault(rs => rs.ResultType == ResultType.Final); // don't show any details if review is needed if (resultSummaryFinal.BallotsNeedingReview != 0) { var locations = new LocationCacher(dbContext).AllForThisElection; var multipleLocations = locations.Count() > 1; //TODO var needReview = _analyzer.VoteInfos // .Where(VoteAnalyzer.VoteNeedReview) .Join(locations, vi => vi.LocationId, l => l.Id, (vi, location) => new { vi, location }) .Select(x => new { x.vi.LocationId, x.vi.BallotId, Status = x.vi.BallotStatusCode == "Review" ? BallotStatusEnum.Review.DisplayText : "Verification Needed", Ballot = multipleLocations ? string.Format("{0} ({1})", x.vi.C_BallotCode, x.location.Name) : x.vi.C_BallotCode }) .Distinct() .OrderBy(x => x.Ballot); var needReview2 = _analyzer.Ballots.Where(b => b.StatusCode == BallotStatusEnum.Review) .Join(locations, b => b.LocationGuid, l => l.LocationGuid, (b, location) => new { b, location }) .Select(x => new { LocationId = x.location.Id, BallotId = x.b.Id, Status = x.b.StatusCode == "Review" ? BallotStatusEnum.Review.DisplayText : "Verification Needed", Ballot = multipleLocations ? string.Format("{0} ({1})", x.b.C_BallotCode, x.location.Name) : x.b.C_BallotCode }); return(new { NeedReview = needReview.Concat(needReview2).Distinct(), ResultsFinal = _analyzer.ResultSummaryFinal .GetPropertiesExcept(null, new[] { "ElectionGuid" }), ResultsCalc = _analyzer.ResultSummaries.First(rs => rs.ResultType == ResultType.Calculated) .GetPropertiesExcept(null, new[] { "ElectionGuid" }), ResultsManual = (_analyzer.ResultSummaries.FirstOrDefault(rs => rs.ResultType == ResultType.Manual) ?? new ResultSummary()).GetPropertiesExcept(null, new[] { "ElectionGuid" }), //ResultsFinal = // resultSummaries.First(rs => rs.ResultType == ResultType.Final) // .GetPropertiesExcept(null, new[] { "ElectionGuid" }), }); } // show vote totals var persons = new PersonCacher(dbContext).AllForThisElection; var vResultInfos = // TODO 2012-01-21 Glen Little: Could return fewer columns for non-tied results _analyzer.Results // new ResultCacher(Db).AllForThisElection .OrderBy(r => r.Rank) .ToList() .Select(r => new { rid = r.Id, r.CloseToNext, r.CloseToPrev, r.ForceShowInOther, r.IsTied, r.IsTieResolved, PersonName = PersonNameFor(persons, r), r.Rank, //ri.RankInExtra, r.Section, r.TieBreakCount, r.TieBreakGroup, r.TieBreakRequired, r.VoteCount }).ToList(); var ties = _analyzer.ResultTies // new ResultTieCacher(Db).AllForThisElection .OrderBy(rt => rt.TieBreakGroup) .Select(rt => new { rt.TieBreakGroup, rt.NumInTie, rt.NumToElect, rt.TieBreakRequired, rt.IsResolved }).ToList(); //var spoiledVotesSummary = Db.vVoteInfoes.where return(new { Votes = vResultInfos, UserSession.CurrentElectionStatus, Ties = ties, NumToElect = _election.NumberToElect, NumExtra = _election.NumberExtra, ShowCalledIn = _election.UseCallInButton, ResultsManual = (_analyzer.ResultSummaries.FirstOrDefault(rs => rs.ResultType == ResultType.Manual) ?? new ResultSummary()) .GetPropertiesExcept(null, new[] { "ElectionGuid" }), ResultsCalc = _analyzer.ResultSummaries.First(rs => rs.ResultType == ResultType.Calculated) .GetPropertiesExcept(null, new[] { "ElectionGuid" }), ResultsFinal = _analyzer.ResultSummaries.First(rs => rs.ResultType == ResultType.Final) .GetPropertiesExcept(null, new[] { "ElectionGuid" }), }); } catch (Exception ex) { return(new { Interrupted = true, Msg = ex.GetAllMsgs("; ") + "\n" + ex.StackTrace }); } }
public JsonResult SavePerson(Person personFromInput) { if (UserSession.CurrentElectionStatus == ElectionTallyStatusEnum.Finalized) { return(new { Message = UserSession.FinalizedNoChangesMessage }.AsJsonResult()); } var personInDatastore = PeopleInElection.SingleOrDefault(p => p.C_RowId == personFromInput.C_RowId); var changed = false; if (personInDatastore == null) { if (personFromInput.C_RowId != -1) { return(new { Message = "Unknown ID" }.AsJsonResult()); } // create new personInDatastore = new Person { PersonGuid = Guid.NewGuid(), ElectionGuid = CurrentElectionGuid }; Db.Person.Add(personInDatastore); PeopleInElection.Add(personInDatastore); changed = true; } else { Db.Person.Attach(personInDatastore); } var beforeChanges = personInDatastore.GetAllProperties(); if (personFromInput.IneligibleReasonGuid == Guid.Empty) { personFromInput.IneligibleReasonGuid = null; } if (personFromInput.Phone != null) { //check via Twilio to ensure real number? if (!new Regex(@"\+[0-9]{4,15}").IsMatch(personFromInput.Phone)) { return(new { Message = "Invalid phone number. Must start with + and only contain digits." }.AsJsonResult()); } } var editableFields = new { // personFromInput.AgeGroup, personFromInput.BahaiId, personFromInput.FirstName, personFromInput.IneligibleReasonGuid, personFromInput.LastName, personFromInput.OtherInfo, personFromInput.OtherLastNames, personFromInput.OtherNames, personFromInput.Area, personFromInput.Email, personFromInput.Phone, }.GetAllPropertyInfos().Select(pi => pi.Name).ToArray(); changed = personFromInput.CopyPropertyValuesTo(personInDatastore, editableFields) || changed; // var defaultReason = new ElectionModel().GetDefaultIneligibleReason(); if (ApplyVoteReasonFlags(personInDatastore)) { changed = true; } // const string all = ElectionModel.CanVoteOrReceive.All; // var canReceiveVotes = personFromInput.CanReceiveVotes.AsBoolean(CurrentElection.CanReceive == all); // if (personInDatastore.CanReceiveVotes != canReceiveVotes) // { // personInDatastore.CanReceiveVotes = canReceiveVotes; // changed = true; // } // // var canVote = personFromInput.CanVote.AsBoolean(CurrentElection.CanVote == all); // if (personInDatastore.CanVote != canVote) // { // personInDatastore.CanVote = canVote; // changed = true; // } if (changed) { SetCombinedInfos(personInDatastore); try { Db.SaveChanges(); } catch (Exception e) { // revert person object back to what it was beforeChanges.CopyPropertyValuesTo(personInDatastore); if (e.GetAllMsgs(";").Contains("IX_PersonEmail")) { return(new { Message = "That email is registered with another person.", Person = PersonForEdit(personInDatastore), }.AsJsonResult()); } if (e.GetAllMsgs(";").Contains("IX_PersonPhone")) { return(new { Message = "That phone number is registered with another person.", Person = PersonForEdit(personInDatastore), }.AsJsonResult()); } return(new { e.LastException().Message }.AsJsonResult()); } new PersonCacher(Db).ReplaceEntireCache(PeopleInElection); UpdateFrontDeskListing(personInDatastore); } var persons = new PersonCacher(Db).AllForThisElection; return(new { Status = "Saved", Person = PersonForEdit(personInDatastore), OnFile = persons.Count(), Eligible = persons.Count(p => p.IneligibleReasonGuid == null), //TODO? split to: can vote, can receive votes }.AsJsonResult()); }
public JsonResult RegisterVotingMethod(int personId, string voteType, bool forceDeselect, int locationId) { if (UserSession.CurrentElectionStatus == ElectionTallyStatusEnum.Finalized) { return(new { Message = UserSession.FinalizedNoChangesMessage }.AsJsonResult()); } var locationModel = new LocationModel(); var hasMultiplePhysicalLocations = locationModel.HasMultiplePhysicalLocations; if (hasMultiplePhysicalLocations && UserSession.CurrentLocation == null) { return(new { Message = "Must select your location first!" }.AsJsonResult()); } if (UserSession.CurrentLocation.C_RowId != locationId) { new ComputerModel().MoveCurrentComputerIntoLocation(locationId); } if (UserSession.GetCurrentTeller(1).HasNoContent()) { return(new { Message = "Must select \"Teller at Keyboard\" first!" }.AsJsonResult()); } if (!VotingMethodEnum.Exists(voteType)) { return(new { Message = "Invalid type" }.AsJsonResult()); } var personCacher = new PersonCacher(Db); var person = personCacher.AllForThisElection.SingleOrDefault(p => p.C_RowId == personId); if (person == null) { return(new { Message = "Unknown person" }.AsJsonResult()); } if (person.VotingMethod == VotingMethodEnum.Online) { var onlineVoter = Db.OnlineVotingInfo.SingleOrDefault(ovi => ovi.PersonGuid == person.PersonGuid && ovi.ElectionGuid == person.ElectionGuid); if (onlineVoter != null) { if (onlineVoter.Status == OnlineBallotStatusEnum.Processed) { return(new { Message = "This online ballot has been processed. Registration cannot be changed." }.AsJsonResult()); } } } Db.Person.Attach(person); person.Teller1 = UserSession.GetCurrentTeller(1); person.Teller2 = UserSession.GetCurrentTeller(2); var votingMethodRemoved = false; Guid?oldVoteLocationGuid = null; Guid?newVoteLocationGuid = null; if (person.VotingMethod == voteType || forceDeselect || !person.CanVote.AsBoolean()) { oldVoteLocationGuid = person.VotingLocationGuid; // it is already set this way...turn if off person.VotingMethod = null; person.VotingLocationGuid = null; person.RegistrationTime = DateTime.Now; votingMethodRemoved = true; var log = person.RegistrationLog; log.Add(new[] { ShowRegistrationTime(person), "De-selected", ShowTellers(person), hasMultiplePhysicalLocations ? LocationName(UserSession.CurrentLocationGuid) : null, }.JoinedAsString("; ", true)); person.RegistrationLog = log; } else { person.VotingMethod = voteType; oldVoteLocationGuid = person.VotingLocationGuid; person.VotingLocationGuid = UserSession.CurrentLocationGuid; person.RegistrationTime = DateTime.Now; newVoteLocationGuid = person.VotingLocationGuid; var log = person.RegistrationLog; log.Add(new[] { ShowRegistrationTime(person), VotingMethodEnum.TextFor(person.VotingMethod), ShowTellers(person), hasMultiplePhysicalLocations ? LocationName(UserSession.CurrentLocationGuid) : null, }.JoinedAsString("; ", true)); person.RegistrationLog = log; // make number for every method except Registered var needEnvNum = person.EnvNum == null && voteType != VotingMethodEnum.Registered; if (needEnvNum) { person.EnvNum = new ElectionModel().GetNextEnvelopeNumber(); } } personCacher.UpdateItemAndSaveCache(person); UpdateFrontDeskListing(person, votingMethodRemoved); // if (lastRowVersion == 0) // { // lastRowVersion = person.C_RowVersionInt.AsLong() - 1; // } UpdateLocationCounts(newVoteLocationGuid, oldVoteLocationGuid, personCacher); Db.SaveChanges(); return(true.AsJsonResult()); }