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.GetMultipleValuesFromQueryString("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.FindUnitById(unitId.Value); if (selectedUnit == null) { return(HttpNotFound()); } 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) .Select(g => new { g.Key, Count = g.Select(s => s.UserId).Distinct().Count() }) .ToDictionary(g => g.Key, g => g.Count); var exercisesAcceptedSolutionsCount = userSolutionsRepo.GetAllAcceptedSubmissions(courseId, slidesIds, periodStart, realPeriodFinish) .GroupBy(s => s.SlideId) .Select(g => new { g.Key, Count = g.Select(s => s.UserId).Distinct().Count() }) .ToDictionary(g => g.Key, g => g.Count); var usersIds = visitsRepo.GetVisitsInPeriod(filterOptions).Select(v => v.UserId).Distinct().AsEnumerable(); /* If we filtered out users from one or several groups show them all */ if (filterOptions.UserIds != null && !filterOptions.IsUserIdsSupplement) { usersIds = filterOptions.UserIds; } var visitedUsers = usersRepo.GetUsersByIds(usersIds).Select(u => new UnitStatisticUserInfo(u)).ToList(); var isMore = visitedUsers.Count > usersLimit; var visitedSlidesCountByUser = visitsRepo.GetVisitsInPeriod(filterOptions) .GroupBy(v => v.UserId) .Select(g => new { g.Key, Count = g.Count() }) .ToDictionary(g => g.Key, g => g.Count); var visitedSlidesCountByUserAllTime = visitsRepo.GetVisitsInPeriod(filterOptions.WithPeriodStart(DateTime.MinValue).WithPeriodFinish(DateTime.MaxValue)) .GroupBy(v => v.UserId) .Select(g => new { g.Key, Count = g.Count() }) .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.UserLastName) .ThenBy(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)); }