/// <summary> /// Constructor. /// </summary> public UserSubmissionResults( User user, Section section, IList<Checkpoint> checkpoints, IList<Submission> submissions) { User = user; SubmissionResults = checkpoints .Where ( c => c.SectionDates?.Any(sd => sd.Section == section) ?? false ) .OrderBy ( c => c.SectionDates.Single(sd => sd.Section == section).DueDate ) .Select ( checkpoint => new UserSubmissionResult ( section, checkpoint, submissions .Where(s => s.Checkpoint == checkpoint) .OrderByDescending(s => s.DateSubmitted) .FirstOrDefault() ) ).ToList(); }
/// <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> /// Constructor. /// </summary> public AssignmentGrade( User user, Model.Questions.Assignment assignment, double score) { User = user; Assignment = assignment; Score = score; }
/// <summary> /// Constructor. /// </summary> public AssignmentGrade( User user, Assignment assignment, double oldScore, double newScore) { User = user; Assignment = assignment; OldScore = oldScore; NewScore = newScore; }
/// <summary> /// Constructor. /// </summary> public SectionSubmissionResult( User user, Submission submission) { LastName = user.LastName; FirstName = user.FirstName; UserId = user.Id; CommitDate = submission?.Commit?.PushDate; PullRequestNumber = submission?.PullRequestNumber; BuildId = submission?.Commit?.Build?.Id; Commit = submission?.Commit; }
/// <summary> /// Returns a list of all valid submission commit SHAs for the given user/project. /// </summary> public async Task<ICollection<string>> GetSubmissionCandidatesAsync( Project project, User user) { var allCommits = await GetAllCommitsAsync ( project, GetStudent(project, user) ); return new HashSet<string> ( allCommits .Where(c => c.Parents.Count > 0) .Select(commit => commit.Sha) ); }
/// <summary> /// Returns the given user's role for this section. /// </summary> private static SectionRole GetSectionRole(User user, Section section) { if (user?.SuperUser ?? false) { return SectionRole.Admin; } else { var classroomMembership = user?.ClassroomMemberships ?.SingleOrDefault(m => m.Classroom == section.Classroom); if (classroomMembership?.Role == ClassroomRole.Admin) return SectionRole.Admin; return classroomMembership?.SectionMemberships ?.SingleOrDefault(m => m.Section == section) ?.Role ?? SectionRole.None; } }
/// <summary> /// Constructor. /// </summary> public GradeSubmissionResult( User user, Section section, Submission currentSubmission, IList<Submission> pastSubmissions) { LastName = user.LastName; FirstName = user.FirstName; SubmissionId = currentSubmission.Id; CommitDate = currentSubmission.Commit.PushDate; DaysLate = currentSubmission.GetDaysLate(section); PullRequestNumber = currentSubmission.PullRequestNumber; Feedback = currentSubmission.Feedback; FeedbackSent = currentSubmission.FeedbackSent; Build = currentSubmission.Commit.Build; PastSubmissions = pastSubmissions .Select(ps => new PastSubmissionResult(ps, section)) .ToList(); RequiredTestsPassed = currentSubmission.Commit.Build.Status == BuildStatus.Completed && currentSubmission.Commit.Build.TestResults .Select ( tr => new { Required = currentSubmission.Checkpoint .TestClasses .FirstOrDefault ( tc => tc.TestClass.ClassName == tr.ClassName )?.Required ?? false, Passed = tr.Succeeded } ) .All ( tr => !tr.Required || tr.Passed ); }
/// <summary> /// Adds a classroom admin. /// </summary> public TestDatabaseBuilder AddAdmin( string userName, string lastName, string firstName, string classroomName, bool superUser, string gitHubLogin = null, bool inGitHubOrg = false) { var classroom = _buildContext.Classrooms .Single(c => c.Name == classroomName); var user = new User() { UniqueId = $"{userName}Id", UserName = userName, FirstName = firstName, LastName = lastName, SuperUser = superUser, GitHubLogin = gitHubLogin, ClassroomMemberships = new List<ClassroomMembership>() { new ClassroomMembership() { ClassroomId = classroom.Id, Role = ClassroomRole.Admin, InGitHubOrganization = inGitHubOrg } } }; _buildContext.Users.Add(user); _buildContext.SaveChanges(); return this; }
/// <summary> /// Ensures a section membership exists for the given user and role. /// The caller is responsible for saving changes. /// </summary> private async Task<SectionMembership> EnsureSectionMembershipAsync( User user, Section section, SectionRole role) { var classroomMembership = await EnsureClassroomMembershipAsync( user, section.Classroom, ClassroomRole.General); if (classroomMembership.SectionMemberships == null) { classroomMembership.SectionMemberships = new List<SectionMembership>(); } var sectionMembership = classroomMembership.SectionMemberships .SingleOrDefault(m => m.SectionId == section.Id); if (sectionMembership == null) { sectionMembership = new SectionMembership() { ClassroomMembershipId = classroomMembership.Id, ClassroomMembership = classroomMembership, SectionId = section.Id, Section = section, Role = role }; classroomMembership.SectionMemberships.Add(sectionMembership); } else if (role > sectionMembership.Role) { sectionMembership.Role = role; } return sectionMembership; }
/// <summary> /// Ensures a classroom membership exists for the given user and role. /// The caller is responsible for saving changes. /// </summary> private async Task<ClassroomMembership> EnsureClassroomMembershipAsync( User user, Classroom classroom, ClassroomRole role) { var classroomMembership = user?.ClassroomMemberships ?.SingleOrDefault(m => m.ClassroomId == classroom.Id); if (user.ClassroomMemberships == null) { user.ClassroomMemberships = new List<ClassroomMembership>(); } if (classroomMembership == null) { classroomMembership = new ClassroomMembership() { ClassroomId = classroom.Id, Classroom = classroom, InGitHubOrganization = false, GitHubTeam = await GetNewGitHubTeamNameAsync(classroom, user), Role = role }; user.ClassroomMemberships.Add(classroomMembership); } else if (role > classroomMembership.Role) { classroomMembership.Role = role; } return classroomMembership; }
/// <summary> /// Returns a commit. /// </summary> private Commit GetCommit(User user, Project project) { return new Commit() { Sha = "Commit3", User = user, UserId = user.Id, Project = project, ProjectId = project.Id }; }
/// <summary> /// Returns whether or not the given user is in the classroom's GitHub organization. /// </summary> private async Task<bool> EnsureGitHubMembershipUpdated( User user, ClassroomMembership membership) { if (membership.InGitHubOrganization) { return true; } await _dbContext.Entry(membership) .Reference(cm => cm.Classroom) .LoadAsync(); var memberInOrganization = await _gitHubOrgClient.CheckMemberAsync ( membership.Classroom.GitHubOrganization, user.GitHubLogin ); if (memberInOrganization) { membership.InGitHubOrganization = true; _dbContext.ClassroomMemberships.Update(membership); return true; } else { return false; } }
/// <summary> /// Returns the given user's classroom role for this classroom. /// </summary> private ClassroomRole GetClassroomRole(User user, Classroom classroom) { if (user?.SuperUser ?? false) { return ClassroomRole.Admin; } else { return ClassroomMembership?.Role ?? ClassroomRole.None; } }
/// <summary> /// Returns the given user's classroom membership for this classroom. /// </summary> private static ClassroomMembership GetClassroomMembership( User user, Classroom classroom) { return user?.ClassroomMemberships ?.SingleOrDefault(m => m.Classroom == classroom); }
public async Task IsServiceActivatedAsync_SignedInAsRegisteredUser_ReturnsTrue() { var identityProvider = new Mock<IIdentityProvider>(); identityProvider .Setup(ip => ip.CurrentIdentity) .Returns(GetIdentity()); var user = new User(); var userService = new Mock<IUserService>(); userService .Setup(us => us.GetAndUpdateCurrentUserAsync()) .ReturnsAsync(new User()); var userProvider = new UserProvider(userService.Object, identityProvider.Object); var result = await userProvider.IsServiceActivatedAsync(); Assert.True(result); userService.Verify(us => us.AnyRegisteredUsersAsync(), Times.Never); }
/// <summary> /// Updates the status of all GitHub memberships for the user. /// </summary> private async Task EnsureGitHubMembershipsUpdated(User user) { if (user.GitHubLogin == null || user.ClassroomMemberships == null) return; bool statusUpdated = false; foreach (var membership in user.ClassroomMemberships) { statusUpdated = await EnsureGitHubMembershipUpdated(user, membership) || statusUpdated; } if (statusUpdated) { await _dbContext.SaveChangesAsync(); } }
/// <summary> /// Returns all checkpoints for a given user, grouped by checkpoint. /// </summary> private static List<IGrouping<Checkpoint, Submission>> GroupSubmissions( Section section, List<Submission> submissions, User student) { return submissions .Where(s => s.Commit.UserId == student.Id) .OrderByDescending(s => s.DateSubmitted) .GroupBy(s => s.Checkpoint) .OrderByDescending ( group => group.Key .SectionDates .Single(sd => sd.SectionId == section.Id) .DueDate ).ToList(); }
public async Task GetCurrentUserAsync_Registered_ReturnsUser() { var identityProvider = new Mock<IIdentityProvider>(); identityProvider .Setup(ip => ip.CurrentIdentity) .Returns(GetIdentity()); var user = new User(); var userService = new Mock<IUserService>(); userService .Setup(us => us.GetAndUpdateCurrentUserAsync()) .ReturnsAsync(user); var userProvider = new UserProvider(userService.Object, identityProvider.Object); var currentUser = await userProvider.GetCurrentUserAsync(); Assert.Equal(user, currentUser); }
/// <summary> /// Returns the student classroom membership for the user. /// </summary> private ClassroomMembership GetStudent(Project project, User user) { return user.ClassroomMemberships.Single ( cm => cm.Classroom == project.Classroom ); }
/// <summary> /// Returns a GitHub repository suffix that is unique class-wide. /// </summary> private async Task<string> GetNewGitHubTeamNameAsync(Classroom classroom, User user) { var proposedSuffix = new string ( $"{user.LastName}{user.FirstName}" .Where(c => char.IsLetter(c)) .ToArray() ); var membersWithSuffix = await _dbContext.ClassroomMemberships .Where(classMember => classMember.ClassroomId == classroom.Id) .Where(classMember => classMember.GitHubTeam.StartsWith(proposedSuffix)) .ToListAsync(); if (membersWithSuffix.Count == 0) return proposedSuffix; const int maxMembersWithSuffix= 100; for (int i = 2; i < maxMembersWithSuffix; i++) { var newProposedSuffix = $"{proposedSuffix}{i}"; var existingUser = membersWithSuffix.SingleOrDefault ( classMember => classMember.GitHubTeam == newProposedSuffix ); if (existingUser == null) { return newProposedSuffix; } } throw new InvalidOperationException("Unable to find GitHub repository suffix for user."); }
/// <summary> /// Ensures that the user provider is initialized. /// </summary> private async Task EnsureInitializedAsync() { if (_initialized) { return; } if (_identityProvider.CurrentIdentity != null) { _currentUser = await _userService.GetAndUpdateCurrentUserAsync(); } _anyRegisteredUsers = _currentUser != null || await _userService.AnyRegisteredUsersAsync(); _initialized = true; }
/// <summary> /// Sends the user an invitation mail. /// </summary> private async Task SendUserInvitationMailAsync(User user, string confirmUrlBuilder) { var confirmUrl = confirmUrlBuilder.Replace("REPLACE", user.EmailConfirmationCode); await _emailProvider.SendMessageAsync ( user.EmailAddress, "*****@*****.**", "CS Classroom", "Confirm your e-mail address with CS Classroom", $"Hi {user.FirstName},<br><br>Thank you for registering for CS Classroom. Please <a href=\"{confirmUrl}\">click here</a> to confirm your e-mail address." ); }
/// <summary> /// Validates that a user is completely retrieved from the database. /// </summary> private bool ValidateUser(User user, string userName) { return user.UserName == userName; }
public async Task GetCurrentUserAsync_Unregistered_ReturnsNull() { var identityProvider = new Mock<IIdentityProvider>(); var user = new User(); var userService = new Mock<IUserService>(); userService .Setup(us => us.GetAndUpdateCurrentUserAsync()) .ReturnsAsync(null); var userProvider = new UserProvider(userService.Object, identityProvider.Object); var currentUser = await userProvider.GetCurrentUserAsync(); Assert.Null(currentUser); }
/// <summary> /// Registers a user. /// </summary> public async Task<RegisterNewUserResult> RegisterNewStudentAsync( string classroomName, string sectionName, StudentRegistration registration, string confirmationUrlBuilder, IModelErrorCollection errors) { var section = _dbContext.Sections .Where(s => s.Classroom.Name == classroomName) .Include(s => s.Classroom) .SingleOrDefault(s => s.Name == sectionName); if (section == null) { return RegisterNewUserResult.SectionNotFound; } if (!section.AllowNewRegistrations) { return RegisterNewUserResult.SectionNotOpen; } var user = await GetAndUpdateCurrentUserAsync(); if (user != null) { return RegisterNewUserResult.AlreadyRegistered; } if (!await _gitHubUserClient.DoesUserExistAsync(registration.GitHubLogin)) { errors.AddError("GitHubLogin", "The GitHub username does not exist."); return RegisterNewUserResult.Failed; } user = new User() { UniqueId = _identityProvider.CurrentIdentity.UniqueId, UserName = _identityProvider.CurrentIdentity.UserName, FirstName = registration.FirstName, LastName = _identityProvider.CurrentIdentity.LastName, EmailAddress = registration.EmailAddress, EmailConfirmationCode = GenerateEmailConfirmationCode(), EmailAddressConfirmed = false, GitHubLogin = registration.GitHubLogin, SuperUser = false }; var membership = await EnsureSectionMembershipAsync(user, section, SectionRole.Student); await EnsureUserInGithubOrgAsync(user, membership.ClassroomMembership); await SendUserInvitationMailAsync(user, confirmationUrlBuilder); _dbContext.Users.Add(user); await _dbContext.SaveChangesAsync(); return RegisterNewUserResult.Success; }
public async Task IsServiceActivatedAsync_NotSignedInAndRegisteredUsers_ReturnsTrue() { var identityProvider = new Mock<IIdentityProvider>(); var user = new User(); var userService = new Mock<IUserService>(); userService .Setup(us => us.GetAndUpdateCurrentUserAsync()) .ReturnsAsync(null); userService .Setup(us => us.AnyRegisteredUsersAsync()) .ReturnsAsync(true); var userProvider = new UserProvider(userService.Object, identityProvider.Object); var result = await userProvider.IsServiceActivatedAsync(); Assert.True(result); }
/// <summary> /// Adds a question category to the database. /// </summary> public TestDatabaseBuilder AddStudent( string userName, string lastName, string firstName, string classroomName, string sectionName, string gitHubLogin = null, bool inGitHubOrg = false) { var section = _buildContext.Sections .Where(s => s.Classroom.Name == classroomName) .Single(s => s.Name == sectionName); var user = new User() { UniqueId = $"{userName}Id", UserName = userName, FirstName = firstName, LastName = lastName, EmailAddress = $"{userName}Email", EmailConfirmationCode = $"{userName}EmailConfirmationCode", GitHubLogin = gitHubLogin, ClassroomMemberships = new List<ClassroomMembership>() { new ClassroomMembership() { ClassroomId = section.ClassroomId, GitHubTeam = $"{lastName}{firstName}", InGitHubOrganization = inGitHubOrg, Role = ClassroomRole.General, SectionMemberships = new List<SectionMembership>() { new SectionMembership() { SectionId = section.Id, Role = SectionRole.Student } } } } }; _buildContext.Users.Add(user); _buildContext.SaveChanges(); return this; }
/// <summary> /// Constructor. /// </summary> public CreateStudentRepoResult(User student, CreateAndPushResult createAndPushResult) { Student = student; CreateAndPushResult = createAndPushResult; }
/// <summary> /// Invites the user to a new GitHub team. /// </summary> private async Task EnsureUserInGithubOrgAsync(User user, ClassroomMembership membership) { if (membership.InGitHubOrganization) return; var team = await _gitHubTeamClient.CreateTeamAsync ( membership.Classroom.GitHubOrganization, membership.GitHubTeam ); await _gitHubTeamClient.InviteUserToTeamAsync ( membership.Classroom.GitHubOrganization, team, user.GitHubLogin ); }