public ActionResult PublishResults(int id) { Election election = db.Elections.Find(id); if (election == null) { return(HttpNotFound()); } bool canDo = ElectionLifecycleInfo.CanPublishResults(election); ViewBag.CanConfirm = canDo; if (Request.HttpMethod.ToUpper() != "POST") { // Just show the template return(View(election)); } if (!canDo) { return(new HttpStatusCodeResult(HttpStatusCode.BadRequest)); } AntiForgery.Validate(); ChangeStateByUserAndRecord(election, ElectionState.ResultsPublished); db.SaveChanges(); BackgroundJob.Enqueue <ElectionStudentSimpleEmailsJobs>( jobs => jobs.SendResultsPublished(election.Id, JobCancellationToken.Null) ); return(RedirectToAction("Details", new { id })); }
public ActionResult RegeneratePositions(int id) { Election election = db.Elections.Find(id); if (election == null) { return(HttpNotFound()); } if (ElectionLifecycleInfo.CanForcePositionGeneration(election)) { using (DbContextTransaction transaction = db.Database.BeginTransaction()) { election.PositionGenerationInProcess = true; db.SaveChanges(); // Undo the PositionGenerationInProcess change if this fails - otherwise the election will be stuck in limbo forever BackgroundJob.Enqueue(() => GeneratePositions.Execute(election.Id, JobCancellationToken.Null)); transaction.Commit(); } } return(RedirectToAction("Details", new { id })); }
public ActionResult Deactivate(int id) { Election election = db.Elections.Find(id); if (election == null) { return(HttpNotFound()); } if (!ElectionLifecycleInfo.CanDeactivate(election)) { // No idea how we got here... History? return(RedirectToAction("Details", new { id })); } if (Request.HttpMethod.ToUpper() != "POST") { // Just show the template return(View(election)); } AntiForgery.Validate(); ChangeStateByUserAndRecord(election, ElectionState.Disabled); db.SaveChanges(); BackgroundJob.Enqueue <SynchronizeDelayedJobsJob>(job => job.Execute(election.Id)); return(RedirectToAction("Details", new { id })); }
public void TestIsInactive() { Assert.True(ElectionLifecycleInfo.IsInactive(new Election())); Assert.True(ElectionLifecycleInfo.IsInactive(new Election { State = ElectionState.Aborted })); Assert.False(ElectionLifecycleInfo.IsInactive(new Election { State = ElectionState.PreNominations })); Assert.False(ElectionLifecycleInfo.IsInactive(new Election { State = ElectionState.Nominations })); Assert.False(ElectionLifecycleInfo.IsInactive(new Election { State = ElectionState.PreVoting })); Assert.False(ElectionLifecycleInfo.IsInactive(new Election { State = ElectionState.Voting })); Assert.False(ElectionLifecycleInfo.IsInactive(new Election { State = ElectionState.Closed })); Assert.False(ElectionLifecycleInfo.IsInactive(new Election { State = ElectionState.ResultsPublished })); }
public void TestIsAfter() { Assert.True(ElectionLifecycleInfo.IsAfter( new Election { State = ElectionState.PreVoting }, ElectionState.Nominations )); Assert.False(ElectionLifecycleInfo.IsAfter( new Election { State = ElectionState.PreNominations }, ElectionState.Nominations )); Assert.False(ElectionLifecycleInfo.IsAfter( new Election { State = ElectionState.Nominations }, ElectionState.Nominations )); Assert.Throws <InactiveElectionNoLifecycleComparisonException>(() => { ElectionLifecycleInfo.IsAfter( new Election { State = ElectionState.Disabled }, ElectionState.Nominations ); }); }
public ActionResult Vote(int id /* Election */) { Election election = db.Elections.Find(id); if (election == null) { return(HttpNotFound()); } string currentUsername = User.Identity.GetUserId(); // ReSharper disable once SimplifyLinqExpression if (!election.EligibilityEntries.Any(entry => entry.Username == currentUsername)) { // This student is not eligible for this election - pretend it doesn't exist return(HttpNotFound()); } if (!ElectionLifecycleInfo.CanVote(election)) { return(new HttpStatusCodeResult(HttpStatusCode.BadRequest)); } return(View(new VotingData( election, new VotingManager().PrepareVotingDataFor(currentUsername, election) ))); }
public void TestBefore() { Assert.Throws <ArgumentOutOfRangeException>(() => ElectionLifecycleInfo.Before(ElectionState.PreNominations)); Assert.AreEqual(ElectionState.PreNominations, ElectionLifecycleInfo.Before(ElectionState.Nominations)); Assert.AreEqual(ElectionState.Nominations, ElectionLifecycleInfo.Before(ElectionState.PreVoting)); Assert.AreEqual(ElectionState.PreVoting, ElectionLifecycleInfo.Before(ElectionState.Voting)); Assert.AreEqual(ElectionState.Voting, ElectionLifecycleInfo.Before(ElectionState.Closed)); Assert.AreEqual(ElectionState.Closed, ElectionLifecycleInfo.Before(ElectionState.ResultsPublished)); Assert.Throws <ArgumentOutOfRangeException>(() => ElectionLifecycleInfo.Before(ElectionState.Disabled)); Assert.Throws <ArgumentOutOfRangeException>(() => ElectionLifecycleInfo.Before(ElectionState.Aborted)); }
public ActionResult Delete(int id) { Election election = db.Elections.Find(id); if (election == null) { return(HttpNotFound()); } bool canDo = ElectionLifecycleInfo.CanDelete(election); ViewBag.CanConfirm = canDo; if (Request.HttpMethod.ToUpper() != "POST") { // Just show the template return(View(election)); } if (!canDo) { // Just reload the page return(RedirectToAction("Delete", new { id })); } AntiForgery.Validate(); using (DbContextTransaction transaction = db.Database.BeginTransaction()) { // Need to cleanup transitions that have explicit references // as otherwise we have cascade cycles and everything spazzes out election.RemoveAutomaticStateTransitions(db); db.SaveChanges(); db.Elections.Remove(election); db.SaveChanges(); transaction.Commit(); } return(RedirectToAction("Current")); }
public ActionResult Nominations(int id) { Election election = db.Elections.Find(id); if (election == null) { return(HttpNotFound()); } string currentUsername = User.Identity.GetUserId(); // ReSharper disable once SimplifyLinqExpression if (!election.EligibilityEntries.Any(entry => entry.Username == currentUsername)) { // This student is not eligible for this election - pretend it doesn't exist return(HttpNotFound()); } List <PositionEligibilityEntry> positionEligibilityEntries = db.PositionEligibilityEntries .Where(entry => entry.Username == currentUsername) .Where(entry => entry.Position.ElectionId == election.Id) .ToList(); NomineeFetcher nomineeFetcher = new NomineeFetcher(new TimetableUserRepository()); NominationsData data = new NominationsData( election, ElectionLifecycleInfo.CanNominate(election), nomineeFetcher.Fetch(positionEligibilityEntries.Select(entry => entry.Position)) ); foreach (PositionEligibilityEntry entry in positionEligibilityEntries) { data.ElgibilePositions.Add(new NominationsData.PositionData( entry.Position, entry.CanNominate, entry.Position.NominationEntries.Any(nomination => nomination.Username == currentUsername) )); } return(View(data)); }
public override bool ShouldBeScheduled() { ElectionState intendedState = IsStart ? ElectionLifecycleInfo.Before(PhaseState) : PhaseState; return(Entity.State == intendedState); }
public ActionResult Edit(int id) { Election election = db.Elections.Find(id); if (election == null) { return(HttpNotFound()); } CouncilElectionData councilData = null; CouncilElectionForm councilForm = null; ElectionForm form; if (election.Type == ElectionType.StudentCouncil) { councilData = db.CouncilElectionData.First(data => data.ElectionId == election.Id); form = councilForm = GenerateFormForCouncil(election, councilData); } else { form = GenerateFormForCourseRep(election); } ModelFieldsAccessibility fieldsInfo = ElectionLifecycleInfo.GetWhatCanBeEditedCouncil(election); ViewData[FormConstants.FieldsInfoKey] = fieldsInfo; ViewBag.Election = election; fieldsInfo.EnsureAllowedDefaultKind( ModelFieldsAccessibility.Kind.Editable, nameof(AdminElectionsController) + "." + nameof(Edit) ); if (Request.HttpMethod.ToUpper() != "POST") { // Just show the template return(View("Edit", form)); } AntiForgery.Validate(); // Update the form based on data that we received // ReSharper disable once ConvertIfStatementToNullCoalescingExpression - we need the compiler to specify different generic arguments if (councilForm != null) { TryUpdateModel(councilForm); } else { TryUpdateModel(form); } // Get the original form so that we use old values for uneditable fields CouncilElectionForm councilOriginalForm = null; ElectionForm originalForm; if (councilForm != null) { originalForm = councilOriginalForm = GenerateFormForCouncil(election, councilData); } else { originalForm = GenerateFormForCourseRep(election); } // Replace all uneditable values with old ones fieldsInfo.ReplaceUneditableWithOldValues(form, originalForm); // As the role IDs are sent from user, we need to make sure that they weren't changed if (councilForm != null && fieldsInfo.CanBeChangedByUser(nameof(CouncilElectionForm.Roles))) { IEnumerable <int?> initialRoleIds = councilOriginalForm.Roles.Select(role => role.Id); IEnumerable <int?> newRoleIds = councilForm.Roles.Select(role => role.Id); if (!initialRoleIds.SequenceEqual(newRoleIds)) { throw new Exception("The IDs of roles were changed by user input"); } } // Validate again (since some rules are relative to other fields and can be affected by operations above) TryValidateModel(form); // Ignore the failures from uneditable fields this.RemoveIgnoredErrors(fieldsInfo); if (!ModelState.IsValid) { // The validation failed so we just display the form again return(View("Edit", form)); } // Record the admin action AdminActionRecord actionRecord = CreateActionRecord(election, AdminActionRecord.RecordType.Edit); actionRecord.SetFormChangeSet(FormChangeSet.Generate(form, originalForm)); db.AdminActionRecords.Add(actionRecord); // Validation passed with the fields that are allowed to change. Persist the changes Mapper.Map(form, election); if (councilData != null) { Mapper.Map(form, councilData); } db.SaveChanges(); BackgroundJob.Enqueue <SynchronizeDelayedJobsJob>(job => job.Execute(election.Id)); AuditLogManager.RecordElectionEdit(User, election); return(RedirectToAction("Details", new { id })); }
public ActionResult Details(int id) { Election election = db.Elections.Find(id); if (election == null) { return(HttpNotFound()); } DetailsData data = new DetailsData { Common = election, NomineeEntries = new NomineeFetcher(new TimetableUserRepository()).Fetch(election.Positions) }; if (election.Type == ElectionType.StudentCouncil) { data.CouncilElectionData = db.CouncilElectionData .First(councilData => councilData.ElectionId == id); } // ReSharper disable once SwitchStatementMissingSomeCases switch (election.State) { case ElectionState.Disabled: { DetailsData.Action action = new DetailsData.Action() { Title = "Activate", Url = Url.Action("Activate", new { id }), CssType = "success" }; SimpleValidationResult validationResult = ElectionLifecycleInfo.CanActivate(election); if (!validationResult.IsNoErrors()) { action.Enabled = false; action.Tooltip = validationResult.Violations[0].HumanError; } else { action.Enabled = true; } data.Actions.Add(action); break; } case ElectionState.PreNominations: { DetailsData.Action action = new DetailsData.Action() { Title = "Deactivate", Url = Url.Action("Deactivate", new { id }), CssType = "warning", Enabled = true, Tooltip = "Go back to deactivated state" }; data.Actions.Add(action); break; } case ElectionState.Closed: { DetailsData.Action action = new DetailsData.Action() { Title = "Publish results", Url = Url.Action("PublishResults", new { id }), CssType = "success", Enabled = true }; data.Actions.Add(action); break; } } if (election.State == ElectionState.Aborted) { data.Actions.Add(new DetailsData.Action() { Title = "Remove from system", Enabled = true, Url = Url.Action("Delete", new { id }), CssType = "danger", }); } else { if (ElectionLifecycleInfo.CanEdit(election)) { data.Actions.Add(new DetailsData.Action() { Title = "Edit", Enabled = true, Url = Url.Action("Edit", new { id }), CssType = "primary" }); } // Should be last data.Actions.Add(new DetailsData.Action() { Title = "Abort", Enabled = true, Url = Url.Action("Abort", new { id }), CssType = "danger" }); } return(View(data)); }
public ActionResult UpdateNominationsStatus(int positionId, bool newStatus) { VotablePosition position = db.VotablePositions.Find(positionId); if (position == null) { return(HttpNotFound()); } Election election = position.Election; string currentUsername = User.Identity.GetUserId(); // ReSharper disable once SimplifyLinqExpression if (!election.EligibilityEntries.Any(entry => entry.Username == currentUsername)) { // This student is not eligible for this election - pretend it doesn't exist return(HttpNotFound()); } PositionEligibilityEntry positionEligibilityEntry = db.PositionEligibilityEntries .FirstOrDefault(entry => entry.PositionId == positionId && entry.Username == currentUsername); if (positionEligibilityEntry == null) { // This student is not eligible for this position - pretend it doesn't exist return(HttpNotFound()); } // At this point we are sure that the position is visible to this student // Now we need to check whether (s)he can change the status (at this time) if (!ElectionLifecycleInfo.CanNominate(election) || !positionEligibilityEntry.CanNominate) { return(new HttpStatusCodeResult(HttpStatusCode.BadRequest)); } // At this point we are sure that the student can change the nomination status for this position // Now we just need to create or delete the record in database (or do nothing if it's already matching) NominationEntry exitingNomination = position.NominationEntries .FirstOrDefault(entry => entry.Username == currentUsername); if (exitingNomination != null) { if (newStatus) { // Do nothing } else { // There is an existing one, remove it db.NominationEntries.Remove(exitingNomination); db.SaveChanges(); } } else { if (newStatus) { // No nomination currently, create one db.NominationEntries.Add(new NominationEntry() { Position = position, Username = currentUsername }); db.SaveChanges(); } else { // Do nothing } } AuditLogManager.RecordNominationUpdate(User, position, newStatus); return(RedirectToAction("Nominations", new { id = election.Id })); }
public override bool ShouldBeScheduled() { return (ElectionLifecycleInfo.AreAlmostOverEmailsEnabled(Entity) && Entity.State == GetPhase().AssociatedState); }