Example #1
0
        private IEnumerable <SlotDto> GetSlotsForAvailability(OfficeHoursTeacherAvailabilityDto availabilityDto,
                                                              DateTime dateStart, DateTime dateEnd, int lmsUserId, OfficeHoursTeacherAvailability availability)
        {
            var slots             = new List <SlotDto>();
            var availabilityStart = availabilityDto.PeriodStart;
            var checkStart        = availabilityStart > dateStart ? availabilityStart : dateStart;
            var periodEnd         = availabilityDto.PeriodEnd.Date.AddDays(1);
            var checkEnd          = periodEnd < dateEnd ? periodEnd : dateEnd;

            var dayCheckStart = checkStart.Date;
            var dayCheckEnd   = checkEnd.Date.AddDays(1);
            var dbSlots       = availability?.Slots;

            while (dayCheckStart < dayCheckEnd)
            {
                if (availabilityDto.DaysOfWeek.Contains((int)dayCheckStart.DayOfWeek))
                {
                    //dayly cycles for intervals
                    foreach (var interval in availabilityDto.Intervals)
                    {
                        var intervalCheckStart = dayCheckStart.AddMinutes(interval.Start) > checkStart
                            ? dayCheckStart.AddMinutes(interval.Start)
                            : new DateTime(checkStart.Year, checkStart.Month, checkStart.Day, checkStart.Hour, 0, 0, DateTimeKind.Utc)
                                                 .AddMinutes((checkStart.Minute / availabilityDto.Duration + (checkStart.Minute % availabilityDto.Duration == 0 ? 0 : 1)) * availabilityDto.Duration);

                        if (intervalCheckStart < checkStart || intervalCheckStart >= checkEnd || intervalCheckStart >= availabilityDto.PeriodEnd) //check if interval start is inside of period that we need to check
                        {
                            continue;
                        }

                        var intervalCheckEnd = interval.End > interval.Start
                            ? dayCheckStart.AddMinutes(interval.End)
                            : dayCheckStart.AddDays(1).AddMinutes(interval.End);
                        while (intervalCheckStart < intervalCheckEnd)
                        {
                            var dbSlot =
                                dbSlots?.FirstOrDefault(x => x.Start == intervalCheckStart); // && end
                            slots.Add(dbSlot == null
                                ? new SlotDto
                            {
                                Start = intervalCheckStart,
                                End   = intervalCheckStart.AddMinutes(availabilityDto.Duration)
                            }
                                : ConvertToDto(dbSlot, lmsUserId));

                            intervalCheckStart = intervalCheckStart.AddMinutes(availabilityDto.Duration);
                        }
                    }
                }

                dayCheckStart = dayCheckStart.AddDays(1);
            }

            return(slots);
        }
Example #2
0
        public async Task <IEnumerable <SlotDto> > ValidateSlotsRange(OfficeHours oh, int lmsUserId,
                                                                      OfficeHoursTeacherAvailabilityDto availabilityDto)
        {
            var currentSlots = await GetSlots(oh.Id, lmsUserId, DateTime.UtcNow, DateTime.UtcNow.AddYears(1));

            var slotsToCheck =
                GetSlotsForAvailability(availabilityDto, DateTime.UtcNow, DateTime.UtcNow.AddYears(1), lmsUserId, null);
            var overlappingSlots = currentSlots.Where(cs =>
                                                      slotsToCheck.Any(
                                                          x => (cs.Start <= x.Start && cs.End > x.Start) || (cs.Start < x.End && cs.End >= x.End)));

            //slotsToCheck.Any(x => currentSlots.Any(cs => (checkEmptySlots || cs.Status != 0) && ((cs.Start<= x.Start && cs.End > x.Start) || (cs.Start < x.End && cs.End >= x.End)))))
            //return false;
            return(overlappingSlots);
        }
Example #3
0
        private OfficeHoursTeacherAvailabilityDto BuildAvailabilityBySlots(IEnumerable <SlotDto> slots, long timeshift, int duration)
        {
            var orderedSlots      = slots.OrderBy(x => x.Start);
            var availabilityStart = orderedSlots.First().Start;
            var availabilityEnd   = orderedSlots.Last().End;
            var availability      = new OfficeHoursTeacherAvailabilityDto
            {
                Duration    = duration,
                PeriodEnd   = availabilityEnd.AddMilliseconds(timeshift),
                PeriodStart = availabilityStart.AddMilliseconds(timeshift),
                Intervals   = BuildIntervalsBySlots(orderedSlots, timeshift, duration)
            };

            availability.DaysOfWeek = new[] { (int)availability.PeriodStart.DayOfWeek }; //assuming that we move only one day
            return(availability);
        }
Example #4
0
        public async Task <OperationResultWithData <OfficeHoursTeacherAvailabilityDto> > AddAvailabitily([FromBody] OfficeHoursTeacherAvailabilityDto dto)
        {
            LmsCourseMeeting meeting = _lmsCourseMeetingModel.GetOneByCourseAndId(LmsCompany.Id, CourseId, dto.MeetingId);

            if (meeting?.OfficeHours == null)
            {
                return(OperationResultWithData <OfficeHoursTeacherAvailabilityDto> .Error("Meeting not found"));
            }
            var result = await _officeHoursService.AddAvailability(meeting.OfficeHours, Session.LmsUser, dto);

            return(result);
        }
Example #5
0
        private static OfficeHoursTeacherAvailability ConvertFromDto(OfficeHours oh, LmsUser lmsUser, OfficeHoursTeacherAvailabilityDto availabilityDto)
        {
            var entity = new OfficeHoursTeacherAvailability
            {
                User        = lmsUser,
                Duration    = availabilityDto.Duration,
                Intervals   = string.Join(",", availabilityDto.Intervals.Select(x => $"{x.Start}-{x.End}")),
                DaysOfWeek  = string.Join(",", availabilityDto.DaysOfWeek),
                PeriodStart = availabilityDto.PeriodStart,
                PeriodEnd   = availabilityDto.PeriodEnd,
                Meeting     = oh
            };

            return(entity);
        }
Example #6
0
        public async Task <OperationResultWithData <OfficeHoursTeacherAvailabilityDto> > AddAvailability(OfficeHours oh, LmsUser lmsUser, OfficeHoursTeacherAvailabilityDto availabilityDto)
        {
            var overlappingSlots = await ValidateSlotsRange(oh, lmsUser.Id, availabilityDto);

            if (overlappingSlots.Any())
            {
                return(OperationResultWithData <OfficeHoursTeacherAvailabilityDto> .Error(
                           "The range of dates overlaps another date range. Please choose another date range."));
            }
            var entity = ConvertFromDto(oh, lmsUser, availabilityDto);

            _availabilityModel.RegisterSave(entity, true);
            return(ConvertToDto(entity).ToSuccessResult());
        }
Example #7
0
        public async Task <OperationResultWithData <SlotDto> > RescheduleSlot(int slotId, LmsUser lmsUser, RescheduleSlotDto dto)
        {
            if (dto.Start < DateTime.UtcNow)
            {
                return(OperationResultWithData <SlotDto> .Error("Upcoming slots couldn't be moved for elapsed time"));
            }

            var slot = _slotModel.GetOneById(slotId).Value;

            //var slot = await _context.OhSlots.Include(x => x.Availability).ThenInclude(x => x.Meeting).FirstOrDefaultAsync(x => x.Id == slotId);
            if (slot == null)
            {
                return(OperationResultWithData <SlotDto> .Error("Slot not found"));
            }

            var currentSlots = await GetSlots(slot.Availability.Meeting.Id, lmsUser.Id, DateTime.UtcNow, DateTime.UtcNow.AddYears(1));

            var busySlot = currentSlots.FirstOrDefault(x => x.Start == dto.Start);

            if (busySlot != null)
            {
                if (busySlot.Status == (int)OfficeHoursSlotStatus.Free) //free
                {
                    if ((busySlot.End - busySlot.Start).Minutes != slot.Availability.Duration)
                    {
                        return(OperationResultWithData <SlotDto> .Error(
                                   "Another slot with different duration is available at the same time."));
                    }

                    var slotResult = await AddSlots(slot.Availability.Meeting.Id, slot.User, new[] {
                        new CreateSlotDto
                        {
                            Start     = dto.Start,
                            End       = dto.Start.AddMinutes(slot.Availability.Duration),
                            Questions = slot.Questions,
                            Subject   = slot.Subject
                        }
                    });

                    if (slotResult.IsSuccess)
                    {
                        var oldSlotResult = await DeleteSlot(slotId, lmsUser);

                        return(slotResult.Data.First().ToSuccessResult());
                    }
                    //todo: send email
                    return(OperationResultWithData <SlotDto> .Error(slotResult.Message));
                }
                else
                {
                    return(OperationResultWithData <SlotDto> .Error(
                               "Another slot has already been booked at this time or time is not available for booking."));
                }
            }
            if (currentSlots.Any(cs =>
                                 (cs.Start <= dto.Start && cs.End > dto.Start) ||
                                 (cs.Start < dto.Start.AddMinutes(slot.Availability.Duration) &&
                                  cs.End >= dto.Start.AddMinutes(slot.Availability.Duration))))
            {
                return(OperationResultWithData <SlotDto> .Error(
                           "Another slot with different duration is available at the same time."));
            }

            var availabilityDto = new OfficeHoursTeacherAvailabilityDto
            {
                Intervals = new List <AvailabilityInterval> {
                    new AvailabilityInterval {
                        Start = dto.Start.Hour * 60 + dto.Start.Minute, End = dto.Start.Hour * 60 + dto.Start.Minute + slot.Availability.Duration
                    }
                },
                PeriodStart = dto.Start,
                PeriodEnd   = dto.Start.AddMinutes(slot.Availability.Duration),
                Duration    = slot.Availability.Duration,
                DaysOfWeek  = new[] { (int)dto.Start.DayOfWeek }
            };
            var availabilityResult = await AddAvailability(slot.Availability.Meeting, lmsUser, availabilityDto);

            if (!availabilityResult.IsSuccess)
            {
                return(OperationResultWithData <SlotDto> .Error($"Error during slot time move. {availabilityResult.Message}"));
            }
            var newSlotResult = await AddSlots(slot.Availability.Meeting.Id, slot.User, new[] {
                new CreateSlotDto
                {
                    Start     = dto.Start,
                    End       = dto.Start.AddMinutes(slot.Availability.Duration),
                    Questions = slot.Questions,
                    Subject   = slot.Subject
                }
            });

            if (newSlotResult.IsSuccess && !string.IsNullOrEmpty(dto.Message))
            {
                //var meeting = slot.Availability.Meeting;
                //var details = await _meetingService.GetMeetingApiDetails(meeting);
                //await _notificationService.SendOHRescheduleEmail(slot.Start, newSlotResult.Data.First(), details.Topic, dto.Message);
            }
            var oldSlotResultAdd = await DeleteSlot(slotId, lmsUser);

            //todo: send email

            return(newSlotResult.IsSuccess ? newSlotResult.Data.First().ToSuccessResult() : OperationResultWithData <SlotDto> .Error(newSlotResult.Message));
        }