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, "Мы не смогли отправить баллы на образовательную платформу"); } } }
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); }
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); }