Exemplo n.º 1
0
        private int GetMaxSlideScoreForUser(Course course, Slide slide, string userId)
        {
            var isSlideSolved                = ControllerUtils.IsSlideSolved(solutionsRepo, userQuizzesRepo, course, userId, slide.Id);
            var hasManualChecking            = visitsRepo.HasManualChecking(course.Id, userId, slide.Id);
            var enabledManualCheckingForUser = groupsRepo.IsManualCheckingEnabledForUser(course, userId);
            var maxSlideScore                = ControllerUtils.GetMaxScoreForUsersSlide(slide, isSlideSolved, hasManualChecking, enabledManualCheckingForUser);

            return(maxSlideScore);
        }
Exemplo n.º 2
0
        private int GetMaxSlideScoreForUser(Course course, Slide slide, string userId)
        {
            var solvedSlidesIds = ControllerUtils.GetSolvedSlides(solutionsRepo, userQuizzesRepo, course, userId);
            var slidesWithUsersManualChecking = new HashSet <Guid>(visitsRepo.GetSlidesWithUsersManualChecking(course.Id, userId));
            var enabledManualCheckingForUser  = groupsRepo.IsManualCheckingEnabledForUser(course, userId);
            var maxSlideScore = ControllerUtils.GetMaxScoreForUsersSlide(slide, solvedSlidesIds.Contains(slide.Id), slidesWithUsersManualChecking.Contains(slide.Id), enabledManualCheckingForUser);

            return(maxSlideScore);
        }
        private TocModel CreateTocModel(Course course, Guid?currentSlideId, string userId)
        {
            var visibleUnits    = unitsRepo.GetVisibleUnits(course, User);
            var visited         = visitsRepo.GetIdOfVisitedSlides(course.Id, userId);
            var scoresForSlides = visitsRepo.GetScoresForSlides(course.Id, userId);

            var solvedSlidesIds = ControllerUtils.GetSolvedSlides(solutionsRepo, userQuizzesRepo, course, userId);
            var slidesWithUsersManualChecking      = visitsRepo.GetSlidesWithUsersManualChecking(course.Id, userId).ToImmutableHashSet();
            var enabledManualCheckingForUser       = groupsRepo.IsManualCheckingEnabledForUser(course, userId);
            Func <Slide, int> getSlideMaxScoreFunc = s => ControllerUtils.GetMaxScoreForUsersSlide(s, solvedSlidesIds.Contains(s.Id), slidesWithUsersManualChecking.Contains(s.Id), enabledManualCheckingForUser);

            var userGroupsIds           = groupsRepo.GetUserGroupsIds(course.Id, userId);
            var enabledScoringGroupsIds = groupsRepo.GetEnabledAdditionalScoringGroups(course.Id)
                                          .Where(e => userGroupsIds.Contains(e.GroupId))
                                          .Select(e => e.ScoringGroupId)
                                          .ToList();
            var additionalScores = additionalScoresRepo.GetAdditionalScoresForUser(course.Id, userId);

            var builder = new TocModelBuilder(
                s => Url.RouteUrl("Course.SlideById", new { courseId = course.Id, slideId = s.Url }),
                s => scoresForSlides.ContainsKey(s.Id) ? scoresForSlides[s.Id] : 0,
                getSlideMaxScoreFunc,
                (u, g) => additionalScores.GetOrDefault(Tuple.Create(u.Id, g.Id), 0),
                course,
                currentSlideId)
            {
                GetUnitInstructionNotesUrl = unit => Url.Action("InstructorNote", "Course", new { courseId = course.Id, unitId = unit.Id }),
                GetUnitStatisticsUrl       = unit => Url.Action("UnitStatistics", "Analytics", new { courseId = course.Id, unitId = unit.Id }),
                IsInstructor  = User.HasAccessFor(course.Id, CourseRole.Instructor),
                IsSolved      = s => solvedSlidesIds.Contains(s.Id),
                IsVisited     = s => visited.Contains(s.Id),
                IsUnitVisible = visibleUnits.Contains,
                IsSlideHidden = s => s is QuizSlide && ((QuizSlide)s).ManualChecking &&
                                !enabledManualCheckingForUser && !solvedSlidesIds.Contains(s.Id),
                EnabledScoringGroupsIds = enabledScoringGroupsIds,
            };

            var userGroups             = groupsRepo.GetUserGroups(course.Id, User.Identity.GetUserId());
            var tocGroupsForStatistics = userGroups.Select(g => new TocGroupForStatistics
            {
                GroupName     = g.Name,
                StatisticsUrl = Url.Action("CourseStatistics", "Analytics", new { courseId = course.Id, group = g.Id })
            });
            var toc = builder.CreateTocModel(tocGroupsForStatistics.ToList());

            toc.NextUnitTime = unitsRepo.GetNextUnitPublishTime(course.Id);
            return(toc);
        }
Exemplo n.º 4
0
        public static async Task <bool> SendToReviewAndUpdateScore(UserExerciseSubmission submission,
                                                                   CourseManager courseManager, SlideCheckingsRepo slideCheckingsRepo, GroupsRepo groupsRepo, VisitsRepo visitsRepo, MetricSender metricSender,
                                                                   bool startTransaction)
        {
            var userId        = submission.User.Id;
            var courseId      = submission.CourseId;
            var course        = courseManager.GetCourse(courseId);
            var exerciseSlide = course.FindSlideById(submission.SlideId, true) as ExerciseSlide;             // SlideId проверен в вызывающем методе

            if (exerciseSlide == null)
            {
                return(false);
            }
            var exerciseMetricId  = GetExerciseMetricId(courseId, exerciseSlide);
            var automaticChecking = submission.AutomaticChecking;
            var isProhibitedUserToSendForReview = slideCheckingsRepo.IsProhibitedToSendExerciseToManualChecking(courseId, exerciseSlide.Id, userId);
            var sendToReview = exerciseSlide.Scoring.RequireReview &&
                               submission.AutomaticCheckingIsRightAnswer &&
                               !isProhibitedUserToSendForReview &&
                               groupsRepo.IsManualCheckingEnabledForUser(course, userId);

            if (sendToReview)
            {
                await slideCheckingsRepo.RemoveWaitingManualCheckings <ManualExerciseChecking>(courseId, exerciseSlide.Id, userId, false);

                await slideCheckingsRepo.AddManualExerciseChecking(courseId, exerciseSlide.Id, userId, submission);

                await visitsRepo.MarkVisitsAsWithManualChecking(courseId, exerciseSlide.Id, userId);

                metricSender.SendCount($"exercise.{exerciseMetricId}.sent_to_review");
                metricSender.SendCount("exercise.sent_to_review");
            }

            await visitsRepo.UpdateScoreForVisit(courseId, exerciseSlide, userId);

            if (automaticChecking != null)
            {
                var verdictForMetric = automaticChecking.GetVerdict().Replace(" ", "");
                metricSender.SendCount($"exercise.{exerciseMetricId}.{verdictForMetric}");
            }

            return(sendToReview);
        }
Exemplo n.º 5
0
        public async Task <ActionResult> SubmitQuiz(string courseId, Guid slideId, string answer, bool isLti)
        {
            metricSender.SendCount("quiz.submit");
            if (isLti)
            {
                metricSender.SendCount("quiz.submit.lti");
            }
            metricSender.SendCount($"quiz.submit.{courseId}");
            metricSender.SendCount($"quiz.submit.{courseId}.{slideId}");

            var course = courseManager.GetCourse(courseId);
            var slide  = course.FindSlideById(slideId) as QuizSlide;

            if (slide == null)
            {
                return(new HttpNotFoundResult());
            }

            var userId        = User.Identity.GetUserId();
            var maxTriesCount = GetMaxTriesCount(courseId, slide);
            var quizState     = GetQuizState(courseId, userId, slideId);

            if (!CanUserFillQuiz(quizState.Item1))
            {
                return(new HttpStatusCodeResult(HttpStatusCode.OK, "Already answered"));
            }

            var tryIndex = quizState.Item2;

            metricSender.SendCount($"quiz.submit.try.{tryIndex}");
            metricSender.SendCount($"quiz.submit.{courseId}.try.{tryIndex}");
            metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.try.{tryIndex}");

            if (slide.ManualChecking && !groupsRepo.IsManualCheckingEnabledForUser(course, userId))
            {
                return(new HttpStatusCodeResult(HttpStatusCode.OK, "Manual checking is disabled for you"));
            }

            var time    = DateTime.Now;
            var answers = JsonConvert.DeserializeObject <List <QuizAnswer> >(answer).GroupBy(x => x.QuizId);
            var quizBlockWithTaskCount = slide.Blocks.Count(x => x is AbstractQuestionBlock);
            var allQuizInfos           = new List <QuizInfoForDb>();

            foreach (var ans in answers)
            {
                var quizInfos = CreateQuizInfo(slide, ans);
                if (quizInfos != null)
                {
                    allQuizInfos.AddRange(quizInfos);
                }
            }
            var blocksInAnswerCount = allQuizInfos.Select(x => x.QuizId).Distinct().Count();

            if (blocksInAnswerCount != quizBlockWithTaskCount)
            {
                return(new HttpStatusCodeResult(HttpStatusCode.Forbidden, "Has empty blocks"));
            }

            using (var transaction = db.Database.BeginTransaction())
            {
                await userQuizzesRepo.RemoveUserQuizzes(courseId, slideId, userId);

                foreach (var quizInfoForDb in allQuizInfos)
                {
                    await userQuizzesRepo.AddUserQuiz(courseId, quizInfoForDb.IsRightAnswer, quizInfoForDb.ItemId, quizInfoForDb.QuizId,
                                                      slideId, quizInfoForDb.Text, userId, time, quizInfoForDb.QuizBlockScore, quizInfoForDb.QuizBlockMaxScore);
                }

                transaction.Commit();
            }

            if (slide.ManualChecking)
            {
                /* If this quiz is already queued for checking for this user, don't add it to queue again */
                if (quizState.Item1 != QuizState.WaitForCheck)
                {
                    await slideCheckingsRepo.AddQuizAttemptForManualChecking(courseId, slideId, userId);

                    await visitsRepo.MarkVisitsAsWithManualChecking(courseId, slideId, userId);
                }
            }
            /* Recalculate score for quiz if this attempt is allowed. Don't recalculate score if this attempt is more then maxTriesCount */
            else if (tryIndex < maxTriesCount)
            {
                var score = allQuizInfos
                            .DistinctBy(forDb => forDb.QuizId)
                            .Sum(forDb => forDb.QuizBlockScore);

                metricSender.SendCount($"quiz.submit.try.{tryIndex}.score", score);
                metricSender.SendCount($"quiz.submit.{courseId}.try.{tryIndex}.score", score);
                metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.try.{tryIndex}.score", score);
                metricSender.SendCount($"quiz.submit.score", score);
                metricSender.SendCount($"quiz.submit.{courseId}.score", score);
                metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.score", score);

                if (score == slide.MaxScore)
                {
                    metricSender.SendCount($"quiz.submit.try.{tryIndex}.full_passed");
                    metricSender.SendCount($"quiz.submit.{courseId}.try.{tryIndex}.full_passed");
                    metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.try.{tryIndex}.full_passed");
                    metricSender.SendCount($"quiz.submit.full_passed");
                    metricSender.SendCount($"quiz.submit.{courseId}.full_passed");
                    metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.full_passed");
                }

                await slideCheckingsRepo.AddQuizAttemptWithAutomaticChecking(courseId, slideId, userId, score);

                await visitsRepo.UpdateScoreForVisit(courseId, slideId, userId);

                if (isLti)
                {
                    LtiUtils.SubmitScore(courseId, slide, userId);
                }
            }

            return(Json(new
            {
                url = Url.RouteUrl("Course.SlideById", new { courseId = courseId, slideId = slide.Url, send = 1 })
            }));
        }
Exemplo n.º 6
0
        public async Task <ActionResult> SubmitQuiz(string courseId, Guid slideId, string answer, bool isLti)
        {
            var course = courseManager.GetCourse(courseId);
            var slide  = course.FindSlideById(slideId) as QuizSlide;

            if (slide == null)
            {
                return(new HttpNotFoundResult());
            }

            var userId       = User.Identity.GetUserId();
            var maxDropCount = GetMaxDropCount(slide);
            var quizState    = GetQuizState(courseId, userId, slideId, maxDropCount).Item1;

            if (!CanUserFillQuiz(quizState))
            {
                return(new HttpStatusCodeResult(HttpStatusCode.OK, "Already answered"));
            }

            if (slide.ManualChecking && !groupsRepo.IsManualCheckingEnabledForUser(course, userId))
            {
                return(new HttpStatusCodeResult(HttpStatusCode.OK, "Manual checking is disabled for you"));
            }

            var time    = DateTime.Now;
            var answers = JsonConvert.DeserializeObject <List <QuizAnswer> >(answer).GroupBy(x => x.QuizId);
            var quizBlockWithTaskCount = slide.Blocks.Count(x => x is AbstractQuestionBlock);
            var allQuizInfos           = new List <QuizInfoForDb>();

            foreach (var ans in answers)
            {
                var quizInfos = CreateQuizInfo(slide, ans);
                if (quizInfos != null)
                {
                    allQuizInfos.AddRange(quizInfos);
                }
            }
            var blocksInAnswerCount = allQuizInfos.Select(x => x.QuizId).Distinct().Count();

            if (blocksInAnswerCount != quizBlockWithTaskCount)
            {
                return(new HttpStatusCodeResult(HttpStatusCode.Forbidden, "Has empty blocks"));
            }

            using (var transaction = db.Database.BeginTransaction())
            {
                await userQuizzesRepo.RemoveUserQuizzes(courseId, slideId, userId);

                foreach (var quizInfoForDb in allQuizInfos)
                {
                    await userQuizzesRepo.AddUserQuiz(courseId, quizInfoForDb.IsRightAnswer, quizInfoForDb.ItemId, quizInfoForDb.QuizId,
                                                      slideId, quizInfoForDb.Text, userId, time, quizInfoForDb.QuizBlockScore, quizInfoForDb.QuizBlockMaxScore);
                }

                transaction.Commit();
            }

            if (slide.ManualChecking)
            {
                /* If this quiz is already queued for checking for this user, don't add it to queue again */
                if (quizState != QuizState.WaitForCheck)
                {
                    await slideCheckingsRepo.AddQuizAttemptForManualChecking(courseId, slideId, userId);

                    await visitsRepo.MarkVisitsAsWithManualChecking(slideId, userId);
                }
            }
            else
            {
                var score = allQuizInfos
                            .DistinctBy(forDb => forDb.QuizId)
                            .Sum(forDb => forDb.QuizBlockScore);
                await slideCheckingsRepo.AddQuizAttemptWithAutomaticChecking(courseId, slideId, userId, score);

                await visitsRepo.UpdateScoreForVisit(courseId, slideId, userId);

                if (isLti)
                {
                    LtiUtils.SubmitScore(slide, userId);
                }
            }

            return(new HttpStatusCodeResult(HttpStatusCode.OK));
        }
Exemplo n.º 7
0
        protected async Task <RunSolutionResult> CheckSolution(string courseId, ExerciseSlide exerciseSlide, string userCode, string userId, string userName, bool waitUntilChecked, bool saveSubmissionOnCompileErrors)
        {
            var slideTitleForMetric = exerciseSlide.LatinTitle.Replace(".", "_").ToLower(CultureInfo.InvariantCulture);

            if (slideTitleForMetric.Length > 25)
            {
                slideTitleForMetric = slideTitleForMetric.Substring(0, 25);
            }
            var exerciseMetricId = $"{courseId.ToLower(CultureInfo.InvariantCulture)}.{exerciseSlide.Id.ToString("N").Substring(32 - 25)}.{slideTitleForMetric}";

            metricSender.SendCount("exercise.try");
            metricSender.SendCount($"exercise.{courseId.ToLower(CultureInfo.InvariantCulture)}.try");
            metricSender.SendCount($"exercise.{exerciseMetricId}.try");

            var course        = courseManager.GetCourse(courseId);
            var exerciseBlock = exerciseSlide.Exercise;
            var buildResult   = exerciseBlock.BuildSolution(userCode);

            if (buildResult.HasErrors)
            {
                metricSender.SendCount($"exercise.{exerciseMetricId}.CompilationError");
            }
            if (buildResult.HasStyleErrors)
            {
                metricSender.SendCount($"exercise.{exerciseMetricId}.StyleViolation");
            }

            if (!saveSubmissionOnCompileErrors)
            {
                if (buildResult.HasErrors)
                {
                    return new RunSolutionResult {
                               IsCompileError = true, ErrorMessage = buildResult.ErrorMessage, ExecutionServiceName = "uLearn"
                    }
                }
                ;
            }

            var compilationErrorMessage = buildResult.HasErrors ? buildResult.ErrorMessage : null;
            var dontRunSubmission       = buildResult.HasErrors;
            var submissionLanguage      = SubmissionLanguageHelpers.ByLangId(exerciseSlide.Exercise.LangId);
            var submission = await userSolutionsRepo.AddUserExerciseSubmission(
                courseId, exerciseSlide.Id,
                userCode, compilationErrorMessage, null,
                userId, "uLearn", GenerateSubmissionName(exerciseSlide, userName),
                submissionLanguage,
                dontRunSubmission?AutomaticExerciseCheckingStatus.Done : AutomaticExerciseCheckingStatus.Waiting
                );

            if (buildResult.HasErrors)
            {
                return new RunSolutionResult {
                           IsCompileError = true, ErrorMessage = buildResult.ErrorMessage, SubmissionId = submission.Id, ExecutionServiceName = "uLearn"
                }
            }
            ;

            try
            {
                if (submissionLanguage.HasAutomaticChecking())
                {
                    await userSolutionsRepo.RunAutomaticChecking(submission, executionTimeout, waitUntilChecked);
                }
            }
            catch (SubmissionCheckingTimeout)
            {
                log.Error($"Не смог запустить проверку решения, никто не взял его на проверку за {executionTimeout.TotalSeconds} секунд.\nКурс «{course.Title}», слайд «{exerciseSlide.Title}» ({exerciseSlide.Id})");

                errorsBot.PostToChannel($"Не смог запустить проверку решения, никто не взял его на проверку за {executionTimeout.TotalSeconds} секунд.\nКурс «{course.Title}», слайд «{exerciseSlide.Title}» ({exerciseSlide.Id})\n\nhttps://ulearn.me/Sandbox");
                return(new RunSolutionResult
                {
                    IsCompillerFailure = true,
                    ErrorMessage = "К сожалению, из-за большой нагрузки мы не смогли оперативно проверить ваше решение. " +
                                   "Мы попробуем проверить его позже, просто подождите и обновите страницу. ",
                    ExecutionServiceName = "uLearn"
                });
            }

            if (!waitUntilChecked)
            {
                metricSender.SendCount($"exercise.{exerciseMetricId}.dont_wait_result");
                return(new RunSolutionResult {
                    SubmissionId = submission.Id
                });
            }

            /* Update the submission */
            submission = userSolutionsRepo.FindNoTrackingSubmission(submission.Id);

            var automaticChecking = submission.AutomaticChecking;
            var isProhibitedUserToSendForReview = slideCheckingsRepo.IsProhibitedToSendExerciseToManualChecking(courseId, exerciseSlide.Id, userId);
            var sendToReview = exerciseBlock.RequireReview &&
                               submission.AutomaticCheckingIsRightAnswer &&
                               !isProhibitedUserToSendForReview &&
                               groupsRepo.IsManualCheckingEnabledForUser(course, userId);

            if (sendToReview)
            {
                await slideCheckingsRepo.RemoveWaitingManualExerciseCheckings(courseId, exerciseSlide.Id, userId);

                await slideCheckingsRepo.AddManualExerciseChecking(courseId, exerciseSlide.Id, userId, submission);

                await visitsRepo.MarkVisitsAsWithManualChecking(courseId, exerciseSlide.Id, userId);

                metricSender.SendCount($"exercise.{exerciseMetricId}.sent_to_review");
                metricSender.SendCount("exercise.sent_to_review");
            }
            await visitsRepo.UpdateScoreForVisit(courseId, exerciseSlide.Id, userId);

            if (automaticChecking != null)
            {
                var verdictForMetric = automaticChecking.GetVerdict().Replace(" ", "");
                metricSender.SendCount($"exercise.{exerciseMetricId}.{verdictForMetric}");
            }

            if (submission.AutomaticCheckingIsRightAnswer)
            {
                await CreateStyleErrorsReviewsForSubmission(submission, buildResult.StyleErrors, exerciseMetricId);
            }

            var result = new RunSolutionResult
            {
                IsCompileError       = automaticChecking?.IsCompilationError ?? false,
                ErrorMessage         = automaticChecking?.CompilationError.Text ?? "",
                IsRightAnswer        = submission.AutomaticCheckingIsRightAnswer,
                ExpectedOutput       = exerciseBlock.HideExpectedOutputOnError ? null : exerciseSlide.Exercise.ExpectedOutput.NormalizeEoln(),
                ActualOutput         = automaticChecking?.Output.Text ?? "",
                ExecutionServiceName = automaticChecking?.ExecutionServiceName ?? "ulearn",
                SentToReview         = sendToReview,
                SubmissionId         = submission.Id,
            };

            if (buildResult.HasStyleErrors)
            {
                result.IsStyleViolation = true;
                result.StyleMessage     = string.Join("\n", buildResult.StyleErrors.Select(e => e.GetMessageWithPositions()));
            }
            return(result);
        }
Exemplo n.º 8
0
        public async Task <ActionResult> SubmitQuiz(string courseId, Guid slideId, string answer, bool isLti)
        {
            metricSender.SendCount("quiz.submit");
            if (isLti)
            {
                metricSender.SendCount("quiz.submit.lti");
            }
            metricSender.SendCount($"quiz.submit.{courseId}");
            metricSender.SendCount($"quiz.submit.{courseId}.{slideId}");

            var course = courseManager.GetCourse(courseId);
            var slide  = course.FindSlideById(slideId) as QuizSlide;

            if (slide == null)
            {
                return(new HttpNotFoundResult());
            }

            var userId        = User.Identity.GetUserId();
            var maxTriesCount = GetMaxAttemptsCount(courseId, slide);

            /* Not it's not important what user's score is, so just pass 0 */
            var state = GetQuizState(courseId, userId, slideId, 0, slide.MaxScore);

            if (!CanUserFillQuiz(state.Status))
            {
                return(new HttpStatusCodeResult(HttpStatusCode.OK, "Already answered"));
            }

            var attemptNumber = state.UsedAttemptsCount;

            metricSender.SendCount($"quiz.submit.try.{attemptNumber}");
            metricSender.SendCount($"quiz.submit.{courseId}.try.{attemptNumber}");
            metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.try.{attemptNumber}");

            if (slide.ManualChecking && !groupsRepo.IsManualCheckingEnabledForUser(course, userId))
            {
                return(new HttpStatusCodeResult(HttpStatusCode.OK, "Manual checking is disabled for you"));
            }

            var answers = JsonConvert.DeserializeObject <List <QuizAnswer> >(answer).GroupBy(x => x.BlockId);
            var quizBlockWithTaskCount = slide.Blocks.Count(x => x is AbstractQuestionBlock);
            var allQuizInfos           = new List <QuizInfoForDb>();

            foreach (var ans in answers)
            {
                var quizInfos = CreateQuizInfo(slide, ans);
                if (quizInfos != null)
                {
                    allQuizInfos.AddRange(quizInfos);
                }
            }

            var blocksInAnswerCount = allQuizInfos.Select(x => x.BlockId).Distinct().Count();

            if (blocksInAnswerCount != quizBlockWithTaskCount)
            {
                return(new HttpStatusCodeResult(HttpStatusCode.Forbidden, "Has empty blocks"));
            }

            UserQuizSubmission submission;

            using (var transaction = db.Database.BeginTransaction())
            {
                submission = await userQuizzesRepo.AddSubmission(courseId, slideId, userId, DateTime.Now).ConfigureAwait(false);

                foreach (var quizInfoForDb in allQuizInfos)
                {
                    await userQuizzesRepo.AddUserQuizAnswer(
                        submission.Id,
                        quizInfoForDb.IsRightAnswer,
                        quizInfoForDb.BlockId,
                        quizInfoForDb.ItemId,
                        quizInfoForDb.Text,
                        quizInfoForDb.QuizBlockScore,
                        quizInfoForDb.QuizBlockMaxScore
                        ).ConfigureAwait(false);
                }

                transaction.Commit();
            }

            if (slide.ManualChecking)
            {
                /* If this quiz is already queued for checking for this user, remove waiting checkings */
                if (state.Status == QuizStatus.WaitsForManualChecking)
                {
                    await slideCheckingsRepo.RemoveWaitingManualCheckings <ManualQuizChecking>(courseId, slideId, userId).ConfigureAwait(false);
                }

                await slideCheckingsRepo.AddManualQuizChecking(submission, courseId, slideId, userId).ConfigureAwait(false);

                await visitsRepo.MarkVisitsAsWithManualChecking(courseId, slideId, userId).ConfigureAwait(false);
            }
            /* Recalculate score for quiz if this attempt is allowed. Don't recalculate score if this attempt number is more then maxTriesCount */
            else if (attemptNumber < maxTriesCount)
            {
                var score = allQuizInfos
                            .DistinctBy(forDb => forDb.BlockId)
                            .Sum(forDb => forDb.QuizBlockScore);

                metricSender.SendCount($"quiz.submit.try.{attemptNumber}.score", score);
                metricSender.SendCount($"quiz.submit.{courseId}.try.{attemptNumber}.score", score);
                metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.try.{attemptNumber}.score", score);
                metricSender.SendCount($"quiz.submit.score", score);
                metricSender.SendCount($"quiz.submit.{courseId}.score", score);
                metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.score", score);

                if (score == slide.MaxScore)
                {
                    metricSender.SendCount($"quiz.submit.try.{attemptNumber}.full_passed");
                    metricSender.SendCount($"quiz.submit.{courseId}.try.{attemptNumber}.full_passed");
                    metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.try.{attemptNumber}.full_passed");
                    metricSender.SendCount($"quiz.submit.full_passed");
                    metricSender.SendCount($"quiz.submit.{courseId}.full_passed");
                    metricSender.SendCount($"quiz.submit.{courseId}.{slideId}.full_passed");
                }

                await slideCheckingsRepo.AddAutomaticQuizChecking(submission, courseId, slideId, userId, score).ConfigureAwait(false);

                await visitsRepo.UpdateScoreForVisit(courseId, slideId, slide.MaxScore, userId).ConfigureAwait(false);

                if (isLti)
                {
                    LtiUtils.SubmitScore(courseId, slide, userId);
                }
            }

            return(Json(new
            {
                url = Url.RouteUrl("Course.SlideById", new { courseId = courseId, slideId = slide.Url, send = 1 })
            }));
        }
Exemplo n.º 9
0
        private async Task <RunSolutionResult> CheckSolution(string courseId, ExerciseSlide exerciseSlide, string userCode)
        {
            var exerciseBlock = exerciseSlide.Exercise;
            var userId        = User.Identity.GetUserId();
            var solution      = exerciseBlock.BuildSolution(userCode);

            if (solution.HasErrors)
            {
                return new RunSolutionResult {
                           IsCompileError = true, ErrorMessage = solution.ErrorMessage, ExecutionServiceName = "uLearn"
                }
            }
            ;
            if (solution.HasStyleIssues)
            {
                return new RunSolutionResult {
                           IsStyleViolation = true, ErrorMessage = solution.StyleMessage, ExecutionServiceName = "uLearn"
                }
            }
            ;

            var submission = await solutionsRepo.RunUserSolution(
                courseId, exerciseSlide.Id, userId,
                userCode, null, null, false, "uLearn",
                GenerateSubmissionName(exerciseSlide), executionTimeout
                );

            var course = courseManager.GetCourse(courseId);

            if (submission == null)
            {
                log.Error($"Не смог запустить проверку решения, никто не взял его на проверку за {executionTimeout.TotalSeconds} секунд.\nКурс «{course.Title}», слайд «{exerciseSlide.Title}» ({exerciseSlide.Id})");

                errorsBot.PostToChannel($"Не смог запустить проверку решения, никто не взял его на проверку за {executionTimeout.TotalSeconds} секунд.\nКурс «{course.Title}», слайд «{exerciseSlide.Title}» ({exerciseSlide.Id})\n\nhttps://ulearn.me/Sandbox");
                return(new RunSolutionResult
                {
                    IsCompillerFailure = true,
                    ErrorMessage = "К сожалению, из-за большой нагрузки мы не смогли оперативно проверить ваше решение. " +
                                   "Мы попробуем проверить его позже, просто подождите и обновите страницу. ",
                    ExecutionServiceName = "uLearn"
                });
            }

            var automaticChecking = submission.AutomaticChecking;
            var isProhibitedUserToSendForReview = slideCheckingsRepo.IsProhibitedToSendExerciseToManualChecking(courseId, exerciseSlide.Id, userId);
            var sendToReview = exerciseBlock.RequireReview &&
                               automaticChecking.IsRightAnswer &&
                               !isProhibitedUserToSendForReview &&
                               groupsRepo.IsManualCheckingEnabledForUser(course, userId);

            if (sendToReview)
            {
                await slideCheckingsRepo.RemoveWaitingManualExerciseCheckings(courseId, exerciseSlide.Id, userId);

                await slideCheckingsRepo.AddManualExerciseChecking(courseId, exerciseSlide.Id, userId, submission);

                await visitsRepo.MarkVisitsAsWithManualChecking(exerciseSlide.Id, userId);
            }
            await visitsRepo.UpdateScoreForVisit(courseId, exerciseSlide.Id, userId);

            return(new RunSolutionResult
            {
                IsCompileError = automaticChecking.IsCompilationError,
                ErrorMessage = automaticChecking.CompilationError.Text,
                IsRightAnswer = automaticChecking.IsRightAnswer,
                ExpectedOutput = exerciseBlock.HideExpectedOutputOnError ? null : exerciseSlide.Exercise.ExpectedOutput.NormalizeEoln(),
                ActualOutput = automaticChecking.Output.Text,
                ExecutionServiceName = automaticChecking.ExecutionServiceName,
                SentToReview = sendToReview,
                SubmissionId = submission.Id,
            });
        }