def __init__(self, occurrences, start_dt, end_dt, candidates=None, rooms=None, specific_room=None, repeat_frequency=None, repeat_interval=None, flexible_days=0, show_blockings=True): self.occurrences = occurrences self.start_dt = start_dt self.end_dt = end_dt self.candidates = candidates self.rooms = rooms self.specific_room = specific_room self.repeat_frequency = repeat_frequency self.repeat_interval = repeat_interval self.flexible_days = flexible_days self.show_blockings = show_blockings self.conflicts = 0 self.bars = [] if self.specific_room and self.rooms: raise ValueError('specific_room and rooms are mutually exclusive') if self.specific_room: self.rooms = [self.specific_room] elif self.rooms is None: self.rooms = Room.find_all(is_active=True) self.rooms = sorted(self.rooms, key=lambda x: natural_sort_key(x.full_name)) if self.show_blockings: # avoid loading user data we don't care about user_strategy = defaultload('blocking').defaultload( 'created_by_user') user_strategy.noload('*') user_strategy.load_only('first_name', 'last_name') room_ids = [r.id for r in self.rooms] filters = { 'room_ids': room_ids, 'state': BlockedRoom.State.accepted, 'start_date': self.start_dt.date(), 'end_date': self.end_dt.date() } self.blocked_rooms = BlockedRoom.find_with_filters( filters).options(user_strategy) self.nonbookable_periods = NonBookablePeriod.find( NonBookablePeriod.room_id.in_(room_ids), NonBookablePeriod.overlaps(self.start_dt, self.end_dt)).all() else: self.blocked_rooms = [] self._produce_bars()
def _process_args(self): blocking_id = self._params.get('blocking_id') self._room = Room.get(self._params['room_id']) self._blocking = Blocking.get(blocking_id) if blocking_id else None if 'start_dt' in self._params and 'end_dt' in self._params: start_dt = datetime.strptime(self._params['start_dt'], '%H:%M %Y-%m-%d') end_dt = datetime.strptime(self._params['end_dt'], '%H:%M %Y-%m-%d') self._nonbookable = bool(NonBookablePeriod.find_first(NonBookablePeriod.room_id == self._room.id, NonBookablePeriod.overlaps(start_dt, end_dt))) else: self._nonbookable = False
def group_nonbookable_periods(periods, dates): if not periods: return {} occurrences = defaultdict(list) for period in periods: for d in dates: if period.start_dt.date() <= d <= period.end_dt.date(): period_occurrence = NonBookablePeriod() period_occurrence.start_dt = ((datetime.combine(d, time(0))) if period.start_dt.date() != d else period.start_dt) period_occurrence.end_dt = ((datetime.combine(d, time(23, 59))) if period.end_dt.date() != d else period.end_dt) occurrences[d].append(period_occurrence) return occurrences
def group_nonbookable_periods(periods, dates): if not periods: return {} occurrences = defaultdict(list) for period in periods: for date in dates: if period.start_dt.date() <= date <= period.end_dt.date(): period_occurrence = NonBookablePeriod() period_occurrence.start_dt = ((datetime.combine(date, time(0))) if period.start_dt.date() != date else period.start_dt) period_occurrence.end_dt = ((datetime.combine(date, time(23, 59))) if period.end_dt.date() != date else period.end_dt) occurrences[date].append(period_occurrence) return occurrences
def _process_args(self): blocking_id = self._params.get('blocking_id') self._room = Room.get(self._params['room_id']) self._blocking = Blocking.get(blocking_id) if blocking_id else None if 'start_dt' in self._params and 'end_dt' in self._params: start_dt = datetime.strptime(self._params['start_dt'], '%H:%M %Y-%m-%d') end_dt = datetime.strptime(self._params['end_dt'], '%H:%M %Y-%m-%d') self._nonbookable = bool( NonBookablePeriod.find_first( NonBookablePeriod.room_id == self._room.id, NonBookablePeriod.overlaps(start_dt, end_dt))) else: self._nonbookable = False
def __init__(self, occurrences, start_dt, end_dt, candidates=None, rooms=None, specific_room=None, repeat_frequency=None, repeat_interval=None, flexible_days=0, show_blockings=True): self.occurrences = occurrences self.start_dt = start_dt self.end_dt = end_dt self.candidates = candidates self.rooms = rooms self.specific_room = specific_room self.repeat_frequency = repeat_frequency self.repeat_interval = repeat_interval self.flexible_days = flexible_days self.show_blockings = show_blockings self.conflicts = 0 self.bars = [] if self.specific_room and self.rooms: raise ValueError('specific_room and rooms are mutually exclusive') if self.specific_room: self.rooms = [self.specific_room] elif self.rooms is None: self.rooms = Room.find_all(is_active=True) self.rooms = sorted(self.rooms, key=lambda x: natural_sort_key(x.full_name)) if self.show_blockings: # avoid loading user data we don't care about user_strategy = defaultload('blocking').defaultload('created_by_user') user_strategy.noload('*') user_strategy.load_only('first_name', 'last_name') room_ids = [r.id for r in self.rooms] filters = { 'room_ids': room_ids, 'state': BlockedRoom.State.accepted, 'start_date': self.start_dt.date(), 'end_date': self.end_dt.date() } self.blocked_rooms = BlockedRoom.find_with_filters(filters).options(user_strategy) self.nonbookable_periods = NonBookablePeriod.find( NonBookablePeriod.room_id.in_(room_ids), NonBookablePeriod.overlaps(self.start_dt, self.end_dt) ).all() else: self.blocked_rooms = [] self._produce_bars()
def update_room_availability(room, availability): if 'bookable_hours' in availability: room.bookable_hours.order_by(False).delete() unique_bh = set((hours['start_time'], hours['end_time']) for hours in availability['bookable_hours']) db.session.add_all( [BookableHours(room=room, start_time=hours[0], end_time=hours[1]) for hours in unique_bh]) if 'nonbookable_periods' in availability: room.nonbookable_periods.order_by(False).delete() unique_nbp = set((period['start_dt'], period['end_dt']) for period in availability['nonbookable_periods']) db.session.add_all( [NonBookablePeriod(room=room, start_dt=datetime.combine(period[0], time(0, 0)), end_dt=datetime.combine(period[1], time(23, 59))) for period in unique_nbp])
def _save(self): room = self._room form = self._form # Simple fields form.populate_obj(room, skip=('bookable_hours', 'nonbookable_periods'), existing_only=True) room.update_name() # Photos if form.small_photo.data and form.large_photo.data: _cache.delete_multi('photo-{}-{}'.format(room.id, size) for size in {'small', 'large'}) room.photo = Photo(thumbnail=form.small_photo.data.read(), data=form.large_photo.data.read()) elif form.delete_photos.data: _cache.delete_multi('photo-{}-{}'.format(room.id, size) for size in {'small', 'large'}) room.photo = None # Custom attributes room.attributes = [ RoomAttributeAssociation(value=form['attribute_{}'.format( attr.id)].data, attribute_id=attr.id) for attr in self._location.attributes.all() if form['attribute_{}'.format(attr.id)].data ] # Bookable times room.bookable_hours = [ BookableHours(start_time=bt['start'], end_time=bt['end']) for bt in form.bookable_hours.data if all(x is not None for x in bt.viewvalues()) ] # Nonbookable dates room.nonbookable_periods = [ NonBookablePeriod(start_dt=nbd.start_dt, end_dt=nbd.end_dt) for nbd in form.nonbookable_periods if (nbd.start_dt and nbd.end_dt) ]
def _save(self): room = self._room form = self._form # Simple fields form.populate_obj(room, skip=('bookable_hours', 'nonbookable_periods'), existing_only=True) room.update_name() # Photos if form.large_photo.data: _cache.delete('photo-{}'.format(room.id)) room.photo = Photo(data=form.large_photo.data.read()) build_rooms_spritesheet() elif form.delete_photos.data: _cache.delete('photo-{}'.format(room.id)) room.photo = None build_rooms_spritesheet() # Custom attributes room.attributes = [ RoomAttributeAssociation( value=form['attribute_{}'.format(attr.id)].data, attribute_id=attr.id) for attr in RoomAttribute.query.all() if form['attribute_{}'.format(attr.id)].data ] # Bookable times room.bookable_hours = [ BookableHours(start_time=bt['start'], end_time=bt['end']) for bt in form.bookable_hours.data if all(x is not None for x in bt.viewvalues()) ] # Nonbookable dates room.nonbookable_periods = [ NonBookablePeriod(start_dt=nbd.start_dt, end_dt=nbd.end_dt) for nbd in form.nonbookable_periods if (nbd.start_dt and nbd.end_dt) ]
def test_overlaps(start_dt, end_dt, expected): start_dt = datetime.strptime(start_dt, "%Y-%m-%d %H:%M") end_dt = datetime.strptime(end_dt, "%Y-%m-%d %H:%M") nbp = NonBookablePeriod(start_dt=datetime(2014, 12, 5), end_dt=datetime(2014, 12, 6)) assert nbp.overlaps(start_dt, end_dt) == expected
def test_overlaps(start_dt, end_dt, expected): start_dt = datetime.strptime(start_dt, '%Y-%m-%d %H:%M') end_dt = datetime.strptime(end_dt, '%Y-%m-%d %H:%M') nbp = NonBookablePeriod(start_dt=datetime(2014, 12, 5), end_dt=datetime(2014, 12, 6)) assert nbp.overlaps(start_dt, end_dt) == expected
def migrate_rooms(self): eq = defaultdict(set) vc = defaultdict(set) for old_room_id, old_room in self.rb_root['Rooms'].iteritems(): eq[old_room._locationName].update( e for e in old_room._equipment.split('`') if e) vc[old_room._locationName].update( e for e in getattr(old_room, 'avaibleVC', []) if e) print cformat('%{white!}migrating equipment') for name, eqs in eq.iteritems(): l = Location.find_first(name=name) if l is None: print cformat('%{yellow!}*** WARNING') print cformat( "%{{yellow!}}***%{{reset}} Location '{}' does not exist. Skipped equipment: {}" .format(name, eqs)) continue l.equipment_types.extend(EquipmentType(name=x) for x in eqs) print cformat('- [%{cyan}{}%{reset}] {}').format(name, eqs) db.session.add(l) db.session.commit() print print cformat('%{white!}migrating vc equipment') for name, vcs in vc.iteritems(): l = Location.find_first(name=name) if l is None: print cformat('%{yellow!}*** WARNING') print cformat( "%{{yellow!}}***%{{reset}} Location '{}' does not exist. Skipped VC equipment: {}" .format(name, vcs)) continue pvc = l.get_equipment_by_name('Video conference') for vc_name in vcs: req = EquipmentType(name=vc_name) req.parent = pvc l.equipment_types.append(req) print cformat('- [%{cyan}{}%{reset}] {}').format( name, req.name) db.session.add(l) db.session.commit() print print cformat('%{white!}migrating rooms') for old_room_id, old_room in self.rb_root['Rooms'].iteritems(): l = Location.find_first(name=old_room._locationName) if l is None: print cformat('%{yellow!}*** WARNING') print cformat( "%{{yellow!}}***%{{reset}} Location '{}' does not exist. Skipped room '{}'" .format(old_room._locationName, old_room.id)) continue r = Room( id=old_room_id, name=convert_to_unicode((old_room._name or '').strip() or generate_name(old_room)), site=convert_to_unicode(old_room.site), division=convert_to_unicode(old_room.division), building=convert_to_unicode(old_room.building), floor=convert_to_unicode(old_room.floor), number=convert_to_unicode(old_room.roomNr), notification_before_days=(( old_room.resvStartNotificationBefore or None) if getattr( old_room, 'resvStartNotification', False) else None), notification_for_responsible=getattr( old_room, 'resvNotificationToResponsible', False), notification_for_assistance=getattr( old_room, 'resvNotificationAssistance', False), reservations_need_confirmation=old_room.resvsNeedConfirmation, telephone=convert_to_unicode( getattr(old_room, 'telephone', None)), key_location=convert_to_unicode( getattr(old_room, 'whereIsKey', None)), capacity=getattr(old_room, 'capacity', None), surface_area=getattr(old_room, 'surfaceArea', None), latitude=getattr(old_room, 'latitude', None), longitude=getattr(old_room, 'longitude', None), comments=convert_to_unicode(getattr(old_room, 'comments', None)), owner_id=self.merged_avatars.get(old_room.responsibleId, old_room.responsibleId), is_active=old_room.isActive, is_reservable=old_room.isReservable, max_advance_days=int(old_room.maxAdvanceDays) if getattr( old_room, 'maxAdvanceDays', None) else None) print cformat( '- [%{cyan}{}%{reset}] %{grey!}{:4}%{reset} %{green!}{}%{reset}' ).format(l.name, r.id, r.name) for old_bookable_time in getattr(old_room, '_dailyBookablePeriods', []): r.bookable_hours.append( BookableHours(start_time=old_bookable_time._startTime, end_time=old_bookable_time._endTime)) print cformat(' %{blue!}Bookable:%{reset} {}').format( r.bookable_hours[-1]) for old_nonbookable_date in getattr(old_room, '_nonBookableDates', []): r.nonbookable_periods.append( NonBookablePeriod(start_dt=old_nonbookable_date._startDate, end_dt=old_nonbookable_date._endDate)) print cformat(' %{blue!}Nonbookable:%{reset} {}').format( r.nonbookable_periods[-1]) if self.photo_path: try: with open( os.path.join( self.photo_path, 'large_photos', get_canonical_name_of(old_room) + '.jpg'), 'rb') as f: large_photo = f.read() except Exception: large_photo = None try: with open( os.path.join( self.photo_path, 'small_photos', get_canonical_name_of(old_room) + '.jpg'), 'rb') as f: small_photo = f.read() except Exception: small_photo = None if large_photo and small_photo: r.photo = Photo(data=large_photo, thumbnail=small_photo) print cformat(' %{blue!}Photos') new_eq = [] for old_equipment in ifilter( None, old_room._equipment.split('`') + old_room.avaibleVC): room_eq = l.get_equipment_by_name(old_equipment) new_eq.append(room_eq) r.available_equipment.append(room_eq) if new_eq: print cformat(' %{blue!}Equipment:%{reset} {}').format( ', '.join(sorted(x.name for x in new_eq))) for attr_name, value in getattr(old_room, 'customAtts', {}).iteritems(): value = convert_to_unicode(value) if not value or ('Simba' in attr_name and value == u'Error: unknown mailing list'): continue attr_name = attribute_map.get(attr_name, attr_name).replace(' ', '-').lower() ca = l.get_attribute_by_name(attr_name) if not ca: print cformat( ' %{blue!}Attribute:%{reset} {} %{red!}not found' ).format(attr_name) continue attr = RoomAttributeAssociation() attr.value = value attr.attribute = ca r.attributes.append(attr) print cformat(' %{blue!}Attribute:%{reset} {} = {}').format( attr.attribute.title, attr.value) l.rooms.append(r) db.session.add(l) print db.session.commit()