public async Task SendDeliveriesOfOneType(NotificationTransport transport, NotificationType notificationType, List <NotificationDelivery> deliveries) { if (deliveries.Count == 0) { return; } if (deliveries.Count == 1) { var delivery = deliveries[0]; var course = courseManager.FindCourse(delivery.Notification.CourseId); if (course == null) { log.Warn($"Can't find course {delivery.Notification.CourseId}"); await notificationsRepo.MarkDeliveryAsFailed(delivery); return; } try { await notificationSender.SendAsync(delivery); await notificationsRepo.MarkDeliveryAsSent(delivery.Id); } catch (Exception e) { log.Warn($"Can\'t send notification {delivery.NotificationId} to {delivery.NotificationTransport}: {e}. Will try later"); await notificationsRepo.MarkDeliveryAsFailed(delivery); } } else { try { await notificationSender.SendAsync(deliveries); await notificationsRepo.MarkDeliveriesAsSent(deliveries.Select(d => d.Id).ToList()); } catch (Exception e) { log.Warn($"Can\'t send multiple notifications [{string.Join(", ", deliveries.Select(d => d.NotificationId))}] to {deliveries[0].NotificationTransport}: {e}. Will try later"); await notificationsRepo.MarkDeliveriesAsFailed(deliveries); } } }
public HashSet <string> GetVisibleCourses() { var appearances = db.UnitAppearances .Where(u => u.PublishTime <= DateTime.Now) .Select(u => new { u.CourseId, u.UnitId }) .AsEnumerable() .GroupBy(p => p.CourseId) .Where(g => courseManager.FindCourse(g.Key) != null) .Where(g => { var units = courseManager.GetCourse(g.Key).GetUnitsNotSafe().Select(u => u.Id).ToHashSet(); units.IntersectWith(g.Select(p => p.UnitId)); return(units.Any()); }) .Select(g => g.Key); return(new HashSet <string>(appearances, StringComparer.OrdinalIgnoreCase)); }
public 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(Task.CompletedTask); } bindingContext.ModelState.SetModelValue(modelName, valueProviderResult); var value = valueProviderResult.FirstValue; // Check if the argument value is null or empty if (string.IsNullOrEmpty(value)) { return(Task.CompletedTask); } var model = courseManager.FindCourse(value); if (model == null) { bindingContext.ModelState.TryAddModelError(modelName, $"Course {value} not found"); } bindingContext.Result = model == null?ModelBindingResult.Failed() : ModelBindingResult.Success(model); return(Task.CompletedTask); }
public async Task <UserExerciseSubmission> AddUserExerciseSubmission( string courseId, Guid slideId, string code, string compilationError, string output, string userId, string executionServiceName, string displayName, Language language, string sandbox, AutomaticExerciseCheckingStatus status = AutomaticExerciseCheckingStatus.Waiting) { if (string.IsNullOrWhiteSpace(code)) { code = "// no code"; } var hash = (await textsRepo.AddText(code)).Hash; var compilationErrorHash = (await textsRepo.AddText(compilationError)).Hash; var outputHash = (await textsRepo.AddText(output)).Hash; var exerciseBlock = (courseManager.FindCourse(courseId)?.FindSlideById(slideId, true) as ExerciseSlide)?.Exercise; AutomaticExerciseChecking automaticChecking; if (exerciseBlock != null && exerciseBlock.HasAutomaticChecking()) { automaticChecking = new AutomaticExerciseChecking { CourseId = courseId, SlideId = slideId, UserId = userId, Timestamp = DateTime.Now, CompilationErrorHash = compilationErrorHash, IsCompilationError = !string.IsNullOrWhiteSpace(compilationError), OutputHash = outputHash, ExecutionServiceName = executionServiceName, DisplayName = displayName, Status = status, IsRightAnswer = false, }; db.AutomaticExerciseCheckings.Add(automaticChecking); } else { automaticChecking = null; } var submission = new UserExerciseSubmission { CourseId = courseId, SlideId = slideId, UserId = userId, Timestamp = DateTime.Now, SolutionCodeHash = hash, CodeHash = code.Split('\n').Select(x => x.Trim()).Aggregate("", (x, y) => x + y).GetHashCode(), Likes = new List <Like>(), AutomaticChecking = automaticChecking, AutomaticCheckingIsRightAnswer = automaticChecking?.IsRightAnswer ?? true, Language = language, Sandbox = sandbox }; db.UserExerciseSubmissions.Add(submission); await db.SaveChangesAsync(); return(submission); }
private void CreateDeliviesForNotification(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 = notification.GetBlockerNotifications(db); 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 = courseManager.FindCourse(notification.CourseId); if (course == null) { return; } } var recipientsIds = notification.GetRecipientsIds(db, course).ToHashSet(); recipientsIds = FilterUsersWhoNotSeeCourse(notification, recipientsIds); log.Info($"Recipients list for notification {notification.Id}: {recipientsIds.Count} user(s)"); if (recipientsIds.Count == 0) { return; } if (recipientsIds.Count > 1000) { log.Warn($"Recipients list for notification is too big {notification.Id}: {recipientsIds.Count} user(s)"); } var transportsSettings = recipientsIds.Count > 1000 ? db.NotificationTransportSettings .Include(s => s.NotificationTransport) .Where(s => s.CourseId == notification.CourseId && s.NotificationType == notificationType && !s.NotificationTransport.IsDeleted) .ToList() .Where(s => recipientsIds.Contains(s.NotificationTransport.UserId)) .ToList() : 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 i.e. for new-comment notification 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, }); } }
public async Task <ActionResult> SlideById(string courseId, string slideId = "", int?checkQueueItemId = null, int?version = null, int autoplay = 0) { if (slideId.Contains("_")) { slideId = slideId.Substring(slideId.LastIndexOf('_') + 1); } // По крайней мере одно из мест использования groupsIds: переход на следующее ревью после выполнения предыдущего. var groupsIds = Request.GetMultipleValuesFromQueryString("group"); if (!Guid.TryParse(slideId, out var slideGuid)) { return(HttpNotFound()); } if (string.IsNullOrWhiteSpace(courseId)) { return(RedirectToAction("Index", "Home")); } var course = courseManager.FindCourse(courseId); if (course == null) { return(HttpNotFound()); } var visibleUnitIds = unitsRepo.GetVisibleUnitIds(course, User); var visibleUnits = course.GetUnits(visibleUnitIds); var isGuest = !User.Identity.IsAuthenticated; var isInstructor = !isGuest && User.HasAccessFor(course.Id, CourseRole.Instructor); var slide = slideGuid == Guid.Empty ? GetInitialSlideForStartup(courseId, visibleUnits, isInstructor) : course.FindSlideById(slideGuid, isInstructor); if (slide == null) { var instructorNote = course.FindInstructorNoteById(slideGuid); if (instructorNote != null && isInstructor) { slide = instructorNote.Slide; } } if (slide == null) { return(HttpNotFound()); } AbstractManualSlideChecking queueItem = null; var isManualCheckingReadonly = false; if (User.HasAccessFor(courseId, CourseRole.Instructor) && checkQueueItemId != null) { if (slide is QuizSlide) { queueItem = slideCheckingsRepo.FindManualCheckingById <ManualQuizChecking>(checkQueueItemId.Value); } if (slide is ExerciseSlide) { queueItem = slideCheckingsRepo.FindManualCheckingById <ManualExerciseChecking>(checkQueueItemId.Value); } if (queueItem == null) { /* It's possible when checking has not been fully checked, lock has been released, but after it user re-send his solution and we removed old waiting checking */ var fakeQueueItem = slide is QuizSlide ? (AbstractManualSlideChecking) new ManualQuizChecking() : new ManualExerciseChecking(); return(RedirectToAction("CheckingQueue", "Admin", new { courseId = courseId, message = "checking_removed" })); } } var model = isGuest ? CreateGuestCoursePageModel(course, slide, autoplay > 0) : await CreateCoursePageModel(course, slide, queueItem, version, groupsIds, autoplay > 0, isManualCheckingReadonly); if (!string.IsNullOrEmpty(Request.QueryString["error"])) { model.Error = Request.QueryString["error"]; } if (!visibleUnits.Contains(model.Slide.Info.Unit)) { return(HttpNotFound("Slide is hidden " + slideGuid)); } return(View("Slide", model)); }