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 })); }
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)); }
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)); } } }
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); }
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)); }
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)); }
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, })); }
private static int GetMaxDropCount(QuizSlide quizSlide) { if (quizSlide == null) { return(MAX_DROPS_COUNT); } var maxDropCount = quizSlide.MaxDropCount; return(maxDropCount == 0 ? MAX_DROPS_COUNT : maxDropCount); }
private QuizModel GuestQuiz(QuizSlide slide, string courseId) { return(new QuizModel { CourseId = courseId, Slide = slide, IsGuest = true, QuizState = QuizState.NotPassed }); }
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), }); }
private byte[] ServeAddQuiz(HttpRequestEventArgs context, string path) { var quiz = new QuizSlide { Id = Guid.NewGuid(), Title = "Новый quiz" }; return(AddNewSlide(context, path, quiz)); }
private QuizModel GuestQuiz(Course course, QuizSlide slide) { return(new QuizModel { Course = course, Slide = slide, IsGuest = true, QuizState = QuizState.NotPassed, }); }
private int GetMaxTriesCount(string courseId, QuizSlide quizSlide) { if (User.HasAccessFor(courseId, CourseRole.Tester)) { return(InfinityTriesCount); } if (quizSlide == null) { return(defaultMaxTriesCount); } return(quizSlide.MaxTriesCount); }
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); }
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); }
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); }
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)); }
private int GetManualCheckingsCountInQueue(ICourse course, QuizSlide slide) { var groupsIds = Request.GetMultipleValuesFromQueryString("group"); return(ControllerUtils.GetManualCheckingsCountInQueue(slideCheckingsRepo, groupsRepo, User, course.Id, slide, groupsIds)); }
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)); }
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); }
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); }