/// <summary> /// Constructor. /// </summary> public SubmissionCandidatesViewModel( User user, IList<Commit> commits, Func<Commit, string> commitUrlBuilder, Checkpoint checkpoint, Model.Projects.Submission latestSubmission, ITimeZoneProvider timeZoneProvider) { User = user; Checkpoint = checkpoint; Candidates = commits .OrderByDescending(commit => commit.PushDate) .ThenByDescending(commit => commit.CommitDate) .Select ( commit => new SubmissionCandidateViewModel ( commit, commitUrlBuilder(commit), latestSubmission?.CommitId == commit.Id, commit == commits.First(), timeZoneProvider ) ).ToList(); }
/// <summary> /// Populates a submission branch with a pull request, and returns the /// pull request number. /// </summary> public async Task<int> CreatePullRequestAsync( Commit commit, Checkpoint checkpoint) { var student = GetStudent(commit.Project, commit.User); var orgName = student.Classroom.GitHubOrganization; var repoName = checkpoint.Project.GetStudentRepoName(student); // Get the commits to use in the pull requests. var allCommits = await GetAllCommitsAsync(commit.Project, student); var submissionCommit = allCommits.SingleOrDefault(c => c.Sha == commit.Sha); var startingCommit = allCommits.Where(c => c.Parents.Count == 0) .OrderBy(c => c.Date) .FirstOrDefault(); // Create a submission branch that initially just contains the starting commit. // This will be the destination of our new pull request. var destBranchName = checkpoint.Name; await _repoClient.CreateBranchAsync ( orgName, repoName, destBranchName, startingCommit.Sha ); // Create a temporary source branch that initially contains the student's commit // for the checkpoint, and all previous commits. This is the source of the pull request. var sourceBranchName = $"{checkpoint.Name}Source"; await _repoClient.CreateBranchAsync ( orgName, repoName, sourceBranchName, submissionCommit.Sha ); // Create the pull request. var pullRequestTitle = $"{checkpoint.DisplayName} Submission"; int pullRequestNumber = await _repoClient.CreatePullRequestAsync ( orgName, repoName, pullRequestTitle, sourceBranchName, destBranchName ); // Delete the temporary source branch. await _repoClient.DeleteBranchAsync(orgName, repoName, sourceBranchName); return pullRequestNumber; }
/// <summary> /// Constructor. /// </summary> public GradeSubmissionViewModel( Checkpoint checkpoint, GradeSubmissionResult result, Func<TestResult, string> testUrlBuilder, Func<int, string> buildUrlBuilder, Func<Commit, int, string> pullRequestUrlBuilder, ITimeZoneProvider timeZoneProvider) { LastName = result.LastName; FirstName = result.FirstName; SubmissionId = result.SubmissionId; CommitDate = GetLink ( buildUrlBuilder(result.Build.Id), result.CommitDate.FormatShortDateTime(timeZoneProvider), preventWrapping: true ); SubmissionStatus = GetSubmissionStatus(result.DaysLate); PullRequest = GetLink ( pullRequestUrlBuilder(result.Build.Commit, result.PullRequestNumber.Value), "See Submission", preventWrapping: true ); RequiredTests = result.RequiredTestsPassed ? GetColoredText("green", "Passed", bold: false, preventWrapping: true) : GetColoredText("red", "Failed", bold: true, preventWrapping: true); Feedback = result.Feedback; FeedbackSent = result.FeedbackSent; TestClassResults = TestClassTableEntry.GetTestClassResults ( checkpoint, result.Build, testUrlBuilder ); PastSubmissions = result.PastSubmissions.Select ( pastSubmission => new PastSubmissionTableEntry ( pastSubmission, buildUrlBuilder, pullRequestUrlBuilder, timeZoneProvider ) ).ToList(); }
/// <summary> /// Executes before the action is executed. /// </summary> protected override async Task InitializeAsync() { await base.InitializeAsync(); Checkpoint = await CheckpointService.GetCheckpointAsync ( ClassroomName, ProjectName, CheckpointName ); ViewBag.Checkpoint = Checkpoint; }
/// <summary> /// Constructor. /// </summary> public SubmittedViewModel( Commit commit, string commitUrl, Checkpoint checkpoint, ITimeZoneProvider timeZoneProvider) { User = commit.User; Checkpoint = checkpoint; Submission = new SubmissionCandidateViewModel ( commit, commitUrl, true /*previousSubmission*/, true /*defaultChoice*/, timeZoneProvider ); }
/// <summary> /// Creates a checkpoint. /// </summary> public async Task<bool> CreateCheckpointAsync( string classroomName, string projectName, Checkpoint checkpoint, IModelErrorCollection modelErrors) { var project = await LoadProjectAsync(classroomName, projectName); if (!UpdateCheckpoint(checkpoint, modelErrors)) return false; checkpoint.ProjectId = project.Id; _dbContext.Add(checkpoint); await _dbContext.SaveChangesAsync(); return true; }
/// <summary> /// Downloads submissions for a set of students. /// </summary> public async Task<StudentSubmissions> DownloadSubmissionsAsync( Checkpoint checkpoint, IList<StudentDownloadRequest> studentDownloadRequests) { var orgName = checkpoint.Project.Classroom.GitHubOrganization; var projName = checkpoint.Project.Name; var students = studentDownloadRequests .Select(request => request.Student) .ToList(); var studentsWithSubmissions = new HashSet<ClassroomMembership> ( studentDownloadRequests .Where(request => request.Submitted) .Select(request => request.Student) ); var studentRepos = await _repoMetadataRetriever.GetStudentRepositoriesAsync ( checkpoint.Project, students ); var submissions = await _operationRunner.RunOperationsAsync ( studentRepos.Keys, async student => new StudentSubmission ( student, await _repoClient.GetRepositoryContentsAsync ( orgName, _repoMetadataRetriever.GetRepoName(checkpoint.Project, student), studentsWithSubmissions.Contains(student) ? checkpoint.Name : null, ArchiveStore.FileSystem ) ) ); return new StudentSubmissions(submissions); }
public async Task<IActionResult> Create(Checkpoint checkpoint) { if (ModelState.IsValid) { var succeeded = await CheckpointService.CreateCheckpointAsync ( ClassroomName, ProjectName, checkpoint, ModelErrors ); if (succeeded) { return RedirectToAction("Index"); } } return View("CreateEdit", checkpoint); }
/// <summary> /// Returns a query for all submissions in a given checkpoint. /// </summary> private IQueryable<Submission> GetCheckpointSubmissionsQuery( Checkpoint checkpoint, Section section) { return _dbContext.Submissions .Where ( submission => submission.CheckpointId == checkpoint.Id && submission.Commit.User.ClassroomMemberships.Any ( cm => cm.SectionMemberships.Any ( sm => sm.SectionId == section.Id && sm.Role == SectionRole.Student ) ) ) .Include(submission => submission.Commit.User.ClassroomMemberships) .Include(submission => submission.Commit.Build); }
/// <summary> /// Returns all submissions for the current checkpoint, along with /// submissions for past checkpoints. /// </summary> private async Task<List<Submission>> GetSubmissionsForGrading( Checkpoint checkpoint, Section section, DateTime dueDate) { return await _dbContext.Submissions .Where ( submission => submission.Checkpoint.ProjectId == checkpoint.ProjectId && submission.Checkpoint .SectionDates.First(sd => sd.SectionId == section.Id) .DueDate <= dueDate && submission.Commit.User.ClassroomMemberships.Any ( cm => cm.SectionMemberships.Any ( sm => sm.SectionId == section.Id && sm.Role == SectionRole.Student ) ) ) .Include(submission => submission.Commit.Build.TestResults) .Include(submission => submission.Commit.User.ClassroomMemberships) .Include(submission => submission.Checkpoint.SectionDates) .ToListAsync(); }
/// <summary> /// Updates a checkpoint. /// </summary> public async Task<bool> UpdateCheckpointAsync( string classroomName, string projectName, Checkpoint checkpoint, IModelErrorCollection modelErrors) { var project = await LoadProjectAsync(classroomName, projectName); checkpoint.ProjectId = project.Id; var currentCheckpoint = await _dbContext.Checkpoints .Where(c => c.Id == checkpoint.Id) .SingleOrDefaultAsync(); _dbContext.Entry(currentCheckpoint).State = EntityState.Detached; if (!UpdateCheckpoint(checkpoint, modelErrors)) return false; _dbContext.Update(checkpoint); await _dbContext.SaveChangesAsync(); return true; }
/// <summary> /// Updates a checkpoint. /// </summary> private bool UpdateCheckpoint(Checkpoint checkpoint, IModelErrorCollection modelErrors) { if (checkpoint.SectionDates != null) { var sections = checkpoint.SectionDates.Select(d => d.SectionId).ToList(); if (sections.Distinct().Count() != sections.Count) { modelErrors.AddError("SectionDates", "You may only have one due date per section."); } } if (checkpoint.TestClasses != null) { var testClasses = checkpoint.TestClasses.Select(tc => tc.TestClassId).ToList(); if (testClasses.Distinct().Count() != testClasses.Count) { modelErrors.AddError("TestClasses", "You may only have one entry per test class."); } } if (modelErrors.HasErrors) { return false; } _dbContext.RemoveUnwantedObjects ( _dbContext.CheckpointDates, checkpointDates => checkpointDates.Id, checkpointDates => checkpointDates.CheckpointId == checkpoint.Id, checkpoint.SectionDates ); _dbContext.RemoveUnwantedObjects ( _dbContext.CheckpointTestClasses, testClass => testClass.Id, testClass => testClass.CheckpointId == checkpoint.Id, checkpoint.TestClasses ); return true; }
/// <summary> /// Returns table entries for each test class. /// </summary> public static IList<TestClassTableEntry> GetTestClassResults( Checkpoint checkpoint, Model.Projects.Build build, Func<TestResult, string> testUrlBuilder) { var testClasses = build.Commit.Project.TestClasses; return build.TestResults.GroupBy(result => result.ClassName) .OrderBy ( result => testClasses.FirstOrDefault ( testClass => testClass.ClassName == result.Key )?.Order ?? 0 ) .Where ( group => testClasses.Any ( testClass => testClass.ClassName == group.Key ) && ( checkpoint == null || ( checkpoint.TestClasses?.Any ( testClass => testClass.TestClass.ClassName == group.Key ) ?? false ) ) ) .Select ( group => new TestClassTableEntry ( testClasses.Single(testClass => testClass.ClassName == group.Key), checkpoint?.TestClasses ?.FirstOrDefault(tc => tc.TestClass.ClassName == group.Key) ?.Required ?? false, group.ToList(), testUrlBuilder ) ).ToList(); }