public ActionResult UnitStatistics(UnitStatisticsParams param) { const int usersLimit = 200; var courseId = param.CourseId; var unitId = param.UnitId; var periodStart = param.PeriodStartDate; var periodFinish = param.PeriodFinishDate; var groupsIds = Request.GetMultipleValues("group"); var realPeriodFinish = periodFinish.Add(TimeSpan.FromDays(1)); var course = courseManager.GetCourse(courseId); if (!unitId.HasValue) { return(View("UnitStatisticsList", new UnitStatisticPageModel { Course = course, Units = course.Units, })); } var selectedUnit = course.GetUnitById(unitId.Value); var slides = selectedUnit.Slides; var slidesIds = slides.Select(s => s.Id).ToList(); var quizzes = slides.OfType <QuizSlide>(); var exersices = slides.OfType <ExerciseSlide>(); var groups = groupsRepo.GetAvailableForUserGroups(courseId, User); var filterOptions = ControllerUtils.GetFilterOptionsByGroup <VisitsFilterOptions>(groupsRepo, User, courseId, groupsIds); filterOptions.SlidesIds = slidesIds; filterOptions.PeriodStart = periodStart; filterOptions.PeriodFinish = realPeriodFinish; /* Dictionary<SlideId, List<Visit>> */ var slidesVisits = visitsRepo.GetVisitsInPeriodForEachSlide(filterOptions); var usersVisitedAllSlidesBeforePeriodCount = visitsRepo.GetUsersVisitedAllSlides(filterOptions.WithPeriodStart(DateTime.MinValue).WithPeriodFinish(periodStart)).Count(); var usersVisitedAllSlidesInPeriodCount = visitsRepo.GetUsersVisitedAllSlides(filterOptions).Count(); var usersVisitedAllSlidesBeforePeriodFinishedCount = visitsRepo.GetUsersVisitedAllSlides(filterOptions.WithPeriodStart(DateTime.MinValue)).Count(); var quizzesAverageScore = quizzes.ToDictionary(q => q.Id, q => (int)slidesVisits.GetOrDefault(q.Id, new List <Visit>()) .Where(v => v.IsPassed) .Select(v => 100 * Math.Min(v.Score, q.MaxScore) / (q.MaxScore != 0 ? q.MaxScore : 1)) .DefaultIfEmpty(-1) .Average() ); /* Dictionary<SlideId, count (distinct by user)> */ var exercisesSolutionsCount = userSolutionsRepo.GetAllSubmissions(courseId, slidesIds, periodStart, realPeriodFinish) .GroupBy(s => s.SlideId) .ToDictionary(g => g.Key, g => g.DistinctBy(s => s.UserId).Count()); var exercisesAcceptedSolutionsCount = userSolutionsRepo.GetAllAcceptedSubmissions(courseId, slidesIds, periodStart, realPeriodFinish) .GroupBy(s => s.SlideId) .ToDictionary(g => g.Key, g => g.DistinctBy(s => s.UserId).Count()); var usersIds = visitsRepo.GetVisitsInPeriod(filterOptions).DistinctBy(v => v.UserId).Select(v => v.UserId); /* If we filtered out users from one or several groups show them all */ if (filterOptions.UsersIds != null && !filterOptions.IsUserIdsSupplement) { usersIds = filterOptions.UsersIds; } var visitedUsers = usersIds .Join(db.Users, v => v, u => u.Id, (v, u) => new UnitStatisticUserInfo { UserId = u.Id, UserName = u.UserName, UserVisibleName = (u.LastName + u.FirstName != "" ? u.LastName + " " + u.FirstName : u.UserName).Trim() }) .ToList(); var isMore = visitedUsers.Count > usersLimit; var visitedSlidesCountByUser = visitsRepo.GetVisitsInPeriod(filterOptions) .GroupBy(v => v.UserId) .ToDictionary(g => g.Key, g => g.Count()); var visitedSlidesCountByUserAllTime = visitsRepo.GetVisitsInPeriod(filterOptions.WithPeriodStart(DateTime.MinValue).WithPeriodFinish(DateTime.MaxValue)) .GroupBy(v => v.UserId) .ToDictionary(g => g.Key, g => g.Count()); /* Get `usersLimit` best by slides count and order them by name */ visitedUsers = visitedUsers .OrderByDescending(u => visitedSlidesCountByUserAllTime.GetOrDefault(u.UserId, 0)) .Take(usersLimit) .OrderBy(u => u.UserVisibleName) .ToList(); var visitedUsersIds = visitedUsers.Select(v => v.UserId).ToList(); var additionalScores = additionalScoresRepo .GetAdditionalScoresForUsers(courseId, unitId.Value, visitedUsersIds) .ToDictionary(kv => kv.Key, kv => kv.Value.Score); var usersGroupsIds = groupsRepo.GetUsersGroupsIds(courseId, visitedUsersIds); var enabledAdditionalScoringGroupsForGroups = groupsRepo.GetEnabledAdditionalScoringGroups(courseId) .GroupBy(e => e.GroupId) .ToDictionary(g => g.Key, g => g.Select(e => e.ScoringGroupId).ToList()); var model = new UnitStatisticPageModel { Course = course, Units = course.Units, Unit = selectedUnit, SelectedGroupsIds = groupsIds, Groups = groups, PeriodStart = periodStart, PeriodFinish = periodFinish, Slides = slides, SlidesVisits = slidesVisits, UsersVisitedAllSlidesBeforePeriodCount = usersVisitedAllSlidesBeforePeriodCount, UsersVisitedAllSlidesInPeriodCount = usersVisitedAllSlidesInPeriodCount, UsersVisitedAllSlidesBeforePeriodFinishedCount = usersVisitedAllSlidesBeforePeriodFinishedCount, QuizzesAverageScore = quizzesAverageScore, ExercisesSolutionsCount = exercisesSolutionsCount, ExercisesAcceptedSolutionsCount = exercisesAcceptedSolutionsCount, VisitedUsers = visitedUsers, VisitedUsersIsMore = isMore, VisitedSlidesCountByUser = visitedSlidesCountByUser, VisitedSlidesCountByUserAllTime = visitedSlidesCountByUserAllTime, AdditionalScores = additionalScores, UsersGroupsIds = usersGroupsIds, EnabledAdditionalScoringGroupsForGroups = enabledAdditionalScoringGroupsForGroups, }; return(View(model)); }