コード例 #1
0
 /// <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();
 }
コード例 #2
0
 /// <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();
 }
コード例 #3
0
 /// <summary>
 /// Constructor.
 /// </summary>
 public AssignmentGrade(
     User user,
     Model.Questions.Assignment assignment,
     double score)
 {
     User = user;
     Assignment = assignment;
     Score = score;
 }
コード例 #4
0
 /// <summary>
 /// Constructor.
 /// </summary>
 public AssignmentGrade(
     User user,
     Assignment assignment,
     double oldScore,
     double newScore)
 {
     User = user;
     Assignment = assignment;
     OldScore = oldScore;
     NewScore = newScore;
 }
コード例 #5
0
 /// <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;
 }
コード例 #6
0
		/// <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)
			);
		}
コード例 #7
0
		/// <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;
			}
		}
コード例 #8
0
        /// <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
                    );
        }
コード例 #9
0
        /// <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;
        }
コード例 #10
0
		/// <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;
		}
コード例 #11
0
		/// <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;
		}
コード例 #12
0
		/// <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
			};
		}
コード例 #13
0
		/// <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;
			}
		}
コード例 #14
0
		/// <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;
			}
		}
コード例 #15
0
		/// <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);
		}
コード例 #16
0
		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);
		}
コード例 #17
0
		/// <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();
			}
		}
コード例 #18
0
		/// <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();
		}
コード例 #19
0
		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);
		}
コード例 #20
0
		/// <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
			);
		}
コード例 #21
0
		/// <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.");
		}
コード例 #22
0
		/// <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;
		}
コード例 #23
0
		/// <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."
			);
		}
コード例 #24
0
		/// <summary>
		/// Validates that a user is completely retrieved from the database.
		/// </summary>
		private bool ValidateUser(User user, string userName)
		{
			return user.UserName == userName;
		}
コード例 #25
0
		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);
		}
コード例 #26
0
		/// <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;
		}
コード例 #27
0
		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);
		}
コード例 #28
0
        /// <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;
        }
コード例 #29
0
 /// <summary>
 /// Constructor.
 /// </summary>
 public CreateStudentRepoResult(User student, CreateAndPushResult createAndPushResult)
 {
     Student = student;
     CreateAndPushResult = createAndPushResult;
 }
コード例 #30
0
		/// <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
			);
		}