示例#1
0
        private static IEnumerable <Vertical> QuizToVerticals(string courseId, QuizSlide slide, string slideUrl, string ltiId)
        {
            var ltiComponent =
                new LtiComponent(slide.Title, slide.Guid + "-quiz", string.Format(slideUrl, courseId, slide.Index), ltiId, true, slide.MaxScore, false);

            yield return(new Vertical(slide.Guid, slide.Title, new Component[] { ltiComponent }));
        }
示例#2
0
        public ActionResult Quiz(QuizSlide slide, string courseId, string userId, bool isGuest, bool isLti = false)
        {
            if (isGuest)
            {
                return(PartialView(GuestQuiz(slide, courseId)));
            }
            var slideId          = slide.Id;
            var maxDropCount     = GetMaxDropCount(slide);
            var state            = GetQuizState(courseId, userId, slideId, maxDropCount);
            var resultsForQuizes = GetResultForQuizes(courseId, userId, slideId, state.Item1);
            var model            = new QuizModel
            {
                CourseId         = courseId,
                Slide            = slide,
                QuizState        = state.Item1,
                TryNumber        = state.Item2,
                MaxDropCount     = maxDropCount,
                ResultsForQuizes = resultsForQuizes,
                AnswersToQuizes  =
                    userQuizzesRepo.GetAnswersForShowOnSlide(courseId, slide,
                                                             userId),
                IsLti = isLti
            };

            if (model.QuizState != QuizState.NotPassed && model.RightAnswers == model.QuestionsCount)
            {
                model.QuizState = QuizState.Total;
            }

            return(PartialView(model));
        }
示例#3
0
        private static IEnumerable <QuizAnswerInfo> GetUserQuizAnswers(QuizSlide slide, IEnumerable <UserQuiz> userQuizzes)
        {
            var answers = userQuizzes.GroupBy(q => q.QuizId).ToDictionary(g => g.Key, g => g.ToList());

            foreach (var block in slide.Blocks.OfType <AbstractQuestionBlock>())
            {
                if (block is FillInBlock)
                {
                    yield return(GetFillInBlockAnswerInfo(answers, block.Id, block.QuestionIndex));
                }
                else if (block is ChoiceBlock)
                {
                    yield return(GetChoiceBlockAnswerInfo(answers, (ChoiceBlock)block, block.QuestionIndex));
                }
                else if (block is IsTrueBlock)
                {
                    yield return(GetIsTrueBlockAnswerInfo(answers, block.Id, block.QuestionIndex));
                }
                else if (block is OrderingBlock)
                {
                    yield return(GetOrderingBlockAnswerInfo(answers, (OrderingBlock)block, block.QuestionIndex));
                }
                else if (block is MatchingBlock)
                {
                    yield return(GetMatchingBlockAnswerInfo(answers, (MatchingBlock)block, block.QuestionIndex));
                }
            }
        }
示例#4
0
        private IEnumerable <QuizInfoForDb> CreateQuizInfo(QuizSlide slide, IGrouping <string, QuizAnswer> answer)
        {
            var block = slide.GetBlockById(answer.Key);

            if (block is FillInBlock)
            {
                return(CreateQuizInfoForDb(block as FillInBlock, answer.First().Text));
            }
            if (block is ChoiceBlock)
            {
                return(CreateQuizInfoForDb(block as ChoiceBlock, answer));
            }
            if (block is OrderingBlock)
            {
                return(CreateQuizInfoForDb(block as OrderingBlock, answer));
            }
            if (block is MatchingBlock)
            {
                return(CreateQuizInfoForDb(block as MatchingBlock, answer));
            }
            if (block is IsTrueBlock)
            {
                return(CreateQuizInfoForDb(block as IsTrueBlock, answer));
            }
            return(null);
        }
示例#5
0
        private static IEnumerable <Vertical> QuizToVerticals(string courseId, QuizSlide slide, string slideUrl, string ltiId)
        {
            var ltiComponent =
                new LtiComponent(slide.Title, slide.NormalizedGuid + "-quiz", string.Format(slideUrl, courseId, slide.Id), ltiId, true, slide.MaxScore, false);

            yield return(new Vertical(slide.NormalizedGuid, slide.Title, new Component[] { ltiComponent }, EdxScoringGroupsHack.ToEdxName(slide.ScoringGroup), slide.MaxScore));
        }
示例#6
0
        public ActionResult Quiz(QuizSlide slide, string courseId, string userId, bool isGuest, bool isLti = false, ManualQuizChecking manualQuizCheckQueueItem = null)
        {
            if (isGuest)
            {
                return(PartialView(GuestQuiz(slide, courseId)));
            }
            var slideId          = slide.Id;
            var maxDropCount     = GetMaxDropCount(slide);
            var state            = GetQuizState(courseId, userId, slideId, maxDropCount);
            var quizState        = state.Item1;
            var tryNumber        = state.Item2;
            var resultsForQuizes = GetResultForQuizes(courseId, userId, slideId, state.Item1);

            log.Info($"Создаю тест для пользователя {userId} в слайде {courseId}:{slide.Id}, isLti = {isLti}");

            var quizVersion = quizzesRepo.GetLastQuizVersion(courseId, slideId);

            if (quizState != QuizState.NotPassed)
            {
                quizVersion = userQuizzesRepo.FindQuizVersionFromUsersAnswer(courseId, slideId, userId);
            }

            /* If we haven't quiz version in database, create it */
            if (quizVersion == null)
            {
                quizVersion = quizzesRepo.AddQuizVersionIfNeeded(courseId, slide);
            }

            /* Restore quiz slide from version stored in the database */
            var quiz = quizVersion.RestoredQuiz;

            slide = new QuizSlide(slide.Info, quiz);

            var userAnswers     = userQuizzesRepo.GetAnswersForShowOnSlide(courseId, slide, userId);
            var canUserFillQuiz = CanUserFillQuiz(quizState);

            var model = new QuizModel
            {
                CourseId                 = courseId,
                Slide                    = slide,
                QuizState                = quizState,
                TryNumber                = tryNumber,
                MaxDropCount             = maxDropCount,
                ResultsForQuizes         = resultsForQuizes,
                AnswersToQuizes          = userAnswers,
                IsLti                    = isLti,
                ManualQuizCheckQueueItem = manualQuizCheckQueueItem,
                CanUserFillQuiz          = canUserFillQuiz,
                GroupsIds                = Request.GetMultipleValues("group"),
            };

            if (model.QuizState == QuizState.Subtotal && model.Score == quiz.MaxScore)
            {
                model.QuizState = QuizState.Total;
            }

            return(PartialView(model));
        }
示例#7
0
        public ActionResult Analytics(string courseId, Guid slideId, DateTime periodStart)
        {
            var course    = courseManager.GetCourse(courseId);
            var unit      = course.FindUnitBySlideId(slideId);
            var quizSlide = (QuizSlide)course.GetSlideById(slideId);

            var quizVersions = quizzesRepo.GetQuizVersions(courseId, quizSlide.Id).ToList();
            var dict         = new SortedDictionary <string, List <QuizAnswerInfo> >();
            var passes       = db.UserQuizzes
                               .Where(q => quizSlide.Id == q.SlideId && !q.isDropped && periodStart <= q.Timestamp)
                               .GroupBy(q => q.UserId)
                               .Join(db.Users, g => g.Key, user => user.Id, (g, user) => new { UserId = user.Id, user.UserName, UserQuizzes = g.ToList(), QuizVersion = g.FirstOrDefault().QuizVersion })
                               .ToList();

            foreach (var pass in passes)
            {
                var slide = quizSlide;
                if (pass.QuizVersion != null)
                {
                    slide = new QuizSlide(quizSlide.Info, pass.QuizVersion.GetRestoredQuiz(course, unit));
                }
                dict[pass.UserName] = GetUserQuizAnswers(slide, pass.UserQuizzes).ToList();
            }

            var userIds           = passes.Select(p => p.UserId).Distinct().ToList();
            var userNameById      = passes.ToDictionary(p => p.UserId, p => p.UserName);
            var groups            = groupsRepo.GetUsersGroupsNamesAsStrings(courseId, userIds, User).ToDictionary(kv => userNameById[kv.Key], kv => kv.Value);
            var rightAnswersCount = dict.Values
                                    .SelectMany(list => list
                                                .Where(info => info.Score == info.MaxScore))
                                    .GroupBy(arg => arg.Id)
                                    .ToDictionary(grouping => grouping.Key, grouping => grouping.Count());

            var usersByQuizVersion       = passes.GroupBy(p => p.QuizVersion?.Id).ToDictionary(g => g.Key, g => g.Select(u => u.UserName).ToList());
            var usersWaitsForManualCheck = slideCheckingsRepo.GetManualCheckingQueue <ManualQuizChecking>(
                new ManualCheckingQueueFilterOptions {
                CourseId = courseId, SlidesIds = new List <Guid> {
                    quizSlide.Id
                }
            }
                ).ToList().Select(i => i.User.UserName).ToImmutableHashSet();

            return(PartialView(new QuizAnalyticsModel
            {
                Course = course,
                Unit = course.FindUnitBySlideId(quizSlide.Id),
                SlideId = quizSlide.Id,

                UserAnswers = dict,
                QuizVersions = quizVersions,
                UsersByQuizVersion = usersByQuizVersion,
                RightAnswersCount = rightAnswersCount,
                GroupByUser = groups,
                UsersWaitsForManualCheck = usersWaitsForManualCheck,
            }));
        }
示例#8
0
        private static int GetMaxDropCount(QuizSlide quizSlide)
        {
            if (quizSlide == null)
            {
                return(MAX_DROPS_COUNT);
            }
            var maxDropCount = quizSlide.MaxDropCount;

            return(maxDropCount == 0 ? MAX_DROPS_COUNT : maxDropCount);
        }
示例#9
0
 private QuizModel GuestQuiz(QuizSlide slide, string courseId)
 {
     return(new QuizModel
     {
         CourseId = courseId,
         Slide = slide,
         IsGuest = true,
         QuizState = QuizState.NotPassed
     });
 }
示例#10
0
 private QuizModel GuestQuiz(Course course, QuizSlide slide)
 {
     return(new QuizModel
     {
         Course = course,
         Slide = slide,
         IsGuest = true,
         QuizState = new QuizState(QuizStatus.ReadyToSend, 0, 0, slide.MaxScore),
     });
 }
示例#11
0
        private byte[] ServeAddQuiz(HttpRequestEventArgs context, string path)
        {
            var quiz = new QuizSlide
            {
                Id    = Guid.NewGuid(),
                Title = "Новый quiz"
            };

            return(AddNewSlide(context, path, quiz));
        }
示例#12
0
 private QuizModel GuestQuiz(Course course, QuizSlide slide)
 {
     return(new QuizModel
     {
         Course = course,
         Slide = slide,
         IsGuest = true,
         QuizState = QuizState.NotPassed,
     });
 }
示例#13
0
        private int GetMaxTriesCount(string courseId, QuizSlide quizSlide)
        {
            if (User.HasAccessFor(courseId, CourseRole.Tester))
            {
                return(InfinityTriesCount);
            }

            if (quizSlide == null)
            {
                return(defaultMaxTriesCount);
            }

            return(quizSlide.MaxTriesCount);
        }
示例#14
0
        public QuizVersion AddQuizVersionIfNeeded(string courseId, QuizSlide slide)
        {
            var slideId = slide.Id;

            var quizXml         = slide.QuizNormalizedXml;
            var lastQuizVersion = GetLastQuizVersion(courseId, slideId);
            var newQuizVersion  = new QuizVersion
            {
                CourseId      = courseId,
                SlideId       = slideId,
                LoadingTime   = DateTime.Now,
                NormalizedXml = quizXml
            };

            if (lastQuizVersion == null || lastQuizVersion.NormalizedXml != newQuizVersion.NormalizedXml)
            {
                db.QuizVersions.Add(newQuizVersion);
                db.SaveChanges();

                return(newQuizVersion);
            }

            return(lastQuizVersion);
        }
示例#15
0
        public Dictionary <string, List <UserQuizAnswer> > GetAnswersForShowingOnSlide(string courseId, QuizSlide slide, string userId, UserQuizSubmission submission = null)
        {
            if (slide == null)
            {
                return(null);
            }

            if (submission == null)
            {
                submission = FindLastUserSubmission(courseId, slide.Id, userId);
            }

            var answer = new Dictionary <string, List <UserQuizAnswer> >();

            foreach (var block in slide.Blocks.OfType <AbstractQuestionBlock>())
            {
                if (submission != null)
                {
                    var ans = db.UserQuizAnswers
                              .Where(q => q.SubmissionId == submission.Id && q.BlockId == block.Id)
                              .OrderBy(x => x.Id)
                              .ToList();

                    answer[block.Id] = ans;
                }
                else
                {
                    answer[block.Id] = new List <UserQuizAnswer>();
                }
            }

            return(answer);
        }
示例#16
0
        public Dictionary <string, List <UserQuizAnswer> > GetAnswersForShowingOnSlide(string courseId, QuizSlide slide, string userId, UserQuizSubmission submission = null)
        {
            if (slide == null)
            {
                return(null);
            }

            if (submission == null)
            {
                submission = FindLastUserSubmission(courseId, slide.Id, userId);
            }

            var answer = new Dictionary <string, List <UserQuizAnswer> >();

            if (submission == null)
            {
                foreach (var block in slide.Blocks.OfType <AbstractQuestionBlock>())
                {
                    answer[block.Id] = new List <UserQuizAnswer>();
                }
                return(answer);
            }

            var blocks2Answers = db.UserQuizAnswers
                                 .Where(q => q.SubmissionId == submission.Id)
                                 .OrderBy(x => x.Id)
                                 .AsEnumerable()
                                 .GroupBy(a => a.BlockId)
                                 .ToDictionary(g => g.Key, g => g.ToList());

            foreach (var block in slide.Blocks.OfType <AbstractQuestionBlock>())
            {
                answer[block.Id] = blocks2Answers.ContainsKey(block.Id)
                                        ? blocks2Answers[block.Id]
                                        : new List <UserQuizAnswer>();
            }

            return(answer);
        }
示例#17
0
        public ActionResult Quiz(QuizSlide slide, string courseId, string userId, bool isGuest, bool isLti = false, ManualQuizChecking manualQuizCheckQueueItem = null, int?send = null)
        {
            metricSender.SendCount("quiz.show");
            if (isLti)
            {
                metricSender.SendCount("quiz.show.lti");
            }
            metricSender.SendCount($"quiz.show.{courseId}");
            metricSender.SendCount($"quiz.show.{courseId}.{slide.Id}");

            var course = courseManager.FindCourse(courseId);

            if (course == null)
            {
                return(HttpNotFound());
            }

            if (isGuest)
            {
                metricSender.SendCount("quiz.show.to.guest");
                return(PartialView(GuestQuiz(course, slide)));
            }
            var slideId          = slide.Id;
            var maxTriesCount    = GetMaxTriesCount(courseId, slide);
            var state            = GetQuizState(courseId, userId, slideId);
            var quizState        = state.Item1;
            var tryNumber        = state.Item2;
            var resultsForQuizes = GetResultForQuizes(courseId, userId, slideId, state.Item1);

            log.Info($"Создаю тест для пользователя {userId} в слайде {courseId}:{slide.Id}, isLti = {isLti}");

            var quizVersion = quizzesRepo.GetLastQuizVersion(courseId, slideId);

            if (quizState != QuizState.NotPassed)
            {
                quizVersion = userQuizzesRepo.FindQuizVersionFromUsersAnswer(courseId, slideId, userId);
            }

            /* If we haven't quiz version in database, create it */
            if (quizVersion == null)
            {
                quizVersion = quizzesRepo.AddQuizVersionIfNeeded(courseId, slide);
            }

            /* Restore quiz slide from version stored in the database */
            var quiz = quizVersion.GetRestoredQuiz(course, course.FindUnitBySlideId(slide.Id));

            slide = new QuizSlide(slide.Info, quiz);

            if (quizState == QuizState.Subtotal)
            {
                var score = resultsForQuizes?.AsEnumerable().Sum(res => res.Value) ?? 0;
                /* QuizState.Subtotal is partially obsolete. If user fully solved quiz, then show answers. Else show empty quiz for the new try... */
                if (score == quiz.MaxScore)
                {
                    quizState = QuizState.Total;
                }
                /* ... and show last try's answers only if argument `send` has been passed in query */
                else if (!send.HasValue)
                {
                    quizState = QuizState.NotPassed;
                    /* ... if we will show answers from last try then drop quiz */
                    userQuizzesRepo.DropQuiz(courseId, userId, slideId);
                }
            }

            var userAnswers     = userQuizzesRepo.GetAnswersForShowOnSlide(courseId, slide, userId);
            var canUserFillQuiz = CanUserFillQuiz(quizState);

            var questionAnswersFrequency = new DefaultDictionary <string, DefaultDictionary <string, int> >();

            if (User.HasAccessFor(courseId, CourseRole.CourseAdmin))
            {
                questionAnswersFrequency = quiz.Blocks.OfType <ChoiceBlock>().ToDictionary(
                    block => block.Id,
                    block => userQuizzesRepo.GetAnswersFrequencyForChoiceBlock(courseId, slide.Id, block.Id).ToDefaultDictionary()
                    ).ToDefaultDictionary();
            }

            var model = new QuizModel
            {
                Course                   = course,
                Slide                    = slide,
                QuizState                = quizState,
                TryNumber                = tryNumber,
                MaxTriesCount            = maxTriesCount,
                ResultsForQuizes         = resultsForQuizes,
                AnswersToQuizes          = userAnswers,
                IsLti                    = isLti,
                ManualQuizCheckQueueItem = manualQuizCheckQueueItem,
                CanUserFillQuiz          = canUserFillQuiz,
                GroupsIds                = Request.GetMultipleValuesFromQueryString("group"),
                QuestionAnswersFrequency = questionAnswersFrequency,
            };

            return(PartialView(model));
        }
示例#18
0
        private int GetManualCheckingsCountInQueue(ICourse course, QuizSlide slide)
        {
            var groupsIds = Request.GetMultipleValuesFromQueryString("group");

            return(ControllerUtils.GetManualCheckingsCountInQueue(slideCheckingsRepo, groupsRepo, User, course.Id, slide, groupsIds));
        }
示例#19
0
        public ActionResult Quiz(QuizSlide slide, string courseId, string userId, bool isGuest, bool isLti = false, ManualQuizChecking manualQuizCheckQueueItem = null, int?send = null, bool attempt = false)
        {
            metricSender.SendCount("quiz.show");
            if (isLti)
            {
                metricSender.SendCount("quiz.show.lti");
            }
            metricSender.SendCount($"quiz.show.{courseId}");
            metricSender.SendCount($"quiz.show.{courseId}.{slide.Id}");

            var course = courseManager.FindCourse(courseId);

            if (course == null)
            {
                return(HttpNotFound());
            }

            if (isGuest)
            {
                metricSender.SendCount("quiz.show.to.guest");
                return(PartialView(GuestQuiz(course, slide)));
            }

            var slideId = slide.Id;
            var isManualCheckingEnabledForUser = slide.ManualChecking && groupsRepo.IsManualCheckingEnabledForUser(course, userId);
            var maxAttemptsCount = GetMaxAttemptsCount(courseId, slide);
            var userScores       = GetUserScoresForBlocks(courseId, userId, slideId, manualQuizCheckQueueItem?.Submission);

            var score = userScores?.AsEnumerable().Sum(res => res.Value) ?? 0;

            var state = GetQuizState(courseId, userId, slideId, score, slide.MaxScore, manualQuizCheckQueueItem?.Submission);

            log.Info($"Показываю тест для пользователя {userId} в слайде {courseId}:{slide.Id}, isLti = {isLti}");

            /* If it's manual checking, change quiz state to IsChecking for correct rendering */
            if (manualQuizCheckQueueItem != null)
            {
                state.Status = QuizStatus.IsCheckingByInstructor;
            }

            /* For manually checked quizzes show last attempt's answers until ?attempt=true is defined in query string */
            if (slide.ManualChecking && manualQuizCheckQueueItem == null && state.Status == QuizStatus.ReadyToSend && state.UsedAttemptsCount > 0 && !attempt)
            {
                state.Status = QuizStatus.Sent;
            }

            /* We also want to show user's answer if user sent answers just now */
            if (state.Status == QuizStatus.ReadyToSend && send.HasValue)
            {
                state.Status = QuizStatus.Sent;
            }

            var userAnswers     = userQuizzesRepo.GetAnswersForShowingOnSlide(courseId, slide, userId, manualQuizCheckQueueItem?.Submission);
            var canUserFillQuiz = (!slide.ManualChecking || isManualCheckingEnabledForUser) && CanUserFillQuiz(state.Status);

            var questionAnswersFrequency = new DefaultDictionary <string, DefaultDictionary <string, int> >();

            if (User.HasAccessFor(courseId, CourseRole.CourseAdmin))
            {
                var choiceBlocks     = slide.Blocks.OfType <ChoiceBlock>().ToList();
                var answersFrequency = userQuizzesRepo.GetAnswersFrequencyForChoiceBlocks(courseId, slide.Id, choiceBlocks);
                questionAnswersFrequency = answersFrequency.Keys.ToDictionary(
                    blockId => blockId,
                    blockId => answersFrequency[blockId].ToDefaultDictionary()
                    ).ToDefaultDictionary();
            }

            var model = new QuizModel
            {
                Course                     = course,
                Slide                      = slide,
                QuizState                  = state,
                MaxAttemptsCount           = maxAttemptsCount,
                UserScores                 = userScores,
                AnswersToQuizzes           = userAnswers,
                IsLti                      = isLti,
                Checking                   = manualQuizCheckQueueItem,
                ManualCheckingsLeftInQueue = manualQuizCheckQueueItem != null?GetManualCheckingsCountInQueue(course, slide) : 0,
                                                 CanUserFillQuiz                = canUserFillQuiz,
                                                 GroupsIds                      = Request.GetMultipleValuesFromQueryString("group"),
                                                 QuestionAnswersFrequency       = questionAnswersFrequency,
                                                 IsManualCheckingEnabledForUser = isManualCheckingEnabledForUser,
            };

            return(PartialView(model));
        }
示例#20
0
        public Dictionary <string, List <string> > GetAnswersForShowOnSlide(string courseId, QuizSlide slide, string userId)
        {
            if (slide == null)
            {
                return(null);
            }
            var answer = new Dictionary <string, List <string> >();

            foreach (var block in slide.Blocks.OfType <AbstractQuestionBlock>())
            {
                var ans = db.UserQuizzes
                          .Where(x => x.UserId == userId && x.SlideId == slide.Id && x.QuizId == block.Id && !x.isDropped).ToList();
                if (block is ChoiceBlock)
                {
                    answer[block.Id] = ans.Select(x => x.ItemId).ToList();
                }
                else if (block is IsTrueBlock)
                {
                    answer[block.Id] = ans.Select(x => x.Text).ToList();
                }
                else if (block is FillInBlock)
                {
                    answer[block.Id] = new List <string>
                    {
                        ans.Select(x => x.Text).FirstOrDefault(),
                        ans.Select(x => x.IsRightAnswer).FirstOrDefault().ToString()
                    }
                }
                ;
            }
            return(answer);
        }
示例#21
0
        public Dictionary <string, List <UserQuiz> > GetAnswersForShowOnSlide(string courseId, QuizSlide slide, string userId)
        {
            if (slide == null)
            {
                return(null);
            }
            var answer = new Dictionary <string, List <UserQuiz> >();

            foreach (var block in slide.Blocks.OfType <AbstractQuestionBlock>())
            {
                var ans = db.UserQuizzes
                          .Where(x => x.UserId == userId && x.SlideId == slide.Id && x.QuizId == block.Id && !x.isDropped).ToList();
                answer[block.Id] = ans;
            }
            return(answer);
        }