private async Task<RunSolutionResult> CheckSolution(ExerciseSlide exerciseSlide, string code, IExecutionService executionService) { var exerciseBlock = exerciseSlide.Exercise; var solution = exerciseBlock.Solution.BuildSolution(code); if (solution.HasErrors) return new RunSolutionResult { IsCompileError = true, CompilationError = solution.ErrorMessage, ExecutionServiceName = "uLearn" }; if (solution.HasStyleIssues) return new RunSolutionResult { IsStyleViolation = true, CompilationError = solution.StyleMessage, ExecutionServiceName = "uLearn" }; var submissionDetails = await executionService.Submit(solution.SourceCode, GenerateSubmissionName(exerciseSlide)); if (submissionDetails == null) return new RunSolutionResult { IsCompillerFailure = true, CompilationError = "Ой-ой, штуковина, которая проверяет решения сломалась (или просто устала). Попробуйте отправить решение позже (когда она немного отдохнет).", ExecutionServiceName = executionService.Name }; var output = submissionDetails.GetOutput(); var expectedOutput = exerciseBlock.ExpectedOutput.NormalizeEoln(); var isRightAnswer = submissionDetails.IsSuccess && output.Equals(expectedOutput); return new RunSolutionResult { IsCompileError = submissionDetails.IsCompilationError, CompilationError = submissionDetails.CompilationErrorMessage, IsRightAnswer = isRightAnswer, ExpectedOutput = exerciseBlock.HideExpectedOutputOnError ? null : expectedOutput, ActualOutput = output, ExecutionServiceName = submissionDetails.ServiceName }; }
private static void TestExerciseSlide(ExerciseSlide slide, IExecutionService executionService) { var solution = slide.Exercise.Solution.BuildSolution(slide.Exercise.EthalonSolution); if (solution.HasErrors) Assert.Fail("Template solution: " + slide.Exercise.EthalonSolution + "\n\n" + "source code: " + solution.SourceCode + "\n\n" + "solution has error in: " + slide.Info.UnitName + " - " + slide.Title + "\n" + "\terror: " + solution.ErrorMessage + "\n\n"); else { //ExperimentMethod(solution); Попытка научиться проводить тестирование, не отправляя на Ideon. var testName = TestContext.CurrentContext.Test.Name; var submition = executionService.Submit(solution.SourceCode, testName).Result; var output = submition.StdOut + "\n" + submition.StdErr; var isRightAnswer = output.NormalizeEoln().Equals(slide.Exercise.ExpectedOutput.NormalizeEoln()); var result = new RunSolutionResult { CompilationError = submition.CompilationErrorMessage, IsRightAnswer = isRightAnswer, ExpectedOutput = slide.Exercise.ExpectedOutput, ActualOutput = output }; if (!isRightAnswer) { Assert.Fail("mistake in: " + slide.Info.UnitName + " - " + slide.Title + "\n" + "\tActualOutput: " + result.ActualOutput + "\n" + "\tExpectedOutput: " + result.ExpectedOutput + "\n" + "\tCompilationError: " + result.CompilationError + "\n" + "\tSourceCode: " + solution.SourceCode + "\n\n"); } } }
private static async Task <int> CreateInitialSubmission(string courseId, ExerciseSlide exerciseSlide, string userCode, Language language, string userId, string userName, bool hasAutomaticChecking, SolutionBuildResult buildResult, IServiceScopeFactory serviceScopeFactory) { using (var scope = serviceScopeFactory.CreateScope()) { var userSolutionsRepo = (IUserSolutionsRepo)scope.ServiceProvider.GetService(typeof(IUserSolutionsRepo)); var compilationErrorMessage = buildResult.HasErrors ? buildResult.ErrorMessage : null; var submissionSandbox = (exerciseSlide.Exercise as UniversalExerciseBlock)?.DockerImageName; var automaticCheckingStatus = hasAutomaticChecking ? buildResult.HasErrors ? AutomaticExerciseCheckingStatus.Done : AutomaticExerciseCheckingStatus.Waiting : (AutomaticExerciseCheckingStatus?)null; return(await userSolutionsRepo.AddUserExerciseSubmission( courseId, exerciseSlide.Id, userCode, compilationErrorMessage, null, userId, "uLearn", GenerateSubmissionName(exerciseSlide, userName), language, submissionSandbox, hasAutomaticChecking, automaticCheckingStatus )); } }
public ProjectExerciseValidator(BaseValidator baseValidator, CsSandboxRunnerSettings settings, ExerciseSlide slide, CsProjectExerciseBlock exercise) : base(baseValidator) { this.settings = settings; this.slide = slide; ex = exercise; }
private void ReportIfEthalonSolutionHasErrorsOrIssues(ExerciseSlide slide) { var exercise = (SingleFileExerciseBlock)slide.Exercise; var ethalon = exercise.EthalonSolution.RemoveCommonNesting(); var solution = exercise.BuildSolution(ethalon); if (solution.HasErrors) { FailOnError(slide, solution, ethalon); return; } if (solution.HasStyleErrors) { var errorMessages = string.Join("\n", solution.StyleErrors.Select(e => e.GetMessageWithPositions())); ReportSlideWarning(slide, "Style issue(s): " + errorMessages); } var result = SandboxRunner.Run(exercise.CreateSubmission(slide.Id.ToString(), ethalon), settings); var output = result.GetOutput().NormalizeEoln(); var isRightAnswer = output.NormalizeEoln().Equals(slide.Exercise.ExpectedOutput.NormalizeEoln()); if (!isRightAnswer) { ReportSlideError(slide, "Ethalon solution does not provide right answer\n" + "ActualOutput: " + output.NormalizeEoln() + "\n" + "ExpectedOutput: " + slide.Exercise.ExpectedOutput.NormalizeEoln() + "\n" + "CompilationError: " + result.CompilationOutput + "\n" + "SourceCode: " + solution.SourceCode + "\n\n"); } }
public UniversalExerciseValidator(BaseValidator baseValidator, DockerSandboxRunnerSettings settings, ExerciseSlide slide, UniversalExerciseBlock exercise) : base(baseValidator) { this.settings = settings; this.slide = slide; ex = exercise; }
public ExerciseScoreFormModel(string courseId, ExerciseSlide slide, ManualExerciseChecking checking, List <string> groupsIds = null, bool isCurrentSubmissionChecking = false) { CourseId = courseId; Slide = slide; Checking = checking; GroupsIds = groupsIds; IsCurrentSubmissionChecking = isCurrentSubmissionChecking; }
public static string ValidateExerciseSlide(ExerciseSlide slide) { var valOut = new StringBuilder(); var val = BuildValidator(slide, valOut); val.ValidateExercises(); return(valOut.ToString()); }
private void FailOnError(ExerciseSlide slide, SolutionBuildResult solution, string ethalonSolution) { ReportSlideError(slide, $@"ETHALON SOLUTION: {ethalonSolution} SOURCE CODE: {solution.SourceCode} ERROR: {solution.ErrorMessage}"); }
private async Task<HintWithLikeButton[]> GetNewHintHtml(ExerciseSlide exerciseSlide, string courseId, bool isNeedNewHint) { var usedHintsCount = slideHintRepo.GetUsedHintsCount(courseId, exerciseSlide.Id, User.Identity.GetUserId()); if (usedHintsCount < exerciseSlide.Exercise.HintsMd.Count) return await RenderHtmlWithHint(exerciseSlide, isNeedNewHint ? usedHintsCount : usedHintsCount - 1, courseId); if (isNeedNewHint) return null; return await RenderHtmlWithHint(exerciseSlide, usedHintsCount - 1, courseId); }
public static CourseValidator BuildValidator(ExerciseSlide slide, StringBuilder valOut) { var v = new CourseValidator(new List <Slide> { slide }); v.Warning += msg => { valOut.Append(msg); }; v.Error += msg => { valOut.Append(msg); }; return(v); }
public static string GetExerciseMetricId(string courseId, ExerciseSlide exerciseSlide) { var slideTitleForMetric = exerciseSlide.LatinTitle.Replace(".", "_").ToLower(CultureInfo.InvariantCulture); if (slideTitleForMetric.Length > 25) { slideTitleForMetric = slideTitleForMetric.Substring(0, 25); } return($"{courseId.ToLower(CultureInfo.InvariantCulture)}.{exerciseSlide.Id.ToString("N").Substring(32 - 25)}.{slideTitleForMetric}"); }
private async Task<HintWithLikeButton[]> RenderHtmlWithHint(ExerciseSlide exerciseSlide, int hintsCount, string courseId) { var ans = new HintWithLikeButton[hintsCount + 1]; for (var i = 0; i <= hintsCount; i++) { var isLiked = slideHintRepo.IsHintLiked(courseId, exerciseSlide.Id, User.Identity.GetUserId(), i); ans[i] = await MakeExerciseHint(exerciseSlide.Exercise.HintsMd[i].RenderMd(exerciseSlide.Info.SlideFile), i, courseId, exerciseSlide.Id, isLiked); } return ans; }
public ExerciseBlockData(string courseId, ExerciseSlide slide, bool isSkipped = true, string solution = null) { CourseId = courseId; Slide = slide; Solution = solution; CanSkip = !isSkipped && Solution == null; IsGuest = true; ReviewState = ExerciseReviewState.NotReviewed; Submissions = new List <UserExerciseSubmission>(); TopUserReviewComments = new List <string>(); }
public ExerciseScoreFormModel(string courseId, ExerciseSlide slide, ManualExerciseChecking checking, int manualCheckingsLeft, List <string> groupsIds = null, bool isCurrentSubmissionChecking = false, bool defaultProhibitFutherReview = true) { CourseId = courseId; Slide = slide; Checking = checking; ManualCheckingsLeft = manualCheckingsLeft; GroupsIds = groupsIds; IsCurrentSubmissionChecking = isCurrentSubmissionChecking; DefaultProhibitFutherReview = defaultProhibitFutherReview; }
public ExerciseBlockData(string courseId, ExerciseSlide slide, bool isSkipped = true, string solution = null) { CourseId = courseId; Slide = slide; Solution = solution; CanSkip = !isSkipped && Solution == null; IsGuest = true; ReviewState = ExerciseReviewState.NotReviewed; Submissions = new List<UserExerciseSubmission>(); TopUserReviewComments = new List<string>(); }
private async Task <HintWithLikeButton[]> RenderHtmlWithHint(ExerciseSlide exerciseSlide, int hintsCount, string courseId) { hintsCount = Math.Min(hintsCount, exerciseSlide.Exercise.HintsMd.Count - 1); var ans = new HintWithLikeButton[hintsCount + 1]; for (var i = 0; i <= hintsCount; i++) { var isLiked = slideHintRepo.IsHintLiked(courseId, exerciseSlide.Id, User.Identity.GetUserId(), i); ans[i] = await MakeExerciseHint(exerciseSlide.Exercise.HintsMd[i].RenderMd(exerciseSlide.Info.SlideFile), i, courseId, exerciseSlide.Id, isLiked); } return(ans); }
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 ); if (submission == null) { log.Error($"Не смог запустить проверку решения, никто не взял его на проверку.\nКурс: {courseId}, слайд «{exerciseSlide.Title}» ({exerciseSlide.Id})"); return new RunSolutionResult { IsCompillerFailure = true, ErrorMessage = "Ой-ой, штуковина, которая проверяет решения, сломалась (или просто устала).\nПопробуйте отправить решение позже — когда она немного отдохнет.", ExecutionServiceName = "uLearn" }; } var course = courseManager.GetCourse(courseId); 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.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, }; }
private async Task <RunSolutionResult> CheckSolution(string courseId, ExerciseSlide exerciseSlide, string code) { var exerciseBlock = exerciseSlide.Exercise; var solution = exerciseBlock.Solution.BuildSolution(code); if (solution.HasErrors) { return new RunSolutionResult { IsCompileError = true, CompilationError = solution.ErrorMessage, ExecutionServiceName = "uLearn" } } ; if (solution.HasStyleIssues) { return new RunSolutionResult { IsStyleViolation = true, CompilationError = solution.StyleMessage, ExecutionServiceName = "uLearn" } } ; var submissionDetails = await solutionsRepo.RunUserSolution( courseId, exerciseSlide.Id, User.Identity.GetUserId(), code, null, null, false, "uLearn", GenerateSubmissionName(exerciseSlide), executionTimeout ); if (submissionDetails == null) { return new RunSolutionResult { IsCompillerFailure = true, CompilationError = "Ой-ой, штуковина, которая проверяет решения сломалась (или просто устала). Попробуйте отправить решение позже (когда она немного отдохнет).", ExecutionServiceName = "uLearn" } } ; var output = submissionDetails.Output.Text; var expectedOutput = exerciseBlock.ExpectedOutput.NormalizeEoln(); var isRightAnswer = submissionDetails.GetVerdict() == "Accepted" && output.Equals(expectedOutput); await visitsRepo.AddSolutionAttempt(exerciseSlide.Id, User.Identity.GetUserId(), isRightAnswer); return(new RunSolutionResult { IsCompileError = submissionDetails.IsCompilationError, CompilationError = submissionDetails.CompilationError.Text, IsRightAnswer = isRightAnswer, ExpectedOutput = exerciseBlock.HideExpectedOutputOnError ? null : expectedOutput, ActualOutput = output, ExecutionServiceName = submissionDetails.ExecutionServiceName }); }
private ExerciseBlockData CreateAcceptedAlertModel(ExerciseSlide slide, Course course) { var userId = User.Identity.GetUserId(); var isSkippedOrPassed = visitsRepo.IsSkippedOrPassed(course.Id, slide.Id, userId); /* TODO: It's not necessary to create ExerciseBlockData here */ var model = new ExerciseBlockData(course.Id, slide, isSkippedOrPassed) { CourseId = course.Id, IsGuest = !User.Identity.IsAuthenticated, Url = Url, }; return(model); }
private async Task <HintWithLikeButton[]> GetNewHintHtml(ExerciseSlide exerciseSlide, string courseId, bool isNeedNewHint) { var usedHintsCount = slideHintRepo.GetUsedHintsCount(courseId, exerciseSlide.Id, User.Identity.GetUserId()); if (usedHintsCount < exerciseSlide.Exercise.HintsMd.Count) { return(await RenderHtmlWithHint(exerciseSlide, isNeedNewHint?usedHintsCount : usedHintsCount - 1, courseId)); } if (isNeedNewHint) { return(null); } return(await RenderHtmlWithHint(exerciseSlide, usedHintsCount - 1, courseId)); }
private async Task<RunSolutionResult> CheckSolution(string courseId, ExerciseSlide exerciseSlide, string code) { var exerciseBlock = exerciseSlide.Exercise; var solution = exerciseBlock.Solution.BuildSolution(code); if (solution.HasErrors) return new RunSolutionResult { IsCompileError = true, CompilationError = solution.ErrorMessage, ExecutionServiceName = "uLearn" }; if (solution.HasStyleIssues) return new RunSolutionResult { IsStyleViolation = true, CompilationError = solution.StyleMessage, ExecutionServiceName = "uLearn" }; var submissionDetails = await solutionsRepo.RunUserSolution( courseId, exerciseSlide.Id, User.Identity.GetUserId(), code, null, null, false, "uLearn", GenerateSubmissionName(exerciseSlide), executionTimeout ); if (submissionDetails == null) return new RunSolutionResult { IsCompillerFailure = true, CompilationError = "Ой-ой, штуковина, которая проверяет решения сломалась (или просто устала). Попробуйте отправить решение позже (когда она немного отдохнет).", ExecutionServiceName = "uLearn" }; var output = submissionDetails.Output.Text; var expectedOutput = exerciseBlock.ExpectedOutput.NormalizeEoln(); var isRightAnswer = submissionDetails.GetVerdict() == "Accepted" && output.Equals(expectedOutput); await visitersRepo.AddSolutionAttempt(exerciseSlide.Id, User.Identity.GetUserId(), isRightAnswer); return new RunSolutionResult { IsCompileError = submissionDetails.IsCompilationError, CompilationError = submissionDetails.CompilationError.Text, IsRightAnswer = isRightAnswer, ExpectedOutput = exerciseBlock.HideExpectedOutputOnError ? null : expectedOutput, ActualOutput = output, ExecutionServiceName = submissionDetails.ExecutionServiceName }; }
public static (int Score, int?Percent) GetExerciseSubmissionManualCheckingsScoreAndPercent(IList <ManualExerciseChecking> manualCheckings, ExerciseSlide slide) { var checkedScoresAndPercents = manualCheckings .Where(c => c.IsChecked) .OrderBy(c => c.Timestamp) .Select(c => (c.Score, c.Percent)) .ToList(); return(GetScoreAndPercentByScoresAndPercents(slide, checkedScoresAndPercents)); }
private static (int Score, int?Percent) GetScoreAndPercentByScoresAndPercents( ExerciseSlide slide, List <(int?Score, int?Percent)> checkedScoresAndPercents)
private async Task <AcceptedSolutionsPageModel> CreateAcceptedSolutionsModel(Course course, ExerciseSlide slide, bool isLti) { var userId = User.Identity.GetUserId(); var isPassed = visitsRepo.IsPassed(course.Id, slide.Id, userId); if (!isPassed) { await visitsRepo.SkipSlide(course.Id, slide.Id, userId); } var submissions = solutionsRepo.GetBestTrendingAndNewAcceptedSolutions(course.Id, slide.Id); foreach (var submission in submissions) { submission.LikedAlready = submission.UsersWhoLike.Any(u => u == userId); submission.RemoveSolutionUrl = Url.Action("RemoveSubmission", "Course", new { course.Id, slideId = slide.Id, submissionId = submission.Id }); } var model = new AcceptedSolutionsPageModel { CourseId = course.Id, CourseTitle = course.Title, Slide = slide, AcceptedSolutions = submissions, User = User, LikeSolutionUrl = Url.Action("LikeSolution"), IsLti = isLti, IsPassed = isPassed }; return(model); }
public (int Score, int?Percent) GetExerciseSlideScoreAndPercent(string courseId, ExerciseSlide slide, string userId) { var isRightAnswer = GetSlideCheckingsByUser <AutomaticExerciseChecking>(courseId, slide.Id, userId) .Any(c => c.IsRightAnswer); if (!isRightAnswer) { return(0, null); } var checkedScoresAndPercents = GetCheckedScoresAndPercents(courseId, slide, userId, null); var automaticScore = slide.Scoring.PassedTestsScore; if (checkedScoresAndPercents.Count == 0) { return(automaticScore, null); } return(GetScoreAndPercentByScoresAndPercents(slide, checkedScoresAndPercents)); }
private async Task <RunSolutionResponse> CheckSolution(string courseId, ExerciseSlide exerciseSlide, string userCode, Language language, string userId, string userName, bool waitUntilChecked, bool saveSubmissionOnCompileErrors ) { var exerciseMetricId = 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 (buildResult.HasStyleErrors) { metricSender.SendCount($"exercise.{exerciseMetricId}.StyleViolation"); } if (!saveSubmissionOnCompileErrors) { if (buildResult.HasErrors) { return new RunSolutionResponse(SolutionRunStatus.CompilationError) { Message = buildResult.ErrorMessage } } ; } var compilationErrorMessage = buildResult.HasErrors ? buildResult.ErrorMessage : null; var submissionSandbox = (exerciseBlock as UniversalExerciseBlock)?.DockerImageName; var hasAutomaticChecking = exerciseBlock.HasAutomaticChecking(); var automaticCheckingStatus = hasAutomaticChecking ? buildResult.HasErrors ? AutomaticExerciseCheckingStatus.Done : AutomaticExerciseCheckingStatus.Waiting : (AutomaticExerciseCheckingStatus?)null; var initialSubmission = await userSolutionsRepo.AddUserExerciseSubmission( courseId, exerciseSlide.Id, userCode, compilationErrorMessage, null, userId, "uLearn", GenerateSubmissionName(exerciseSlide, userName), language, submissionSandbox, hasAutomaticChecking, automaticCheckingStatus ); var isCourseAdmin = await courseRolesRepo.HasUserAccessToCourseAsync(userId, courseId, CourseRoleType.CourseAdmin); if (buildResult.HasErrors) { return new RunSolutionResponse(SolutionRunStatus.Success) { Submission = SubmissionInfo.Build(initialSubmission, null, isCourseAdmin) } } ; var executionTimeout = TimeSpan.FromSeconds(exerciseBlock.TimeLimit * 2 + 5); UserExerciseSubmission updatedSubmissionNoTracking; try { if (hasAutomaticChecking) { var priority = exerciseBlock is SingleFileExerciseBlock ? 10 : 0; await userSolutionsRepo.RunAutomaticChecking(initialSubmission, 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"); updatedSubmissionNoTracking = await userSolutionsRepo.FindSubmissionByIdNoTracking(initialSubmission.Id); var message = updatedSubmissionNoTracking.AutomaticChecking.Status == AutomaticExerciseCheckingStatus.Running ? "Решение уже проверяется." : "Решение ждет своей очереди на проверку, мы будем пытаться проверить его еще 10 минут."; return(new RunSolutionResponse(SolutionRunStatus.SubmissionCheckingTimeout) { Message = $"К сожалению, мы не смогли оперативно проверить ваше решение. {message}. Просто подождите и обновите страницу.", Submission = SubmissionInfo.Build(updatedSubmissionNoTracking, null, isCourseAdmin) }); } if (!waitUntilChecked) { metricSender.SendCount($"exercise.{exerciseMetricId}.dont_wait_result"); // По вовзращаемому значению нельзя отличить от случая, когда никто не взял на проверку return(new RunSolutionResponse(SolutionRunStatus.Success) { Submission = SubmissionInfo.Build(initialSubmission, null, isCourseAdmin) }); } updatedSubmissionNoTracking = await userSolutionsRepo.FindSubmissionByIdNoTracking(initialSubmission.Id); updatedSubmissionNoTracking.Reviews = await CreateStyleErrorsReviewsForSubmission(updatedSubmissionNoTracking.Id, buildResult.StyleErrors, exerciseMetricId); if (!hasAutomaticChecking) { await SendToReviewAndUpdateScore(updatedSubmissionNoTracking, courseManager, slideCheckingsRepo, groupsRepo, visitsRepo, metricSender); } var score = await visitsRepo.GetScore(courseId, exerciseSlide.Id, userId); var waitingForManualChecking = updatedSubmissionNoTracking.ManualCheckings.Any(c => !c.IsChecked) ? true : (bool?)null; var prohibitFurtherManualChecking = updatedSubmissionNoTracking.ManualCheckings.Any(c => c.ProhibitFurtherManualCheckings); var result = new RunSolutionResponse(SolutionRunStatus.Success) { Score = score, WaitingForManualChecking = waitingForManualChecking, ProhibitFurtherManualChecking = prohibitFurtherManualChecking, Submission = SubmissionInfo.Build(updatedSubmissionNoTracking, null, isCourseAdmin) }; return(result); }
public void TestSlides(ExerciseSlide slide, IExecutionService ideoneClient) { TestExerciseSlide(slide, ideoneClient); }
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); }
public Solution(ExerciseSlide slide, UserSolution solution) { Id = solution.Id; UserCode = GetText(solution.SolutionCode); Code = slide.Exercise.Solution.BuildSolution(UserCode).SourceCode; IsCompilationError = solution.IsCompilationError; CompilationError = GetText(solution.CompilationError); ActualOutput = GetText(solution.Output); IsRightAnswer = solution.IsRightAnswer; ExpectedOutput = slide.Exercise.ExpectedOutput.NormalizeEoln(); }
public async Task <(int Score, int?Percent)> GetExerciseSlideScoreAndPercent(string courseId, ExerciseSlide slide, string userId) { var hasAutomaticChecking = slide.Exercise.HasAutomaticChecking(); if (hasAutomaticChecking) { var isRightAnswer = await GetSlideCheckingsByUser <AutomaticExerciseChecking>(courseId, slide.Id, userId) .AnyAsync(c => c.IsRightAnswer); if (!isRightAnswer) { return(0, null); } } var checkedScoresAndPercents = await GetCheckedScoresAndPercents(courseId, slide, userId, null); var automaticScore = slide.Scoring.PassedTestsScore; if (checkedScoresAndPercents.Count == 0) { return(automaticScore, null); } return(GetScoreAndPercentByScoresAndPercents(slide, checkedScoresAndPercents)); }
public ExerciseControlsModel(string courseId, ExerciseSlide slide) { CourseId = courseId; Slide = slide; }
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); }
protected async Task <RunSolutionResult> CheckSolution(string courseId, ExerciseSlide exerciseSlide, string userCode, string userId, string userName, bool waitUntilChecked, bool saveSubmissionOnCompileErrors) { var exerciseMetricId = GetExerciseMetricId(courseId, exerciseSlide); 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 = exerciseBlock.Language.Value; var submissionSandbox = (exerciseBlock as UniversalExerciseBlock)?.DockerImageName; var submission = await userSolutionsRepo.AddUserExerciseSubmission( courseId, exerciseSlide.Id, userCode, compilationErrorMessage, null, userId, "uLearn", GenerateSubmissionName(exerciseSlide, userName), submissionLanguage, submissionSandbox, dontRunSubmission?AutomaticExerciseCheckingStatus.Done : AutomaticExerciseCheckingStatus.Waiting ); if (buildResult.HasErrors) { return new RunSolutionResult { IsCompileError = true, ErrorMessage = buildResult.ErrorMessage, SubmissionId = submission.Id, ExecutionServiceName = "uLearn" } } ; var hasAutomaticChecking = exerciseBlock.HasAutomaticChecking(); var executionTimeout = TimeSpan.FromSeconds(exerciseBlock.TimeLimit * 2 + 5); try { if (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); if (submission.AutomaticCheckingIsRightAnswer) { await CreateStyleErrorsReviewsForSubmission(submission, buildResult.StyleErrors, exerciseMetricId); } var automaticChecking = submission.AutomaticChecking; bool sentToReview; if (!hasAutomaticChecking) { sentToReview = await SendToReviewAndUpdateScore(submission, courseManager, slideCheckingsRepo, groupsRepo, visitsRepo, metricSender, true).ConfigureAwait(false); } else { sentToReview = slideCheckingsRepo.HasManualExerciseChecking(courseId, exerciseSlide.Id, userId, submission.Id); } 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 = sentToReview, SubmissionId = submission.Id, }; if (buildResult.HasStyleErrors) { result.IsStyleViolation = true; result.StyleMessage = string.Join("\n", buildResult.StyleErrors.Select(e => e.GetMessageWithPositions())); } return(result); }
public ExerciseScoreFormModel(string courseId, ExerciseSlide slide, ManualExerciseChecking checking, int? groupId = null, bool isCurrentSubmissionChecking = false) { CourseId = courseId; Slide = slide; Checking = checking; GroupId = groupId; IsCurrentSubmissionChecking = isCurrentSubmissionChecking; }
public void TestSlides(ExerciseSlide slide, IExecutionService executionService) { TestExerciseSlide(slide, executionService); }
public static SubmissionResult FromSolution(ExerciseSolutionByGrader solution, ExerciseSlide slide) { var automaticChecking = solution.Submission?.AutomaticChecking; if (automaticChecking == null || automaticChecking.Status != AutomaticExerciseCheckingStatus.Done) { return new SubmissionResult { Status = "IN_PROCESS" } } ; var score = (double)automaticChecking.Score / slide.Scoring.PassedTestsScore; if (score > 1) { score = 1; } return(new SubmissionResult { Status = "READY", Result = score, CompilationLog = automaticChecking.CompilationError?.Text ?? "", ExecutionLog = automaticChecking.Output?.Text ?? "", }); }
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, }); }