private async Task <bool> TrySendSubmissionResultsToQueue(XQueueClient client, XQueueExerciseSubmission submission)
        {
            var checking = submission.Submission.AutomaticChecking;

            var slide = (await courseManager.FindCourseAsync(checking.CourseId))?.FindSlideById(checking.SlideId, true) as ExerciseSlide;

            if (slide == null)
            {
                log.Warn($"Can't find exercise slide {checking.SlideId} in course {checking.CourseId}. Exit");
                return(false);
            }

            var score = checking.IsRightAnswer ? 1 : 0;

            var message = checking.IsCompilationError ? checking.CompilationError.Text : checking.Output.Text;

            return(await client.PutResult(new XQueueResult
            {
                header = submission.XQueueHeader,
                Body = new XQueueResultBody
                {
                    IsCorrect = checking.IsRightAnswer,
                    Message = message,
                    Score = score,
                }
            }));
        }
        private async Task <RunnerSubmission> ToRunnerSubmission(UserExerciseSubmission submission, IWebCourseManager courseManager)
        {
            log.Info($"Собираю для отправки в RunCsJob решение {submission.Id}");
            var slide = (await courseManager.FindCourseAsync(submission.CourseId))?.FindSlideById(submission.SlideId, true);

            if (slide is ExerciseSlide exerciseSlide)
            {
                log.Info($"Ожидаю, если курс {submission.CourseId} заблокирован");
                courseManager.WaitWhileCourseIsLocked(submission.CourseId);
                log.Info($"Курс {submission.CourseId} разблокирован");

                if (exerciseSlide is PolygonExerciseSlide)
                {
                    return(((PolygonExerciseBlock)exerciseSlide.Exercise).CreateSubmission(
                               submission.Id.ToString(),
                               submission.SolutionCode.Text,
                               submission.Language
                               ));
                }

                return(exerciseSlide.Exercise.CreateSubmission(
                           submission.Id.ToString(),
                           submission.SolutionCode.Text
                           ));
            }

            return(new FileRunnerSubmission
            {
                Id = submission.Id.ToString(),
                Code = "// no slide anymore",
                Input = "",
                NeedRun = true
            });
        }
Example #3
0
        public async Task ProcessResult(UserExerciseSubmission submission, RunningResults result)
        {
            if (result.StyleErrors == null || result.StyleErrors.Count == 0)
            {
                return;
            }

            if (result.Verdict != Verdict.Ok)
            {
                return;
            }

            var checking = submission.AutomaticChecking;

            if (!checking.IsRightAnswer)
            {
                return;
            }

            var exerciseSlide = (await courseManager.FindCourseAsync(submission.CourseId))
                                ?.FindSlideById(submission.SlideId, true) as ExerciseSlide;

            if (exerciseSlide == null)
            {
                return;
            }

            if (ulearnBotUserId == null)
            {
                ulearnBotUserId = await usersRepo.GetUlearnBotUserId();
            }

            var exerciseMetricId = ExerciseController.GetExerciseMetricId(submission.CourseId, exerciseSlide);

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

            foreach (var error in result.StyleErrors)
            {
                await slideCheckingsRepo.AddExerciseCodeReview(
                    submission.Id,
                    ulearnBotUserId,
                    error.Span.StartLinePosition.Line,
                    error.Span.StartLinePosition.Character,
                    error.Span.EndLinePosition.Line,
                    error.Span.EndLinePosition.Character,
                    error.Message
                    );

                var errorName = error.ErrorType;
                metricSender.SendCount("exercise.style_error");
                metricSender.SendCount($"exercise.style_error.{errorName}");
                metricSender.SendCount($"exercise.{exerciseMetricId}.style_error");
                metricSender.SendCount($"exercise.{exerciseMetricId}.style_error.{errorName}");
            }
        }
Example #4
0
        private async Task SendDeliveriesOfOneType(List <NotificationDelivery> deliveries)
        {
            if (deliveries.Count == 0)
            {
                return;
            }

            if (deliveries.Count == 1)
            {
                var delivery = deliveries[0];
                var course   = await courseManager.FindCourseAsync(delivery.Notification.CourseId);

                if (course == null)
                {
                    log.Warn($"Can't find course {delivery.Notification.CourseId}");
                    await notificationsRepo.MarkDeliveryAsFailed(delivery);

                    return;
                }

                try
                {
                    await notificationSender.Send(delivery);

                    await notificationsRepo.MarkDeliveryAsSent(delivery.Id);
                }
                catch (Exception e)
                {
                    log.Warn(e, $"Can\'t send notification {delivery.NotificationId} to {delivery.NotificationTransport}. Will try later");
                    await notificationsRepo.MarkDeliveryAsFailed(delivery);
                }
            }
            else
            {
                try
                {
                    await notificationSender.Send(deliveries);

                    await notificationsRepo.MarkDeliveriesAsSent(deliveries.Select(d => d.Id).ToList());
                }
                catch (Exception e)
                {
                    log.Warn(e, $"Can\'t send multiple notifications [{string.Join(", ", deliveries.Select(d => d.NotificationId))}] to {deliveries[0].NotificationTransport}. Will try later");
                    await notificationsRepo.MarkDeliveriesAsFailed(deliveries);
                }
            }
        }
Example #5
0
        public async Task <bool> IsCourseVisibleForStudentsAsync(string courseId)
        {
            if (await courseManager.FindCourseAsync(courseId) == null)
            {
                return(false);
            }
            var visibleUnitsIds = await db.UnitAppearances
                                  .Where(u => u.CourseId == courseId)
                                  .Where(u => u.PublishTime <= DateTime.Now)
                                  .Select(u => u.UnitId)
                                  .ToListAsync();

            var units = (await courseManager.GetCourseAsync(courseId)).GetUnitsNotSafe().Select(u => u.Id).ToHashSet();

            units.IntersectWith(visibleUnitsIds);
            return(units.Any());
        }
Example #6
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, "Мы не смогли отправить баллы на образовательную платформу");
                }
            }
        }
Example #7
0
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            // Specify a default argument name if none is set by ModelBinderAttribute
            var modelName = bindingContext.BinderModelName;

            if (string.IsNullOrEmpty(modelName))
            {
                modelName = "courseId";
            }

            // Try to fetch the value of the argument by name
            var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

            if (valueProviderResult == ValueProviderResult.None)
            {
                return;
            }

            bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
            var value = valueProviderResult.FirstValue;

            // Check if the argument value is null or empty
            if (string.IsNullOrEmpty(value))
            {
                return;
            }

            var model = await courseManager.FindCourseAsync(value);

            if (model == null)
            {
                bindingContext.ModelState.TryAddModelError(modelName, $"Course {value} not found");
            }
            bindingContext.Result = model == null?ModelBindingResult.Failed() : ModelBindingResult.Success(model);
        }
Example #8
0
        public async Task ProcessResult(UserExerciseSubmission submission, RunningResults result)
        {
            if (result.StyleErrors == null || result.StyleErrors.Count == 0)
            {
                return;
            }

            if (result.Verdict != Verdict.Ok)
            {
                return;
            }

            var checking = submission.AutomaticChecking;

            if (!checking.IsRightAnswer)
            {
                return;
            }

            var exerciseSlide = (await courseManager.FindCourseAsync(submission.CourseId))
                                ?.FindSlideById(submission.SlideId, true) as ExerciseSlide;

            if (exerciseSlide == null)
            {
                return;
            }

            if (ulearnBotUserId == null)
            {
                ulearnBotUserId = await usersRepo.GetUlearnBotUserId();
            }

            var exerciseMetricId = RunnerSetResultController.GetExerciseMetricId(submission.CourseId, exerciseSlide);

            await CreateStyleErrorsReviewsForSubmission(submission.Id, result.StyleErrors, exerciseMetricId);
        }
Example #9
0
        private async Task CreateDeliveriesForNotification(Notification notification)
        {
            var notificationType = notification.GetNotificationType();

            log.Info($"Found new notification {notificationType} #{notification.Id}");

            if (!notification.IsActual())
            {
                log.Info($"Notification #{notification.Id}: is not actual more");
                return;
            }

            var blockerNotifications = await notification.GetBlockerNotifications(serviceProvider);

            if (blockerNotifications.Count > 0)
            {
                log.Info(
                    $"There are blocker notifications (this one will not be send if blocker notifications has been already sent to the same transport): " +
                    $"{string.Join(", ", blockerNotifications.Select(n => $"{n.GetNotificationType()} #{n.Id}"))}"
                    );
            }

            Course course = null;

            if (!string.IsNullOrWhiteSpace(notification.CourseId))
            {
                course = await courseManager.FindCourseAsync(notification.CourseId);

                if (course == null)
                {
                    return;
                }
            }

            var recipientsIds = (await notification.GetRecipientsIdsAsync(serviceProvider, course)).ToHashSet();

            recipientsIds = await FilterUsersWhoNotSeeCourse(notification, recipientsIds);

            log.Info($"Recipients list for notification {notification.Id}: {recipientsIds.Count} user(s)");

            if (recipientsIds.Count == 0)
            {
                return;
            }

            var transportsSettings = db.NotificationTransportSettings
                                     .Include(s => s.NotificationTransport)
                                     .Where(s => s.CourseId == notification.CourseId &&
                                            s.NotificationType == notificationType &&
                                            !s.NotificationTransport.IsDeleted &&
                                            recipientsIds.Contains(s.NotificationTransport.UserId)).ToList();

            var commonTransports = db.NotificationTransports.Where(t => t.UserId == null && t.IsEnabled).ToList();

            var isEnabledByDefault = notificationType.IsEnabledByDefault();

            if (isEnabledByDefault)
            {
                log.Info($"Notification #{notification.Id}. This notification type is enabled by default, so collecting data for it");

                var recipientsTransports = db.NotificationTransports.Where(
                    t => recipientsIds.Contains(t.UserId) &&
                    !t.IsDeleted &&
                    t.IsEnabled
                    ).ToList();
                var notFoundTransports = recipientsTransports.Except(transportsSettings.Select(c => c.NotificationTransport), new NotificationTransportIdComparer());

                foreach (var transport in notFoundTransports)
                {
                    transportsSettings.Add(new NotificationTransportSettings
                    {
                        IsEnabled               = true,
                        NotificationTransport   = transport,
                        NotificationTransportId = transport.Id,
                    });
                }
            }
            else if (notification.IsNotificationForEveryone)
            {
                /* Add notification to all common transports */
                /* It's used for notifications which should be sent to everyone in the course */
                log.Info($"Notification #{notification.Id}. This notification type is sent to everyone, so add it to all common transports ({commonTransports.Count} transport(s)):");
                foreach (var commonTransport in commonTransports)
                {
                    log.Info($"Common transport {commonTransport}");
                    transportsSettings.Add(new NotificationTransportSettings
                    {
                        IsEnabled               = true,
                        NotificationTransport   = commonTransport,
                        NotificationTransportId = commonTransport.Id,
                    });
                }
            }

            var blockerNotificationsSentToTransports = new HashSet <int>(
                GetNotificationsDeliveries(blockerNotifications.Select(n => n.Id), transportsSettings.Select(s => s.NotificationTransportId))
                .Select(d => d.NotificationTransportId)
                );

            if (blockerNotificationsSentToTransports.Count > 0)
            {
                log.Info(
                    "Blocked notifications have been already sent to follow transports:" +
                    $"{string.Join(", ", blockerNotificationsSentToTransports)}"
                    );
            }

            var now = DateTime.Now;

            foreach (var transportSettings in transportsSettings)
            {
                log.Info($"Notification #{notification.Id}: add delivery to {transportSettings.NotificationTransport}, isEnabled: {transportSettings.IsEnabled}");
                if (!transportSettings.IsEnabled)
                {
                    continue;
                }

                if (!transportSettings.NotificationTransport.IsEnabled)
                {
                    log.Info($"Transport {transportSettings.NotificationTransport} is fully disabled, ignore it");
                    continue;
                }

                /* Always ignore to send notification to user initiated this notification */
                if (transportSettings.NotificationTransport.UserId == notification.InitiatedById)
                {
                    log.Info($"Don't sent notification to the transport {transportSettings.NotificationTransport} because it has been initiated by this user");
                    continue;
                }

                if (blockerNotificationsSentToTransports.Contains(transportSettings.NotificationTransportId))
                {
                    log.Info($"Some blocker notification already has been sent to transport {transportSettings.NotificationTransport}, ignore it");
                    continue;
                }

                log.Info($"Notification #{notification.Id}: add delivery to {transportSettings.NotificationTransport}, sending at {now}");
                db.NotificationDeliveries.Add(new NotificationDelivery
                {
                    Notification            = notification,
                    NotificationTransportId = transportSettings.NotificationTransportId,
                    CreateTime  = now,
                    NextTryTime = now,
                    FailsCount  = 0,
                    Status      = NotificationDeliveryStatus.NotSent,
                });
            }
        }