/// <summary> /// Removes the calling user from the specified selected course. /// If after the removal no other user has selected the course, /// the course is removed from the schedule. /// </summary> /// <remarks> /// If the user has not selected the course with the specified ID, /// nothing happens. /// </remarks> /// <param name="courseId">Course ID</param> /// <returns></returns> public async Task RemoveUserFromCourse(string courseId, bool acquireSemaphore = true) { using (var errorReporter = new ErrorReporter(s => CallingClient.Errors.ScheduleMessage = s)) { if (PaulRepository.Courses.All(c => c.Id != courseId)) { errorReporter.Throw( new ArgumentException("Course not found", nameof(courseId)), UserErrorsViewModel.GenericErrorMessage); } var schedule = CallingClient.SharedScheduleVM.Schedule; var selectedCourse = schedule.SelectedCourses .FirstOrDefault(c => c.CourseId == courseId); if (selectedCourse == null) { errorReporter.Throw( new ArgumentException("Course not found in the schedule!"), UserErrorsViewModel.GenericErrorMessage); } var selectedConnectedCourses = schedule.SelectedCourses .Where(sel => selectedCourse.Course.ConnectedCourses.Any(it => it.Id == sel.CourseId)) .ToList(); if (acquireSemaphore) { await CallingClient.SharedScheduleVM.TimetableHubSemaphore.WaitAsync(); } try { var selectedCourseUser = selectedCourse.Users.FirstOrDefault(o => o.User == CallingClient.User); //Find selected Tutorials var selectedTutorials = schedule.SelectedCourses .Where(sel => selectedCourse.Course.Tutorials .Concat(selectedConnectedCourses.SelectMany(s => s.Course.Tutorials)) .Any(it => it.Id == sel.CourseId)) .ToList(); if (selectedCourseUser != null) { // Remove user from selected courses foreach (var sel in selectedConnectedCourses.Concat(selectedTutorials).Concat(new[] { selectedCourse })) { await PaulRepository.RemoveUserFromSelectedCourseAsync(sel, selectedCourseUser); } } if (!selectedCourse.Users.Any()) { var firstTutorials = selectedCourse.Course.Tutorials.Take(1) .Concat(selectedConnectedCourses.SelectMany(s => s.Course.Tutorials.Take(1))); // Remove all Pending Tutorials from all TailoredSchedules foreach (var user in CallingClient.SharedScheduleVM.Users) { foreach (var t in firstTutorials) { user.TailoredScheduleVM.RemovePendingTutorials(t, errorReporter); } } // The course is no longer selected by anyone // -> Remove the whole course from schedule foreach (var sel in selectedConnectedCourses.Concat(selectedTutorials).Concat(new[] { selectedCourse })) { await PaulRepository.RemoveCourseFromScheduleAsync(schedule, sel.CourseId); } } UpdateAddedStateInSearchResultsAndCourseList(selectedCourse.Course, isAdded: false); UpdateTailoredViewModels(); } finally { if (acquireSemaphore) { CallingClient.SharedScheduleVM.TimetableHubSemaphore.Release(); } } } }
/// <summary> /// RPC-method for removing a course from the schedule /// </summary> /// <param name="courseId"></param> /// <returns></returns> public async Task RemoveCourse(string courseId) { using (var errorReporter = new ErrorReporter(s => CallingClient.Errors.ScheduleMessage = s)) { var course = PaulRepository.Courses.FirstOrDefault(c => c.Id == courseId); if (course == null) { errorReporter.Throw( new ArgumentException("Course not found", nameof(courseId)), UserErrorsViewModel.GenericErrorMessage); } var schedule = CallingClient.SharedScheduleVM.Schedule; await CallingClient.SharedScheduleVM.TimetableHubSemaphore.WaitAsync(); try { var selectedCourse = schedule.SelectedCourses.FirstOrDefault(c => c.CourseId == courseId); if (selectedCourse != null) { //Find selected Tutorials var selectedTutorials = schedule.SelectedCourses .Where(sel => selectedCourse.Course.Tutorials.Any(it => it.Id == sel.CourseId)) .Select(s => s.Course) .ToList(); var courses = selectedCourse.Course.ConnectedCourses .Concat(selectedTutorials) .Concat(new[] { selectedCourse.Course }); foreach (var course1 in courses) { try { if (course1.Tutorials.Any()) { // Remove all pending tutorials from all TailoredSchedules foreach (var user in CallingClient.SharedScheduleVM.Users) { user.TailoredScheduleVM.RemovePendingTutorials(course1.Tutorials.FirstOrDefault(), errorReporter); } } await PaulRepository.RemoveCourseFromScheduleAsync(schedule, course1.Id); UpdateAddedStateInSearchResultsAndCourseList(course1, isAdded: false); } catch (NullReferenceException e) { // This is just for purposes of compatibility // with development versions. Can be safely removed // after product launch PaulRepository.AddLog(e.Message, FatalityLevel.Normal, typeof(TimetableHub).Name); } } UpdateTailoredViewModels(); } else if (course.IsTutorial) { // The user has decided to remove a tutorial before joining one CallingClient.TailoredScheduleVM.RemovePendingTutorials(course, errorReporter); UpdateTailoredViewModels(); } else { errorReporter.Throw( new ArgumentException("Course not found in the schedule!"), UserErrorsViewModel.GenericErrorMessage); } } finally { CallingClient.SharedScheduleVM.TimetableHubSemaphore.Release(); } } }