Beispiel #1
0
        public async Task ProcessResult(UserExerciseSubmission submission, RunningResults result)
        {
            var ltiRequestJson = await ltiRequestsRepo.Find(submission.CourseId, submission.UserId, submission.SlideId);

            if (ltiRequestJson != null)
            {
                try
                {
                    var exerciseSlide = (await courseManager.FindCourseAsync(submission.CourseId)).FindSlideById(submission.SlideId, true) as ExerciseSlide;
                    var score         = await visitsRepo.GetScore(submission.CourseId, submission.SlideId, submission.UserId);

                    await LtiUtils.SubmitScore(exerciseSlide, submission.UserId, score, ltiRequestJson, ltiConsumersRepo);
                }
                catch (Exception e)
                {
                    log.Error(e, "Мы не смогли отправить баллы на образовательную платформу");
                }
            }
        }
Beispiel #2
0
        public async Task <ActionResult <RunSolutionResponse> > RunSolution(
            [FromRoute] Course course,
            [FromRoute] Guid slideId,
            [FromBody] RunSolutionParameters parameters,
            [FromQuery] Language language,
            [FromQuery] bool isLti = false)
        {
            var courseId = course.Id;

            /* Check that no checking solution by this user in last time */
            var delta         = TimeSpan.FromSeconds(30);
            var halfMinuteAgo = DateTime.Now.Subtract(delta);

            if (await userSolutionsRepo.IsCheckingSubmissionByUser(courseId, slideId, User.Identity.GetUserId(), halfMinuteAgo, DateTime.MaxValue))
            {
                return(Json(new RunSolutionResponse(SolutionRunStatus.Ignored)
                {
                    Message = $"Ваше решение по этой задаче уже проверяется. Дождитесь окончания проверки. Вы можете отправить новое решение через {delta.Seconds} секунд."
                }));
            }

            var code = parameters.Solution;

            if (code.Length > TextsRepo.MaxTextSize)
            {
                return(Json(new RunSolutionResponse(SolutionRunStatus.Ignored)
                {
                    Message = "Слишком длинный код"
                }));
            }

            var isInstructor = await courseRolesRepo.HasUserAccessToCourseAsync(UserId, courseId, CourseRoleType.Instructor);

            var exerciseSlide = (await courseManager.FindCourseAsync(courseId))?.FindSlideById(slideId, isInstructor) as ExerciseSlide;

            if (exerciseSlide == null)
            {
                return(NotFound(new ErrorResponse("Slide not found")));
            }

            var result = await CheckSolution(
                courseId, exerciseSlide, code, language, User.Identity.GetUserId(), User.Identity.Name,
                waitUntilChecked : true, saveSubmissionOnCompileErrors : false
                ).ConfigureAwait(false);

            if (isLti)
            {
                try
                {
                    var score = await visitsRepo.GetScore(courseId, slideId, UserId);

                    await LtiUtils.SubmitScore(courseId, exerciseSlide, User.Identity.GetUserId(), score, ltiRequestsRepo, ltiConsumersRepo);
                }
                catch (Exception e)
                {
                    log.Error(e, "Мы не смогли отправить баллы на вашу образовательную платформу");
                    return(Json(new RunSolutionResponse(SolutionRunStatus.InternalServerError)
                    {
                        Message = "Мы не смогли отправить баллы на вашу образовательную платформу. Пожалуйста, обновите страницу — мы попробуем сделать это ещё раз."
                    }));
                }
            }

            return(result);
        }
Beispiel #3
0
        private async Task <RunSolutionResponse> CheckSolution(string courseId,
                                                               ExerciseSlide exerciseSlide,
                                                               string userCode,
                                                               Language language,
                                                               string userId,
                                                               string userName,
                                                               bool waitUntilChecked,
                                                               bool saveSubmissionOnCompileErrors
                                                               )
        {
            var exerciseMetricId = RunnerSetResultController.GetExerciseMetricId(courseId, exerciseSlide);

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

            var course = await courseManager.GetCourseAsync(courseId);

            var exerciseBlock = exerciseSlide.Exercise;
            var buildResult   = exerciseBlock.BuildSolution(userCode);

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

            if (!saveSubmissionOnCompileErrors)
            {
                if (buildResult.HasErrors)
                {
                    return new RunSolutionResponse(SolutionRunStatus.CompilationError)
                           {
                               Message = buildResult.ErrorMessage
                           }
                }
                ;
            }

            var hasAutomaticChecking = exerciseBlock.HasAutomaticChecking();
            var sandbox      = (exerciseSlide.Exercise as UniversalExerciseBlock)?.DockerImageName;
            var submissionId = await CreateInitialSubmission(courseId, exerciseSlide, userCode, language, userId, userName,
                                                             hasAutomaticChecking, buildResult, serviceScopeFactory);

            UserExerciseSubmission submissionNoTracking;             // Получается позже, чтобы быть максимально обновленным из базы, и чтобы не занимать память надолго и не попасть в 2 поколение

            var isCourseAdmin = await courseRolesRepo.HasUserAccessToCourse(userId, courseId, CourseRoleType.CourseAdmin);

            if (buildResult.HasErrors)
            {
                submissionNoTracking = await userSolutionsRepo.FindSubmissionByIdNoTracking(submissionId);

                return(new RunSolutionResponse(SolutionRunStatus.Success)
                {
                    Submission = SubmissionInfo.Build(submissionNoTracking, null, isCourseAdmin)
                });
            }

            var executionTimeout = TimeSpan.FromSeconds(exerciseBlock.TimeLimit * 2 + 5);

            try
            {
                if (hasAutomaticChecking)
                {
                    var priority = exerciseBlock is SingleFileExerciseBlock ? 10 : 0;

                    await userSolutionsRepo.RunAutomaticChecking(submissionId, sandbox, executionTimeout, waitUntilChecked, priority);
                }
            }
            catch (SubmissionCheckingTimeout)
            {
                log.Error($"Не смог запустить проверку решения, никто не взял его на проверку за {executionTimeout.TotalSeconds} секунд.\nКурс «{course.Title}», слайд «{exerciseSlide.Title}» ({exerciseSlide.Id})");
                await errorsBot.PostToChannelAsync($"Не смог запустить проверку решения, никто не взял его на проверку за {executionTimeout.TotalSeconds} секунд.\nКурс «{course.Title}», слайд «{exerciseSlide.Title}» ({exerciseSlide.Id})\n\nhttps://ulearn.me/Sandbox");

                submissionNoTracking = await userSolutionsRepo.FindSubmissionByIdNoTracking(submissionId);

                var message = submissionNoTracking.AutomaticChecking.Status == AutomaticExerciseCheckingStatus.Running
                                        ? "Решение уже проверяется."
                                        : "Решение ждет своей очереди на проверку, мы будем пытаться проверить его еще 10 минут.";
                return(new RunSolutionResponse(SolutionRunStatus.SubmissionCheckingTimeout)
                {
                    Message = $"К сожалению, мы не смогли оперативно проверить ваше решение. {message}. Просто подождите и обновите страницу.",
                    Submission = SubmissionInfo.Build(submissionNoTracking, null, isCourseAdmin)
                });
            }

            submissionNoTracking = await userSolutionsRepo.FindSubmissionByIdNoTracking(submissionId);

            if (!waitUntilChecked)
            {
                metricSender.SendCount($"exercise.{exerciseMetricId}.dont_wait_result");
                // По вовзращаемому значению нельзя отличить от случая, когда никто не взял на проверку
                return(new RunSolutionResponse(SolutionRunStatus.Success)
                {
                    Submission = SubmissionInfo.Build(submissionNoTracking, null, isCourseAdmin)
                });
            }

            if (!hasAutomaticChecking)
            {
                await RunnerSetResultController.SendToReviewAndUpdateScore(submissionNoTracking, courseManager, slideCheckingsRepo, groupsRepo, visitsRepo, metricSender);
            }

            // StyleErrors для C# proj и file устанавливаются только здесь, берутся из buildResult. В StyleErrorsResultObserver.ProcessResult попадают только ошибки из docker
            if (buildResult.HasStyleErrors)
            {
                var styleErrors = await ConvertStyleErrors(buildResult);

                submissionNoTracking.Reviews = await styleErrorsResultObserver.CreateStyleErrorsReviewsForSubmission(submissionId, styleErrors, exerciseMetricId);
            }

            var score = await visitsRepo.GetScore(courseId, exerciseSlide.Id, userId);

            var waitingForManualChecking      = submissionNoTracking.ManualCheckings.Any(c => !c.IsChecked) ? true : (bool?)null;
            var prohibitFurtherManualChecking = submissionNoTracking.ManualCheckings.Any(c => c.ProhibitFurtherManualCheckings);
            var result = new RunSolutionResponse(SolutionRunStatus.Success)
            {
                Score = score,
                WaitingForManualChecking      = waitingForManualChecking,
                ProhibitFurtherManualChecking = prohibitFurtherManualChecking,
                Submission = SubmissionInfo.Build(submissionNoTracking, null, isCourseAdmin)
            };

            return(result);
        }