def unprocess_field_data(cls, versioned_data, unversioned_data): data = {} arrival_date_from = _to_date(unversioned_data['arrival_date_from']) arrival_date_to = _to_date(unversioned_data['arrival_date_to']) departure_date_from = _to_date(unversioned_data['departure_date_from']) departure_date_to = _to_date(unversioned_data['departure_date_to']) data['arrival_dates'] = [(dt.date().isoformat(), format_date(dt)) for dt in iterdays(arrival_date_from, arrival_date_to)] data['departure_dates'] = [(dt.date().isoformat(), format_date(dt)) for dt in iterdays(departure_date_from, departure_date_to)] items = deepcopy(versioned_data['choices']) for item in items: item['caption'] = unversioned_data['captions'][item['id']] data['choices'] = items return data
def get_room_calendar(start_date, end_date, room_ids, **filters): start_dt = datetime.combine(start_date, time(hour=0, minute=0)) end_dt = datetime.combine(end_date, time(hour=23, minute=59)) query = _bookings_query(dict(filters, **{'start_date': start_dt, 'end_date': end_dt, 'room_ids': room_ids})) query = query.order_by(db.func.indico.natsort(Room.full_name)) rooms = (Room.query .filter(Room.is_active, Room.id.in_(room_ids) if room_ids else True) .options(joinedload('location')) .order_by(db.func.indico.natsort(Room.full_name)) .all()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) occurrences_by_room = groupby(query, attrgetter('reservation.room_id')) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = OrderedDict((room.id, { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(blocked_rooms.get(room.id, []), dates), }) for room in rooms) for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [occ for occ in occurrences if not occ.reservation.is_accepted] existing_bookings = [occ for occ in occurrences if occ.reservation.is_accepted] calendar[room_id].update({ 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings) }) return calendar
def _calculate_occurrences(self, event, from_dt, to_dt, tz): start_dt = max(from_dt, event.start_dt) if from_dt else event.start_dt end_dt = min(to_dt, event.end_dt) if to_dt else event.end_dt for day in iterdays(start_dt, end_dt): first_start, last_end = find_event_day_bounds(event, day.date()) if first_start is not None: yield Period(first_start, last_end)
def _process(self): room_details = room_details_schema.dump(self.room).data start_dt = date.today() end_dt = start_dt + timedelta(days=4) last_bookings = group_by_occurrence_date( get_existing_room_occurrences(self.room, start_dt, end_dt, only_accepted=True)) range_bookings = { day.date(): last_bookings.get(day.date()) for day in iterdays(start_dt, end_dt) } bookings = [{ 'availability': { 'usage': bookings or [] }, 'label': dt, 'conflictIndicator': False, 'id': dt } for dt, bookings in serialize_occurrences( range_bookings).iteritems()] room_details['bookings'] = sorted(bookings, key=itemgetter('id')) return jsonify(room_details)
def get_room_details_availability(room, start_dt, end_dt): dates = [d.date() for d in iterdays(start_dt, end_dt)] occurrences = get_existing_room_occurrences(room, start_dt, end_dt, RepeatFrequency.DAY, 1) pre_bookings = [occ for occ in occurrences if not occ.reservation.is_accepted] bookings = [occ for occ in occurrences if occ.reservation.is_accepted] blocked_rooms = get_rooms_blockings([room], start_dt.date(), end_dt.date()) nonoverridable_blocked_rooms = group_blocked_rooms(filter_blocked_rooms(blocked_rooms, nonoverridable_only=True, explicit=True)).get(room.id, []) overridable_blocked_rooms = group_blocked_rooms(filter_blocked_rooms(blocked_rooms, overridable_only=True, explicit=True)).get(room.id, []) unbookable_hours = get_rooms_unbookable_hours([room]).get(room.id, []) nonbookable_periods = get_rooms_nonbookable_periods([room], start_dt, end_dt).get(room.id, []) availability = [] for day in dates: iso_day = day.isoformat() nb_periods = serialize_nonbookable_periods(group_nonbookable_periods(nonbookable_periods, dates)).get(iso_day) availability.append({ 'bookings': serialize_occurrences(group_by_occurrence_date(bookings)).get(iso_day), 'pre_bookings': serialize_occurrences(group_by_occurrence_date(pre_bookings)).get(iso_day), 'blockings': serialize_blockings(group_blockings(nonoverridable_blocked_rooms, dates)).get(iso_day), 'overridable_blockings': (serialize_blockings(group_blockings(overridable_blocked_rooms, dates)) .get(iso_day)), 'nonbookable_periods': nb_periods, 'unbookable_hours': serialize_unbookable_hours(unbookable_hours), 'day': iso_day, }) return sorted(availability, key=itemgetter('day'))
def serialize_timetable(self, event, days=None, hide_weekends=False, hide_empty_days=False): timetable = {} for day in iterdays(event.start_dt_local, event.end_dt_local, skip_weekends=hide_weekends, day_whitelist=days): date_str = day.strftime('%Y%m%d') timetable[date_str] = {} contributions_strategy = defaultload('contribution') contributions_strategy.subqueryload('person_links') contributions_strategy.subqueryload('references') query_options = (contributions_strategy, defaultload('session_block').subqueryload('person_links')) query = (TimetableEntry.query.with_parent(event) .options(*query_options) .order_by(TimetableEntry.type != TimetableEntryType.SESSION_BLOCK)) for entry in query: day = entry.start_dt.astimezone(event.tzinfo).date() date_str = day.strftime('%Y%m%d') if date_str not in timetable: continue if not entry.can_view(session.user): continue data = self.serialize_timetable_entry(entry, load_children=False) key = self._get_entry_key(entry) if entry.parent: parent_code = 's{}'.format(entry.parent_id) timetable[date_str][parent_code]['entries'][key] = data else: timetable[date_str][key] = data if hide_empty_days: timetable = self._filter_empty_days(timetable) return timetable
def serialize_session_timetable(self, session_, without_blocks=False, hide_empty_days=False): timetable = {} for day in iterdays(session_.event_new.start_dt_local, session_.event_new.end_dt_local): timetable[day.strftime('%Y%m%d')] = {} for block in session_.blocks: block_entry = block.timetable_entry if not block_entry: continue date_key = block_entry.start_dt.astimezone( session_.event_new.tzinfo).strftime('%Y%m%d') entries = block_entry.children if without_blocks else [block_entry] for entry in entries: if not entry.can_view(session.user): continue entry_key = self._get_entry_key(entry) timetable[date_key][ entry_key] = self.serialize_timetable_entry( entry, load_children=True) if hide_empty_days: timetable = self._filter_empty_days(timetable) return timetable
def serialize_session_timetable(self, session_, without_blocks=False, strip_empty_days=False): event_tz = self.event.tzinfo timetable = {} if session_.blocks: start_dt = min(chain((b.start_dt for b in session_.blocks), (self.event.start_dt,))).astimezone(event_tz) end_dt = max(chain((b.end_dt for b in session_.blocks), (self.event.end_dt,))).astimezone(event_tz) else: start_dt = self.event.start_dt_local end_dt = self.event.end_dt_local for day in iterdays(start_dt, end_dt): timetable[day.strftime('%Y%m%d')] = {} for block in session_.blocks: block_entry = block.timetable_entry if not block_entry: continue date_key = block_entry.start_dt.astimezone(event_tz).strftime('%Y%m%d') entries = block_entry.children if without_blocks else [block_entry] for entry in entries: if not entry.can_view(self.user): continue entry_key = self._get_entry_key(entry) timetable[date_key][entry_key] = self.serialize_timetable_entry(entry, load_children=True) if strip_empty_days: timetable = self._strip_empty_days(timetable) return timetable
def find_with_filters(filters, avatar=None): from indico.modules.rb.models.rooms import Room from indico.modules.rb.models.reservations import Reservation q = ReservationOccurrence.find(Room.is_active, _join=[Reservation, Room], _eager=ReservationOccurrence.reservation) if 'start_dt' in filters and 'end_dt' in filters: start_dt = filters['start_dt'] end_dt = filters['end_dt'] criteria = [] # We have to check the time range for EACH DAY for day_start_dt in iterdays(start_dt, end_dt): # Same date, but the end time day_end_dt = datetime.combine(day_start_dt.date(), end_dt.time()) criteria.append(db_dates_overlap(ReservationOccurrence, 'start_dt', day_start_dt, 'end_dt', day_end_dt)) q = q.filter(or_(*criteria)) if filters.get('is_only_mine') and avatar: q = q.filter((Reservation.booked_for_id == avatar.id) | (Reservation.created_by_id == avatar.id)) if filters.get('room_ids'): q = q.filter(Room.id.in_(filters['room_ids'])) if filters.get('is_only_confirmed_bookings') and not filters.get('is_only_pending_bookings'): q = q.filter(Reservation.is_accepted) elif not filters.get('is_only_confirmed_bookings') and filters.get('is_only_pending_bookings'): q = q.filter(~Reservation.is_accepted) if filters.get('is_rejected') and filters.get('is_cancelled'): q = q.filter(Reservation.is_rejected | ReservationOccurrence.is_rejected | Reservation.is_cancelled | ReservationOccurrence.is_cancelled) else: if filters.get('is_rejected'): q = q.filter(Reservation.is_rejected | ReservationOccurrence.is_rejected) else: q = q.filter(~Reservation.is_rejected & ~ReservationOccurrence.is_rejected) if filters.get('is_cancelled'): q = q.filter(Reservation.is_cancelled | ReservationOccurrence.is_cancelled) else: q = q.filter(~Reservation.is_cancelled & ~ReservationOccurrence.is_cancelled) if filters.get('is_archived'): q = q.filter(Reservation.is_archived) if filters.get('uses_vc'): q = q.filter(Reservation.uses_vc) if filters.get('needs_vc_assistance'): q = q.filter(Reservation.needs_vc_assistance) if filters.get('needs_assistance'): q = q.filter(Reservation.needs_assistance) if filters.get('booked_for_name'): qs = u'%{}%'.format(filters['booked_for_name']) q = q.filter(Reservation.booked_for_name.ilike(qs)) if filters.get('reason'): qs = u'%{}%'.format(filters['reason']) q = q.filter(Reservation.booking_reason.ilike(qs)) return q.order_by(Room.id)
def unprocess_field_data(cls, versioned_data, unversioned_data): data = {} arrival_date_from = _to_date(unversioned_data["arrival_date_from"]) arrival_date_to = _to_date(unversioned_data["arrival_date_to"]) departure_date_from = _to_date(unversioned_data["departure_date_from"]) departure_date_to = _to_date(unversioned_data["departure_date_to"]) data["arrival_dates"] = [ (dt.date().isoformat(), format_date(dt)) for dt in iterdays(arrival_date_from, arrival_date_to) ] data["departure_dates"] = [ (dt.date().isoformat(), format_date(dt)) for dt in iterdays(departure_date_from, departure_date_to) ] items = deepcopy(versioned_data["choices"]) for item in items: item["caption"] = unversioned_data["captions"][item["id"]] data["choices"] = items return data
def get_room_calendar(start_date, end_date, room_ids): start_dt = datetime.combine(start_date, time(hour=0, minute=0)) end_dt = datetime.combine(end_date, time(hour=23, minute=59)) reservation_strategy = contains_eager('reservation') reservation_strategy.noload('room') reservation_strategy.noload('booked_for_user') reservation_strategy.noload('created_by_user') query = (ReservationOccurrence.query.filter( ReservationOccurrence.is_valid).filter( ReservationOccurrence.start_dt >= start_dt, ReservationOccurrence.end_dt <= end_dt).join(Reservation).join(Room).filter( Room.is_active, Room.id.in_(room_ids) if room_ids else True).order_by( db.func.indico.natsort( Room.full_name)).options(reservation_strategy)) rooms = (Room.query.filter( Room.is_active, Room.id.in_(room_ids) if room_ids else True).options( joinedload('location')).order_by( db.func.indico.natsort(Room.full_name)).all()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods( rooms, start_dt, end_dt) occurrences_by_room = groupby(query, attrgetter('reservation.room_id')) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = OrderedDict((room.id, { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(blocked_rooms.get(room.id, []), dates), }) for room in rooms) for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [ occ for occ in occurrences if not occ.reservation.is_accepted ] existing_bookings = [ occ for occ in occurrences if occ.reservation.is_accepted ] calendar[room_id].update({ 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings) }) return calendar
def iter_days(self): if self.repeat_frequency is None and self.repeat_interval is None: for dt in iterdays(self.start_dt, self.end_dt): yield dt.date() else: for dt in ReservationOccurrence.iter_start_time(self.start_dt, self.end_dt, (self.repeat_frequency, self.repeat_interval)): for offset in xrange(-self.flexible_days, self.flexible_days + 1): yield (dt + timedelta(days=offset)).date()
def calculate_rooms_bookable_time(rooms, start_date=None, end_date=None): if end_date is None: end_date = date.today() - relativedelta(days=1) if start_date is None: start_date = end_date - relativedelta(days=29) working_time_per_day = sum((datetime.combine(date.today(), end) - datetime.combine(date.today(), start)).seconds for start, end in WORKING_TIME_PERIODS) working_days = sum(1 for __ in iterdays(start_date, end_date, skip_weekends=True)) return working_days * working_time_per_day * len(rooms)
def calculate_rooms_bookable_time(rooms, start_date=None, end_date=None): if end_date is None: end_date = date.today() - relativedelta(days=1) if start_date is None: start_date = end_date - relativedelta(days=29) working_time_per_day = sum((datetime.combine(date.today(), end) - datetime.combine(date.today(), start)).seconds for start, end in Location.working_time_periods) working_days = sum(1 for __ in iterdays(start_date, end_date, skip_weekends=True)) return working_days * working_time_per_day * len(rooms)
def calculate_rooms_bookable_time(rooms, start_date=None, end_date=None): if end_date is None: end_date = date.today() - relativedelta(days=1) if start_date is None: start_date = end_date - relativedelta(days=29) working_time_start = datetime.combine(date.today(), Location.working_time_start) working_time_end = datetime.combine(date.today(), Location.working_time_end) working_time_per_day = (working_time_end - working_time_start).seconds working_days = sum(1 for __ in iterdays(start_date, end_date, skip_weekends=True)) return working_days * working_time_per_day * len(rooms)
def get_room_calendar(start_date, end_date, room_ids, include_inactive=False, **filters): start_dt = datetime.combine(start_date, time(hour=0, minute=0)) end_dt = datetime.combine(end_date, time(hour=23, minute=59)) query = _bookings_query(dict(filters, start_dt=start_dt, end_dt=end_dt, room_ids=room_ids, include_inactive=include_inactive)) bookings = query.order_by(db.func.indico.natsort(Room.full_name)).all() rooms = set() if room_ids: rooms = set(Room.query .filter(~Room.is_deleted, Room.id.in_(room_ids)) .options(joinedload('location'))) rooms.update(b.reservation.room for b in bookings) rooms = sorted(rooms, key=lambda r: natural_sort_key(r.full_name)) occurrences_by_room = groupby(bookings, attrgetter('reservation.room_id')) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) nonoverridable_blocked_rooms = group_blocked_rooms(filter_blocked_rooms(blocked_rooms, nonoverridable_only=True, explicit=True)) overridable_blocked_rooms = group_blocked_rooms(filter_blocked_rooms(blocked_rooms, overridable_only=True, explicit=True)) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = {room.id: { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(nonoverridable_blocked_rooms.get(room.id, []), dates), 'overridable_blockings': group_blockings(overridable_blocked_rooms.get(room.id, []), dates), } for room in rooms} for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [occ for occ in occurrences if occ.reservation.is_pending] existing_bookings = [occ for occ in occurrences if not occ.reservation.is_pending and occ.is_valid] concurrent_pre_bookings = get_concurrent_pre_bookings(pre_bookings) additional_data = { 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings), 'concurrent_pre_bookings': group_by_occurrence_date(concurrent_pre_bookings) } if include_inactive: additional_data.update({ 'cancellations': group_by_occurrence_date(occ for occ in occurrences if occ.is_cancelled), 'rejections': group_by_occurrence_date(occ for occ in occurrences if occ.is_rejected) }) calendar[room_id].update(additional_data) return calendar
def _eventDaysIterator(conf): """ Iterates over the daily times of an event """ sched = conf.getSchedule() for day in iterdays(conf.getStartDate(), conf.getEndDate()): # ignore days that have no occurrences if sched.getEntriesOnDay(day): startDT = sched.calculateDayStartDate(day) endDT = sched.calculateDayEndDate(day) if startDT != endDT: yield Period(startDT, endDT)
def calculate_rooms_bookable_time(rooms, start_date=None, end_date=None): if end_date is None: end_date = date.today() - relativedelta(days=1) if start_date is None: start_date = end_date - relativedelta(days=29) working_time_start = datetime.combine(date.today(), Location.working_time_start) working_time_end = datetime.combine(date.today(), Location.working_time_end) working_time_per_day = (working_time_end - working_time_start).seconds working_days = iterdays(start_date, end_date, skip_weekends=True).count() return working_days * working_time_per_day * len(rooms)
def get_room_calendar(start_date, end_date, room_ids, include_inactive=False, **filters): start_dt = datetime.combine(start_date, time(hour=0, minute=0)) end_dt = datetime.combine(end_date, time(hour=23, minute=59)) query = _bookings_query(dict(filters, start_dt=start_dt, end_dt=end_dt, room_ids=room_ids, include_inactive=include_inactive)) query = query.order_by(db.func.indico.natsort(Room.full_name)) rooms = (Room.query .filter(~Room.is_deleted, Room.id.in_(room_ids) if room_ids else True) .options(joinedload('location')) .order_by(db.func.indico.natsort(Room.full_name)) .all()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) occurrences_by_room = groupby(query, attrgetter('reservation.room_id')) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) nonoverridable_blocked_rooms = group_blocked_rooms(filter_blocked_rooms(blocked_rooms, nonoverridable_only=True, explicit=True)) overridable_blocked_rooms = group_blocked_rooms(filter_blocked_rooms(blocked_rooms, overridable_only=True, explicit=True)) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = OrderedDict((room.id, { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(nonoverridable_blocked_rooms.get(room.id, []), dates), 'overridable_blockings': group_blockings(overridable_blocked_rooms.get(room.id, []), dates), }) for room in rooms) for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [occ for occ in occurrences if occ.reservation.is_pending] existing_bookings = [occ for occ in occurrences if not occ.reservation.is_pending and occ.is_valid] additional_data = { 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings) } if include_inactive: additional_data.update({ 'cancellations': group_by_occurrence_date(occ for occ in occurrences if occ.is_cancelled), 'rejections': group_by_occurrence_date(occ for occ in occurrences if occ.is_rejected) }) calendar[room_id].update(additional_data) return calendar
def get_room_calendar(day, room_ids): start_dt = datetime.combine(day, time(hour=0, minute=0)) end_dt = datetime.combine(day, time(hour=23, minute=59)) reservation_strategy = contains_eager('reservation') reservation_strategy.noload('room') reservation_strategy.noload('booked_for_user') reservation_strategy.noload('created_by_user') query = (ReservationOccurrence.query .filter(ReservationOccurrence.is_valid) .filter(ReservationOccurrence.start_dt >= start_dt, ReservationOccurrence.end_dt <= end_dt) .join(Reservation) .join(Room) .filter(Room.is_active, Room.id.in_(room_ids) if room_ids else True) .order_by(db.func.indico.natsort(Room.full_name)) .options(reservation_strategy)) rooms = (Room.query .filter(Room.is_active, Room.id.in_(room_ids) if room_ids else True) .options(joinedload('location')) .order_by(db.func.indico.natsort(Room.full_name)) .all()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods(rooms, start_dt, end_dt) occurrences_by_room = groupby(query, attrgetter('reservation.room_id')) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = OrderedDict((room.id, { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(blocked_rooms.get(room.id, []), dates), }) for room in rooms) for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [occ for occ in occurrences if not occ.reservation.is_accepted] existing_bookings = [occ for occ in occurrences if occ.reservation.is_accepted] calendar[room_id].update({ 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings) }) return calendar
def serialize_timetable(self, event, days=None, hide_weekends=False, strip_empty_days=False): tzinfo = event.tzinfo if self.management else event.display_tzinfo event.preload_all_acl_entries() timetable = {} for day in iterdays(event.start_dt.astimezone(tzinfo), event.end_dt.astimezone(tzinfo), skip_weekends=hide_weekends, day_whitelist=days): date_str = day.strftime('%Y%m%d') timetable[date_str] = {} contributions_strategy = defaultload('contribution') contributions_strategy.subqueryload('person_links') contributions_strategy.subqueryload('references') query_options = ( contributions_strategy, defaultload('session_block').subqueryload('person_links')) query = (TimetableEntry.query.with_parent(event).options( *query_options).order_by( TimetableEntry.type != TimetableEntryType.SESSION_BLOCK)) for entry in query: day = entry.start_dt.astimezone(tzinfo).date() date_str = day.strftime('%Y%m%d') if date_str not in timetable: continue if not entry.can_view(session.user): continue data = self.serialize_timetable_entry(entry, load_children=False) key = self._get_entry_key(entry) if entry.parent: parent_code = 's{}'.format(entry.parent_id) timetable[date_str][parent_code]['entries'][key] = data else: if (entry.type == TimetableEntryType.SESSION_BLOCK and entry.start_dt.astimezone(tzinfo).date() != entry.end_dt.astimezone(tzinfo).date()): # If a session block lasts into another day we need to add it to that day, too timetable[entry.end_dt.astimezone(tzinfo).date().strftime( '%Y%m%d')][key] = data timetable[date_str][key] = data if strip_empty_days: timetable = self._strip_empty_days(timetable) return timetable
def serialize_session_timetable(self, session_, without_blocks=False, hide_empty_days=False): timetable = {} for day in iterdays(session_.event_new.start_dt_local, session_.event_new.end_dt_local): timetable[day.strftime('%Y%m%d')] = {} for block in session_.blocks: block_entry = block.timetable_entry if not block_entry: continue date_key = block_entry.start_dt.astimezone(session_.event_new.tzinfo).strftime('%Y%m%d') entries = block_entry.children if without_blocks else [block_entry] for entry in entries: if not entry.can_view(session.user): continue entry_key = self._get_entry_key(entry) timetable[date_key][entry_key] = self.serialize_timetable_entry(entry, load_children=True) if hide_empty_days: timetable = self._filter_empty_days(timetable) return timetable
def index_booking(self, bk): conf = bk.getConference() contribs = bk.getTalkSelectionList() choose = bk.isChooseTalkSelected() # if contributions chosen individually if choose and contribs: for contrib_id in contribs: # check that contrib is in valid room if CollaborationTools.isAbleToBeWebcastOrRecorded(conf.getContributionById(contrib_id), bk.getType()): self.index_obj(CSBookingInstanceWrapper(bk, conf.getContributionById(contrib_id))) # We need to check if it is a lecture with a correct room elif CollaborationTools.isAbleToBeWebcastOrRecorded(conf, bk.getType()) or conf.getType() !="simple_event": for day in iterdays(conf.getStartDate(), conf.getEndDate()): bkw = CSBookingInstanceWrapper(bk, conf, day.replace(hour=0, minute=0, second=0), day.replace(hour=23, minute=59, second=59)) self.index_obj(bkw)
def get_room_details_availability(room, start_dt, end_dt): dates = [d.date() for d in iterdays(start_dt, end_dt)] bookings = get_existing_room_occurrences(room, start_dt, end_dt, RepeatFrequency.DAY, 1, only_accepted=True) blockings = get_rooms_blockings([room], start_dt.date(), end_dt.date()).get(room.id, []) unbookable_hours = get_rooms_unbookable_hours([room]).get(room.id, []) nonbookable_periods = get_rooms_nonbookable_periods([room], start_dt, end_dt).get(room.id, []) availability = [] for day in dates: iso_day = day.isoformat() availability.append({ 'bookings': serialize_occurrences(group_by_occurrence_date(bookings)).get(iso_day), 'blockings': serialize_blockings(group_blockings(blockings, dates)).get(iso_day), 'nonbookable_periods': serialize_nonbookable_periods( group_nonbookable_periods(nonbookable_periods, dates)).get(iso_day), 'unbookable_hours': serialize_unbookable_hours(unbookable_hours), 'day': iso_day, }) return sorted(availability, key=itemgetter('day'))
def get_room_details_availability(room, start_dt, end_dt): dates = [d.date() for d in iterdays(start_dt, end_dt)] bookings = get_existing_room_occurrences(room, start_dt, end_dt, RepeatFrequency.DAY, 1, only_accepted=True) blockings = get_rooms_blockings([room], start_dt.date(), end_dt.date()).get(room.id, []) unbookable_hours = get_rooms_unbookable_hours([room]).get(room.id, []) nonbookable_periods = get_rooms_nonbookable_periods([room], start_dt, end_dt).get(room.id, []) availability = [] for day in dates: iso_day = day.isoformat() nb_periods = serialize_nonbookable_periods(group_nonbookable_periods(nonbookable_periods, dates)).get(iso_day) availability.append({ 'bookings': serialize_occurrences(group_by_occurrence_date(bookings)).get(iso_day), 'blockings': serialize_blockings(group_blockings(blockings, dates)).get(iso_day), 'nonbookable_periods': nb_periods, 'unbookable_hours': serialize_unbookable_hours(unbookable_hours), 'day': iso_day, }) return sorted(availability, key=itemgetter('day'))
def serialize_timetable(self, event, days=None, hide_weekends=False, hide_empty_days=False): timetable = {} for day in iterdays(event.start_dt_local, event.end_dt_local, skip_weekends=hide_weekends, day_whitelist=days): date_str = day.strftime('%Y%m%d') timetable[date_str] = {} contributions_strategy = defaultload('contribution') contributions_strategy.subqueryload('person_links') contributions_strategy.subqueryload('references') query_options = ( contributions_strategy, defaultload('session_block').subqueryload('person_links')) query = (TimetableEntry.query.with_parent(event).options( *query_options).order_by( TimetableEntry.type != TimetableEntryType.SESSION_BLOCK)) for entry in query: day = entry.start_dt.astimezone(event.tzinfo).date() date_str = day.strftime('%Y%m%d') if date_str not in timetable: continue if not entry.can_view(session.user): continue data = self.serialize_timetable_entry(entry, load_children=False) key = self._get_entry_key(entry) if entry.parent: parent_code = 's{}'.format(entry.parent_id) timetable[date_str][parent_code]['entries'][key] = data else: timetable[date_str][key] = data if hide_empty_days: timetable = self._filter_empty_days(timetable) return timetable
def serialize_timetable(self, days=None, hide_weekends=False, strip_empty_days=False): tzinfo = self.event.tzinfo if self.management else self.event.display_tzinfo self.event.preload_all_acl_entries() timetable = {} for day in iterdays(self.event.start_dt.astimezone(tzinfo), self.event.end_dt.astimezone(tzinfo), skip_weekends=hide_weekends, day_whitelist=days): date_str = day.strftime('%Y%m%d') timetable[date_str] = {} contributions_strategy = defaultload('contribution') contributions_strategy.subqueryload('person_links') contributions_strategy.subqueryload('references') query_options = (contributions_strategy, defaultload('session_block').subqueryload('person_links')) query = (TimetableEntry.query.with_parent(self.event) .options(*query_options) .order_by(TimetableEntry.type != TimetableEntryType.SESSION_BLOCK)) for entry in query: day = entry.start_dt.astimezone(tzinfo).date() date_str = day.strftime('%Y%m%d') if date_str not in timetable: continue if not entry.can_view(self.user): continue data = self.serialize_timetable_entry(entry, load_children=False) key = self._get_entry_key(entry) if entry.parent: parent_code = 's{}'.format(entry.parent_id) timetable[date_str][parent_code]['entries'][key] = data else: if (entry.type == TimetableEntryType.SESSION_BLOCK and entry.start_dt.astimezone(tzinfo).date() != entry.end_dt.astimezone(tzinfo).date()): # If a session block lasts into another day we need to add it to that day, too timetable[entry.end_dt.astimezone(tzinfo).date().strftime('%Y%m%d')][key] = data timetable[date_str][key] = data if strip_empty_days: timetable = self._strip_empty_days(timetable) return timetable
def test_iterdays(from_, to, skip_weekends, day_whitelist, day_blacklist, expected): assert len(list(iterdays(from_, to, skip_weekends, day_whitelist, day_blacklist))) == expected
def find_with_filters(cls, filters, user=None): from indico.modules.rb.models.rooms import Room from indico.modules.rb.models.reservations import Reservation q = (ReservationOccurrence.find( Room.is_active, _join=[ReservationOccurrence.reservation, Room], _eager=ReservationOccurrence.reservation).options( cls.NO_RESERVATION_USER_STRATEGY)) if 'start_dt' in filters and 'end_dt' in filters: start_dt = filters['start_dt'] end_dt = filters['end_dt'] criteria = [] # We have to check the time range for EACH DAY for day_start_dt in iterdays(start_dt, end_dt): # Same date, but the end time day_end_dt = datetime.combine(day_start_dt.date(), end_dt.time()) criteria.append( db_dates_overlap(ReservationOccurrence, 'start_dt', day_start_dt, 'end_dt', day_end_dt)) q = q.filter(or_(*criteria)) if filters.get('is_only_mine') and user: q = q.filter((Reservation.booked_for_id == user.id) | (Reservation.created_by_id == user.id)) if filters.get('room_ids'): q = q.filter(Room.id.in_(filters['room_ids'])) if filters.get('is_only_confirmed_bookings' ) and not filters.get('is_only_pending_bookings'): q = q.filter(Reservation.is_accepted) elif not filters.get('is_only_confirmed_bookings') and filters.get( 'is_only_pending_bookings'): q = q.filter(~Reservation.is_accepted) if filters.get('is_rejected') and filters.get('is_cancelled'): q = q.filter(Reservation.is_rejected | ReservationOccurrence.is_rejected | Reservation.is_cancelled | ReservationOccurrence.is_cancelled) else: if filters.get('is_rejected'): q = q.filter(Reservation.is_rejected | ReservationOccurrence.is_rejected) else: q = q.filter(~Reservation.is_rejected & ~ReservationOccurrence.is_rejected) if filters.get('is_cancelled'): q = q.filter(Reservation.is_cancelled | ReservationOccurrence.is_cancelled) else: q = q.filter(~Reservation.is_cancelled & ~ReservationOccurrence.is_cancelled) if filters.get('is_archived'): q = q.filter(Reservation.is_archived) if filters.get('uses_vc'): q = q.filter(Reservation.uses_vc) if filters.get('needs_vc_assistance'): q = q.filter(Reservation.needs_vc_assistance) if filters.get('needs_assistance'): q = q.filter(Reservation.needs_assistance) if filters.get('booked_for_name'): qs = u'%{}%'.format(filters['booked_for_name']) q = q.filter(Reservation.booked_for_name.ilike(qs)) if filters.get('reason'): qs = u'%{}%'.format(filters['reason']) q = q.filter(Reservation.booking_reason.ilike(qs)) return q.order_by(Room.id)
def _get_session_timetable_entries(self): entries = {} for day in iterdays(self.event_new.start_dt, self.event_new.end_dt): entries[day.date()] = get_session_block_entries( self.event_new, day) return entries
def _get_session_timetable_entries(self): entries = {} for day in iterdays(self.event_new.start_dt, self.event_new.end_dt): entries[day.date()] = get_session_block_entries(self.event_new, day) return entries
def inject_week_timetable(event, days, tz_name, tpl='events/timetable/display/_weeks.html'): first_week_day = layout_settings.get( event, 'timetable_theme_settings').get('start_day') sunday_first = (first_week_day == 'sunday') show_end_times = request.args.get('showEndTimes') == '1' tz = timezone(tz_name) day_dict = defaultdict(list, days) sorted_dates = [ d.date() for d in iterdays(event.start_dt.astimezone(tz), event.end_dt.astimezone(tz)) ] first_day, last_day = sorted_dates[0], sorted_dates[-1] has_weekends = any(d.weekday() in (5, 6) for d in sorted_dates) # Calculate the actual starting day, based on the selected first day of the week if first_week_day != 'event': week_start = 6 if sunday_first else 0 if first_day.weekday() != week_start: first_day -= timedelta(days=first_day.weekday()) + timedelta( days=int(has_weekends and sunday_first)) week_table_shallow = [] skipped_days = 0 for i, dt in enumerate(iterdays(first_day, last_day)): day = dt.date() if day > last_day: # the loop doesn't account for skipped days so we might have to break early break if not has_weekends and day.weekday() == 5: day += timedelta(days=2) skipped_days += 2 if i % (7 if has_weekends else 5) == 0: week_table_shallow.append([]) week_table_shallow[-1].append((day, day_dict[day])) # build a new week table that contains placeholders week_table = [] for week in week_table_shallow: # Build list of time slots that are used this week time_slots = set() for day, entries in week: time_slots.update(_localized_time(x.start_dt, tz) for x in entries) # Build each day with its contributions and placeholders tmp = [] for day, entries in week: day_tmp = defaultdict(list) for entry in entries: day_tmp[_localized_time(entry.start_dt, tz)].append(entry) for slot in sorted(time_slots): day_tmp.setdefault(slot, []) # We've got a dict with a {slot: [entry, entry, ...]} mapping (for a single day) # We'll run over it and make some additional calculations day_tmp_sorted = sorted(day_tmp.items()) day_entries = {} for n, (slot, slot_entries) in enumerate(day_tmp_sorted): tmp_slot_entries = [] for entry in slot_entries: # Check how many empty slots which intersect this one exist count = sum(1 for x in takewhile( lambda x: not x[1], iter(day_tmp_sorted[n + 1:])) if x[0] < _localized_time(entry.end_dt, tz)) tmp_slot_entries.append((entry, count)) day_entries[slot] = tmp_slot_entries tmp.append((day, day_entries)) week_table.append(tmp) timetable_settings = layout_settings.get(event, 'timetable_theme_settings') return render_template(tpl, event=event, week_table=week_table, timetable_settings=timetable_settings, has_weekends=has_weekends, timezone=tz_name, tz_object=tz, show_end_times=show_end_times)
def inject_week_timetable(event, days, tz_name, tpl='events/timetable/display/_weeks.html'): first_week_day = layout_settings.get(event, 'timetable_theme_settings').get('start_day') sunday_first = (first_week_day == 'sunday') show_end_times = request.args.get('showEndTimes') == '1' tz = timezone(tz_name) day_dict = defaultdict(list, days) sorted_dates = [d.date() for d in iterdays(event.start_dt.astimezone(tz), event.end_dt.astimezone(tz))] first_day, last_day = sorted_dates[0], sorted_dates[-1] has_weekends = any(d.weekday() in (5, 6) for d in sorted_dates) # Calculate the actual starting day, based on the selected first day of the week if first_week_day != 'event': week_start = 6 if sunday_first else 0 if first_day.weekday() != week_start: first_day -= timedelta(days=first_day.weekday()) + timedelta(days=int(has_weekends and sunday_first)) week_table_shallow = [] skipped_days = 0 for i, dt in enumerate(iterdays(first_day, last_day)): day = dt.date() if day > last_day: # the loop doesn't account for skipped days so we might have to break early break if not has_weekends and day.weekday() == 5: day += timedelta(days=2) skipped_days += 2 if i % (7 if has_weekends else 5) == 0: week_table_shallow.append([]) week_table_shallow[-1].append((day, day_dict[day])) # build a new week table that contains placeholders week_table = [] for week in week_table_shallow: # Build list of time slots that are used this week time_slots = set() for day, entries in week: time_slots.update(_localized_time(x.start_dt, tz) for x in entries) # Build each day with its contributions and placeholders tmp = [] for day, entries in week: day_tmp = defaultdict(list) for entry in entries: day_tmp[_localized_time(entry.start_dt, tz)].append(entry) for slot in sorted(time_slots): day_tmp.setdefault(slot, []) # We've got a dict with a {slot: [entry, entry, ...]} mapping (for a single day) # We'll run over it and make some additional calculations day_tmp_sorted = sorted(day_tmp.viewitems()) day_entries = OrderedDict() for n, (slot, slot_entries) in enumerate(day_tmp_sorted): tmp_slot_entries = [] for entry in slot_entries: # Check how many empty slots which intersect this one exist count = sum(1 for x in takewhile(lambda x: not x[1], iter(day_tmp_sorted[n + 1:])) if x[0] < _localized_time(entry.end_dt, tz)) tmp_slot_entries.append((entry, count)) day_entries[slot] = tmp_slot_entries tmp.append((day, day_entries)) week_table.append(tmp) timetable_settings = layout_settings.get(event, 'timetable_theme_settings') return render_template(tpl, event=event, week_table=week_table, timetable_settings=timetable_settings, has_weekends=has_weekends, timezone=tz_name, tz_object=tz, show_end_times=show_end_times)
def get_room_calendar(start_date, end_date, room_ids, include_inactive=False, **filters): start_dt = datetime.combine(start_date, time(hour=0, minute=0)) end_dt = datetime.combine(end_date, time(hour=23, minute=59)) query = _bookings_query( dict(filters, start_dt=start_dt, end_dt=end_dt, room_ids=room_ids, include_inactive=include_inactive)) query = query.order_by(db.func.indico.natsort(Room.full_name)) rooms = (Room.query.filter( Room.is_active, Room.id.in_(room_ids) if room_ids else True).options( joinedload('location')).order_by( db.func.indico.natsort(Room.full_name)).all()) unbookable_hours = get_rooms_unbookable_hours(rooms) nonbookable_periods = get_rooms_nonbookable_periods( rooms, start_dt, end_dt) occurrences_by_room = groupby(query, attrgetter('reservation.room_id')) blocked_rooms = get_rooms_blockings(rooms, start_dt, end_dt) dates = [d.date() for d in iterdays(start_dt, end_dt)] calendar = OrderedDict((room.id, { 'room_id': room.id, 'nonbookable_periods': group_nonbookable_periods(nonbookable_periods.get(room.id, []), dates), 'unbookable_hours': unbookable_hours.get(room.id, []), 'blockings': group_blockings(blocked_rooms.get(room.id, []), dates), }) for room in rooms) for room_id, occurrences in occurrences_by_room: occurrences = list(occurrences) pre_bookings = [ occ for occ in occurrences if occ.reservation.is_pending ] existing_bookings = [ occ for occ in occurrences if not occ.reservation.is_pending and occ.is_valid ] additional_data = { 'bookings': group_by_occurrence_date(existing_bookings), 'pre_bookings': group_by_occurrence_date(pre_bookings) } if include_inactive: additional_data.update({ 'cancellations': group_by_occurrence_date(occ for occ in occurrences if occ.is_cancelled), 'rejections': group_by_occurrence_date(occ for occ in occurrences if occ.is_rejected) }) calendar[room_id].update(additional_data) return calendar
def get_category_timetable(categ_ids, start_dt, end_dt, detail_level='event', tz=utc, from_categ=None, grouped=True): """Retrieve time blocks that fall within a specific time interval for a given set of categories. :param categ_ids: iterable containing list of category IDs :param start_dt: start of search interval (``datetime``, expected to be in display timezone) :param end_dt: end of search interval (``datetime`` in expected to be in display timezone) :param detail_level: the level of detail of information (``event|session|contribution``) :param tz: the ``timezone`` information should be displayed in :param from_categ: ``Category`` that will be taken into account to calculate visibility :param grouped: Whether to group results by start date :returns: a dictionary containing timetable information in a structured way. See source code for examples. """ day_start = start_dt.astimezone(utc) day_end = end_dt.astimezone(utc) dates_overlap = lambda t: (t.start_dt >= day_start) & (t.start_dt <= day_end) items = defaultdict(lambda: defaultdict(list)) # first of all, query TimetableEntries/events that fall within # specified range of dates (and category set) events = _query_events(categ_ids, day_start, day_end) if from_categ: events = events.filter(Event.is_visible_in(from_categ)) for eid, tt_start_dt in events: if tt_start_dt: items[eid][tt_start_dt.astimezone(tz).date()].append(tt_start_dt) else: items[eid] = None # then, retrieve detailed information about the events event_ids = set(items) query = (Event.find(Event.id.in_(event_ids)) .options(subqueryload(Event.person_links).joinedload(EventPersonLink.person), joinedload(Event.own_room).noload('owner'), joinedload(Event.own_venue), joinedload(Event.category).undefer('effective_icon_data'), undefer('effective_protection_mode'))) scheduled_events = defaultdict(list) ongoing_events = [] events = [] for e in query: if grouped: local_start_dt = e.start_dt.astimezone(tz).date() local_end_dt = e.end_dt.astimezone(tz).date() if items[e.id] is None: # if there is no TimetableEntry, this means the event has not timetable on that interval for day in iterdays(max(start_dt.date(), local_start_dt), min(end_dt.date(), local_end_dt)): # if the event starts on this date, we've got a time slot if day.date() == local_start_dt: scheduled_events[day.date()].append((e.start_dt, e)) else: ongoing_events.append(e) else: for start_d, start_dts in items[e.id].viewitems(): scheduled_events[start_d].append((start_dts[0], e)) else: events.append(e) # result['events'][date(...)] -> [(datetime(....), Event(...))] # result[event_id]['contribs'][date(...)] -> [(TimetableEntry(...), Contribution(...))] # result['ongoing_events'] = [Event(...)] if grouped: result = defaultdict(lambda: defaultdict(lambda: defaultdict(list))) else: result = defaultdict(lambda: defaultdict(list)) result.update({ 'events': scheduled_events if grouped else events, 'ongoing_events': ongoing_events }) # according to detail level, ask for extra information from the DB if detail_level != 'event': query = _query_blocks(event_ids, dates_overlap, detail_level) if grouped: for b in query: start_date = b.timetable_entry.start_dt.astimezone(tz).date() result[b.session.event_id]['blocks'][start_date].append((b.timetable_entry, b)) else: for b in query: result[b.session.event_id]['blocks'].append(b) if detail_level == 'contribution': query = (Contribution.find(Contribution.event_id.in_(event_ids), dates_overlap(TimetableEntry), ~Contribution.is_deleted) .options(contains_eager(Contribution.timetable_entry), joinedload(Contribution.person_links)) .join(TimetableEntry)) if grouped: for c in query: start_date = c.timetable_entry.start_dt.astimezone(tz).date() result[c.event_id]['contribs'][start_date].append((c.timetable_entry, c)) else: for c in query: result[c.event_id]['contributions'].append(c) query = (Break.find(TimetableEntry.event_id.in_(event_ids), dates_overlap(TimetableEntry)) .options(contains_eager(Break.timetable_entry)) .join(TimetableEntry)) if grouped: for b in query: start_date = b.timetable_entry.start_dt.astimezone(tz).date() result[b.timetable_entry.event_id]['breaks'][start_date].append((b.timetable_entry, b)) else: for b in query: result[b.timetable_entry.event_id]['breaks'].append(b) return result