def _process(self): form = RequestListFilterForm(request.args, csrf_enabled=False) results = None if form.validate_on_submit(): reverse = form.direction.data == 'desc' from_dt = as_utc(get_day_start( form.start_date.data)) if form.start_date.data else None to_dt = as_utc(get_day_end( form.end_date.data)) if form.end_date.data else None results = find_requests(from_dt=from_dt, to_dt=to_dt) results = [(req, req.event, req.event.start_dt, contribs, session_blocks) for req, contribs, session_blocks in results] results = group_list(results, lambda x: x[2].date(), itemgetter(2), sort_reverse=reverse) results = OrderedDict( sorted(results.viewitems(), key=itemgetter(0), reverse=reverse)) return WPVCAssistance.render_template( 'request_list.html', form=form, results=results, action=url_for('.request_list'), vc_capable_rooms=get_vc_capable_rooms(), within_working_hours=start_time_within_working_hours)
def _process(self): form = RequestListFilterForm(request.args, csrf_enabled=False) results = None if request.args and form.validate(): reverse = form.direction.data == 'desc' talks = form.granularity.data == 'talks' from_dt = as_utc(get_day_start( form.start_date.data)) if form.start_date.data else None to_dt = as_utc(get_day_end( form.end_date.data)) if form.end_date.data else None states = {form.state.data} if form.state.data is not None else None results = find_requests(talks=talks, from_dt=from_dt, to_dt=to_dt, states=states) if not talks: results = [(req, req.event, req.event.start_dt) for req in results] results = group_list(results, lambda x: x[2].date(), itemgetter(2), sort_reverse=reverse) results = OrderedDict( sorted(results.viewitems(), key=itemgetter(0), reverse=reverse)) return WPAudiovisualManagers.render_template('request_list.html', form=form, results=results)
def find_next_start_dt(duration, obj, day=None): """Find the next most convenient start date fitting a duration within an object. :param duration: Duration to fit into the event/session-block. :param obj: The :class:`Event` or :class:`SessionBlock` the duration needs to fit into. :param day: The local event date where to fit the duration in case the object is an event. :return: The end datetime of the latest scheduled entry in the object if the duration fits then. It it doesn't, the latest datetime that fits it. ``None`` if the duration cannot fit in the object. """ if isinstance(obj, Event): if day is None: raise ValueError("No day specified for event.") if not (obj.start_dt_local.date() <= day <= obj.end_dt_local.date()): raise ValueError("Day out of event bounds.") earliest_dt = obj.start_dt if obj.start_dt_local.date() == day else obj.start_dt.replace(hour=8, minute=0) latest_dt = obj.end_dt if obj.start_dt.date() == day else get_day_end(day, tzinfo=obj.tzinfo) elif isinstance(obj, SessionBlock): if day is not None: raise ValueError("Day specified for session block.") earliest_dt = obj.timetable_entry.start_dt latest_dt = obj.timetable_entry.end_dt else: raise ValueError("Invalid object type {}".format(type(obj))) max_duration = latest_dt - earliest_dt if duration > max_duration: return None start_dt = find_latest_entry_end_dt(obj, day=day) or earliest_dt end_dt = start_dt + duration if end_dt > latest_dt: start_dt = latest_dt - duration return start_dt
def test_filter_available( dummy_room, create_reservation, create_blocking, has_booking, has_blocking, has_pre_booking, include_pre_bookings, has_pending_blocking, include_pending_blockings, filtered, ): if has_booking: create_reservation( start_dt=datetime.combine(date.today(), time(8)), end_dt=datetime.combine(date.today(), time(10)) ) if has_pre_booking: create_reservation( start_dt=datetime.combine(date.today(), time(10)), end_dt=datetime.combine(date.today(), time(12)), is_accepted=False, ) if has_blocking: create_blocking(state=BlockedRoom.State.accepted) if has_pending_blocking: create_blocking(state=BlockedRoom.State.pending) availabilty_filter = Room.filter_available( get_day_start(date.today()), get_day_end(date.today()), (RepeatFrequency.NEVER, 0), include_pre_bookings=include_pre_bookings, include_pending_blockings=include_pending_blockings, ) assert set(Room.find_all(availabilty_filter)) == (set() if filtered else {dummy_room})
def get_default_booking_interval(duration=90, precision=15, force_today=False): """Get the default booking interval for a room. Returns the default booking interval for a room as a tuple containing the start and end times as `datetime` objects. The start time is the default working start time or the current time (if the working start time is in the past); rounded up to the given precision in minutes (15 by default). The end time corresponds to the start time plus the given duration in minutes. If the booking ends after the end of work time, it is automatically moved to the next day. :param duration: int -- The duration of a booking in minutes (must be greater than 1) :param precision: int -- The number of minutes by which to round up the current time for the start time of a booking. Negative values are allowed but will round the time down and create a booking starting in the past. :param force_today: Forces a booking to be for today, even if it past the end of work time. This is ignored if the current time is either after 23:50 or within the amount of minutes of the precision from midnight. For example with a precision of 30 minutes, if the current time is 23:42 then the meeting will be the following day. :returns: (datetime, datetime, bool) -- A tuple with the start and end times of the booking and a boolean which is `True` if the date was changed from today and `False` otherwise. :raises: ValueError if the duration is less than 1 minute """ if duration < 1: raise ValueError( "The duration must be strictly positive (got {} min)".format( duration)) date_changed = False work_start = datetime.combine(date.today(), Location.working_time_periods[0][0]) work_end = datetime.combine(date.today(), Location.working_time_periods[-1][1]) start_dt = max(work_start, round_up_to_minutes(datetime.now(), precision=precision)) end_dt = start_dt + timedelta(minutes=duration) if end_dt.date() > start_dt.date(): end_dt = get_day_end(start_dt.date()) if ((not force_today and start_dt > work_end) or start_dt.date() > date.today() or end_dt - start_dt < timedelta(minutes=10)): date_changed = True start_dt = work_start + timedelta(days=1) end_dt = start_dt + timedelta(minutes=duration) return start_dt, end_dt, date_changed
def validate_start_dt(self, field): event = self.contrib.event day = self.contrib.start_dt.astimezone(event.tzinfo).date() if day == event.end_dt_local.date(): latest_dt = event.end_dt error_msg = _("With this time, the contribution would exceed the event end time.") else: latest_dt = get_day_end(day, tzinfo=event.tzinfo) error_msg = _("With this time, the contribution would exceed the current day.") if field.data + self.contrib.duration > latest_dt: raise ValidationError(error_msg)
def _process(self): form = RequestListFilterForm(request.args) results = None if form.validate_on_submit(): reverse = form.direction.data == 'desc' from_dt = as_utc(get_day_start(form.start_date.data)) if form.start_date.data else None to_dt = as_utc(get_day_end(form.end_date.data)) if form.end_date.data else None results = _find_requests(from_dt=from_dt, to_dt=to_dt) results = group_list(results, lambda req: dateutil.parser.parse(req['requested_at']).date(), sort_reverse=reverse) results = OrderedDict(sorted(results.viewitems(), reverse=reverse)) return WPRoomAssistance.render_template('request_list.html', form=form, results=results, parse_dt=dateutil.parser.parse)
def validate_duration(self, field): if field.errors: return if self.contrib.is_scheduled: event = self.contrib.event day = self.contrib.start_dt.astimezone(event.tzinfo).date() if day == event.end_dt_local.date(): latest_dt = event.end_dt error_msg = _("With this duration, the contribution would exceed the event end time.") else: latest_dt = get_day_end(day, tzinfo=event.tzinfo) error_msg = _("With this duration, the contribution would exceed the current day.") if self.contrib.start_dt + field.data > latest_dt: raise ValidationError(error_msg)
def get_default_booking_interval(duration=90, precision=15, force_today=False): """Get the default booking interval for a room. Returns the default booking interval for a room as a tuple containing the start and end times as `datetime` objects. The start time is the default working start time or the current time (if the working start time is in the past); rounded up to the given precision in minutes (15 by default). The end time corresponds to the start time plus the given duration in minutes. If the booking ends after the end of work time, it is automatically moved to the next day. :param duration: int -- The duration of a booking in minutes (must be greater than 1) :param precision: int -- The number of minutes by which to round up the current time for the start time of a booking. Negative values are allowed but will round the time down and create a booking starting in the past. :param force_today: Forces a booking to be for today, even if it past the end of work time. This is ignored if the current time is either after 23:50 or within the amount of minutes of the precision from midnight. For example with a precision of 30 minutes, if the current time is 23:42 then the meeting will be the following day. :returns: (datetime, datetime, bool) -- A tuple with the start and end times of the booking and a boolean which is `True` if the date was changed from today and `False` otherwise. :raises: ValueError if the duration is less than 1 minute """ if duration < 1: raise ValueError("The duration must be strictly positive (got {} min)".format(duration)) date_changed = False work_start = datetime.combine(date.today(), Location.working_time_periods[0][0]) work_end = datetime.combine(date.today(), Location.working_time_periods[-1][1]) start_dt = max(work_start, round_up_to_minutes(datetime.now(), precision=precision)) end_dt = start_dt + timedelta(minutes=duration) if end_dt.date() > start_dt.date(): end_dt = get_day_end(start_dt.date()) if ((not force_today and start_dt > work_end) or start_dt.date() > date.today() or end_dt - start_dt < timedelta(minutes=10)): date_changed = True start_dt = work_start + timedelta(days=1) end_dt = start_dt + timedelta(minutes=duration) return start_dt, end_dt, date_changed
def _process(self): form = VCRoomListFilterForm(request.args, csrf_enabled=False) results = None if request.args and form.validate(): reverse = form.direction.data == 'desc' from_dt = as_utc(get_day_start(form.start_date.data)) if form.start_date.data else None to_dt = as_utc(get_day_end(form.end_date.data)) if form.end_date.data else None results = find_event_vc_rooms(from_dt=from_dt, to_dt=to_dt, distinct=True) results = group_list((r for r in results if r.event_new), key=lambda r: r.event_new.start_dt.date(), sort_by=lambda r: r.event_new.start_dt, sort_reverse=reverse) results = OrderedDict(sorted(results.viewitems(), key=itemgetter(0), reverse=reverse)) return WPVCService.render_template('vc_room_list.html', form=form, results=results, action=url_for('.vc_room_list'))
def _process(self): form = VCRoomListFilterForm(request.args) results = None if request.args and form.validate(): reverse = form.direction.data == 'desc' from_dt = as_utc(get_day_start(form.start_date.data)) if form.start_date.data else None to_dt = as_utc(get_day_end(form.end_date.data)) if form.end_date.data else None results = find_event_vc_rooms(from_dt=from_dt, to_dt=to_dt, distinct=True) results = group_list((r for r in results if r.event), key=lambda r: r.event.getStartDate().date(), sort_by=lambda r: r.event.getStartDate(), sort_reverse=reverse) results = OrderedDict(sorted(results.viewitems(), key=itemgetter(0), reverse=reverse)) return WPVCService.render_template('vc_room_list.html', form=form, results=results, action=url_for('.vc_room_list'))
def test_filter_available(dummy_room, create_reservation, create_blocking, has_booking, has_blocking, has_pre_booking, include_pre_bookings, has_pending_blocking, include_pending_blockings, filtered): if has_booking: create_reservation(start_dt=datetime.combine(date.today(), time(8)), end_dt=datetime.combine(date.today(), time(10))) if has_pre_booking: create_reservation(start_dt=datetime.combine(date.today(), time(10)), end_dt=datetime.combine(date.today(), time(12)), state=ReservationState.pending) if has_blocking: create_blocking(state=BlockedRoom.State.accepted) if has_pending_blocking: create_blocking(state=BlockedRoom.State.pending) availabilty_filter = Room.filter_available(get_day_start(date.today()), get_day_end(date.today()), (RepeatFrequency.NEVER, 0), include_pre_bookings=include_pre_bookings, include_pending_blockings=include_pending_blockings) assert set(Room.find_all(availabilty_filter)) == (set() if filtered else {dummy_room})