def _serializable_reservation(reservation_data, include_room=False): """Serializable reservation (standalone or inside room) :param reservation_data: Reservation data :param include_room: Include minimal room information """ reservation = reservation_data['reservation'] data = reservation.to_serializable('__api_public__', converters={datetime: _add_server_tz}) data['_type'] = 'Reservation' data['repeatability'] = None if reservation.repeat_frequency: data['repeatability'] = RepeatMapping.get_short_name( *reservation.repetition) data['vcList'] = reservation_data['vc_equipment'] if include_room: data['room'] = _serializable_room_minimal( reservation_data['reservation'].room) if 'occurrences' in reservation_data: data['occurrences'] = [ o.to_serializable('__api_public__', converters={datetime: _add_server_tz}) for o in reservation_data['occurrences'] ] return data
def _getPageContent(self, params): reservation = params['reservation'] params['endpoints'] = self.endpoints params['assistance_emails'] = rb_settings.get('assistance_emails') params['repetition'] = RepeatMapping.get_message(*reservation.repetition) params['edit_logs'] = reservation.edit_logs.order_by(ReservationEditLog.timestamp.desc()).all() params['excluded_days'] = reservation.find_excluded_days().all() return WTemplated('RoomBookingDetails').getHTML(params)
def _getBody(self, params): reservation = params['reservation'] params['endpoints'] = self.endpoints params['assistance_emails'] = settings.get('assistance_emails', []) params['vc_equipment'] = ', '.join(eq.name for eq in reservation.get_vc_equipment()) params['repetition'] = RepeatMapping.get_message(*reservation.repetition) params['edit_logs'] = reservation.edit_logs.order_by(ReservationEditLog.timestamp.desc()).all() params['excluded_days'] = reservation.find_excluded_days().all() return WTemplated('RoomBookingDetails').getHTML(params)
def _getBody(self, params): reservation = params["reservation"] params["endpoints"] = self.endpoints params["assistance_emails"] = rb_settings.get("assistance_emails") params["vc_equipment"] = ", ".join(eq.name for eq in reservation.get_vc_equipment()) params["repetition"] = RepeatMapping.get_message(*reservation.repetition) params["edit_logs"] = reservation.edit_logs.order_by(ReservationEditLog.timestamp.desc()).all() params["excluded_days"] = reservation.find_excluded_days().all() return WTemplated("RoomBookingDetails").getHTML(params)
def _show_confirm(self, room, form, step=None, defaults=None): # form can be PeriodForm or Confirmform depending on the step we come from if step == 2: confirm_form = self._make_confirm_form(room, step, defaults=defaults) else: # Step3 => Step3 due to an error in the form confirm_form = form conflicts, pre_conflicts = self._get_all_conflicts(room, form) repeat_msg = RepeatMapping.get_message(form.repeat_frequency.data, form.repeat_interval.data) return self._get_view('confirm', form=confirm_form, room=room, start_dt=form.start_dt.data, end_dt=form.end_dt.data, repeat_frequency=form.repeat_frequency.data, repeat_interval=form.repeat_interval.data, repeat_msg=repeat_msg, conflicts=conflicts, pre_conflicts=pre_conflicts, errors=confirm_form.error_list).display()
def _serializable_reservation(reservation_data, include_room=False): """Serializable reservation (standalone or inside room) :param reservation_data: Reservation data :param include_room: Include minimal room information """ reservation = reservation_data['reservation'] data = reservation.to_serializable('__api_public__', converters={datetime: _add_server_tz}) data['_type'] = 'Reservation' data['repeatability'] = None if reservation.repeat_frequency: data['repeatability'] = RepeatMapping.get_short_name(*reservation.repetition) if include_room: data['room'] = _serializable_room_minimal(reservation_data['reservation'].room) if 'occurrences' in reservation_data: data['occurrences'] = [o.to_serializable('__api_public__', converters={datetime: _add_server_tz}) for o in reservation_data['occurrences']] return data
def _process(self): key = str(sorted(dict(request.args, lang=session.lang, user=session.user.getId()).items())) html = self._cache.get(key) if not html: default_location = Location.default_location aspects = [a.to_serializable() for a in default_location.aspects] buildings = default_location.get_buildings() html = WPRoomBookingMapOfRoomsWidget(self, aspects=aspects, buildings=buildings, room_id=self._room_id, default_repeat='{}|0'.format(RepeatFrequency.NEVER), default_start_dt=datetime.combine(date.today(), Location.working_time_start), default_end_dt=datetime.combine(date.today(), Location.working_time_end), repeat_mapping=RepeatMapping.getMapping()).display() self._cache.set(key, html, 3600) return html
def _serializable_reservation(reservation_data, include_room=False): """Serializable reservation (standalone or inside room). :param reservation_data: Reservation data :param include_room: Include minimal room information """ from indico.modules.rb.schemas import ReservationLegacyAPISchema, ReservationOccurrenceLegacyAPISchema reservation = reservation_data['reservation'] data = ReservationLegacyAPISchema().dump(reservation) data['_type'] = 'Reservation' data['repeatability'] = None if reservation.repeat_frequency: data['repeatability'] = RepeatMapping.get_short_name( *reservation.repetition) if include_room: data['room'] = _serializable_room_minimal( reservation_data['reservation'].room) if 'occurrences' in reservation_data: data['occurrences'] = ReservationOccurrenceLegacyAPISchema( many=True).dump(reservation_data['occurrences']) return data
def migrate_reservations(self): print cformat("%{white!}migrating reservations") i = 1 for rid, v in self.rb_root["Reservations"].iteritems(): room = Room.get(v.room.id) if room is None: print cformat(" %{red!}skipping resv for dead room {0.room.id}: {0.id} ({0._utcCreatedDT})").format(v) continue repeat_frequency, repeat_interval = RepeatMapping.convert_legacy_repeatability(v.repeatability) booked_for_id = getattr(v, "bookedForId", None) r = Reservation( id=v.id, created_dt=as_utc(v._utcCreatedDT), start_dt=utc_to_local(v._utcStartDT), end_dt=utc_to_local(v._utcEndDT), booked_for_id=self.merged_avatars.get(booked_for_id, booked_for_id) or None, booked_for_name=convert_to_unicode(v.bookedForName), contact_email=convert_to_unicode(v.contactEmail), contact_phone=convert_to_unicode(getattr(v, "contactPhone", None)), created_by_id=self.merged_avatars.get(v.createdBy, v.createdBy) or None, is_cancelled=v.isCancelled, is_accepted=v.isConfirmed, is_rejected=v.isRejected, booking_reason=convert_to_unicode(v.reason), rejection_reason=convert_to_unicode(getattr(v, "rejectionReason", None)), repeat_frequency=repeat_frequency, repeat_interval=repeat_interval, uses_vc=getattr(v, "usesAVC", False), needs_vc_assistance=getattr(v, "needsAVCSupport", False), needs_assistance=getattr(v, "needsAssistance", False), ) for eq_name in getattr(v, "useVC", []): eq = room.location.get_equipment_by_name(eq_name) if eq: r.used_equipment.append(eq) occurrence_rejection_reasons = {} if getattr(v, "resvHistory", None): for h in reversed(v.resvHistory._entries): ts = as_utc(parse_dt_string(h._timestamp)) if len(h._info) == 2: possible_rejection_date, possible_rejection_reason = h._info m = re.match( r"Booking occurrence of the (\d{1,2} \w{3} \d{4}) rejected", possible_rejection_reason ) if m: d = datetime.strptime(m.group(1), "%d %b %Y") occurrence_rejection_reasons[d] = possible_rejection_reason[9:].strip("'") el = ReservationEditLog( timestamp=ts, user_name=h._responsibleUser, info=map(convert_to_unicode, h._info) ) r.edit_logs.append(el) notifications = getattr(v, "startEndNotification", []) or [] excluded_days = getattr(v, "_excludedDays", []) or [] ReservationOccurrence.create_series_for_reservation(r) for occ in r.occurrences: occ.notification_sent = occ.date in notifications occ.is_rejected = r.is_rejected occ.is_cancelled = r.is_cancelled or occ.date in excluded_days occ.rejection_reason = ( convert_to_unicode(occurrence_rejection_reasons[occ.date]) if occ.date in occurrence_rejection_reasons else None ) event_id = getattr(v, "_ReservationBase__owner", None) if hasattr(event_id, "_Impersistant__obj"): # Impersistant object event_id = event_id._Impersistant__obj if event_id is not None: event = self.zodb_root["conferences"].get(event_id) if event: # For some stupid reason there are bookings in the database which have a completely unrelated parent guids = getattr(event, "_Conference__roomBookingGuids", []) if any(int(x.id) == v.id for x in guids if x.id is not None): r.event_id = int(event_id) else: print cformat(" %{red}event {} does not contain booking {}").format(event_id, v.id) print cformat("- [%{cyan}{}%{reset}/%{green!}{}%{reset}] %{grey!}{}%{reset} {}").format( room.location_name, room.name, r.id, r.created_dt.date() ) room.reservations.append(r) db.session.add(room) i = (i + 1) % 1000 if not i: db.session.commit() db.session.commit()
def test_repeat_mapping(repetition, message): assert RepeatMapping.get_message(*repetition) == message
def find_with_filters(filters, user=None): from indico.modules.rb.models.locations import Location equipment_count = len(filters.get('available_equipment', ())) equipment_subquery = None if equipment_count: equipment_subquery = ( db.session.query(RoomEquipmentAssociation) .with_entities(func.count(RoomEquipmentAssociation.c.room_id)) .filter( RoomEquipmentAssociation.c.room_id == Room.id, RoomEquipmentAssociation.c.equipment_id.in_(eq.id for eq in filters['available_equipment']) ) .correlate(Room) .as_scalar() ) capacity = filters.get('capacity') q = ( Room.query .join(Location.rooms) .filter( Location.id == filters['location'].id if filters.get('location') else True, ((Room.capacity >= (capacity * 0.8)) | (Room.capacity == None)) if capacity else True, Room.is_reservable if filters.get('is_only_public') else True, Room.is_auto_confirm if filters.get('is_auto_confirm') else True, Room.is_active if filters.get('is_only_active', False) else True, (equipment_subquery == equipment_count) if equipment_subquery is not None else True) ) if filters.get('available', -1) != -1: repetition = RepeatMapping.convert_legacy_repeatability(ast.literal_eval(filters['repeatability'])) is_available = Room.filter_available(filters['start_dt'], filters['end_dt'], repetition, include_pre_bookings=filters.get('include_pre_bookings', True), include_pending_blockings=filters.get('include_pending_blockings', True)) # Filter the search results if filters['available'] == 0: # booked/unavailable q = q.filter(~is_available) elif filters['available'] == 1: # available q = q.filter(is_available) else: raise ValueError('Unexpected availability value') free_search_columns = ( 'name', 'site', 'division', 'building', 'floor', 'number', 'telephone', 'key_location', 'comments' ) if filters.get('details'): # Attributes are stored JSON-encoded, so we need to JSON-encode the provided string and remove the quotes # afterwards since PostgreSQL currently does not expose a function to decode a JSON string: # http://www.postgresql.org/message-id/[email protected] details = filters['details'].lower() details_str = u'%{}%'.format(escape_like(details)) details_json = u'%{}%'.format(escape_like(json.dumps(details)[1:-1])) free_search_criteria = [getattr(Room, c).ilike(details_str) for c in free_search_columns] free_search_criteria.append(Room.attributes.any(cast(RoomAttributeAssociation.value, db.String) .ilike(details_json))) q = q.filter(or_(*free_search_criteria)) q = q.order_by(Room.capacity) rooms = q.all() # Apply a bunch of filters which are *much* easier to do here than in SQL! if filters.get('is_only_public'): # This may trigger additional SQL queries but is_public is cached and doing this check here is *much* easier rooms = [r for r in rooms if r.is_public] if filters.get('is_only_my_rooms'): assert user is not None rooms = [r for r in rooms if r.is_owned_by(user)] if capacity: # Unless it would result in an empty resultset we don't want to show rooms with >20% more capacity # than requested. This cannot be done easily in SQL so we do that logic here after the SQL query already # weeded out rooms that are too small matching_capacity_rooms = [r for r in rooms if r.capacity is None or r.capacity <= capacity * 1.2] if matching_capacity_rooms: rooms = matching_capacity_rooms return rooms
def test_repeat_mapping_invalid_legacy(): with pytest.raises(IndicoError): RepeatMapping.convert_legacy_repeatability(123)
def test_repeat_mapping(repetition, legacy, short_name, message): assert RepeatMapping.get_message(*repetition) == message assert RepeatMapping.get_short_name(*repetition) == short_name assert RepeatMapping.convert_legacy_repeatability(legacy) == repetition
def migrate_reservations(self): print cformat('%{white!}migrating reservations') i = 1 for rid, v in self.rb_root['Reservations'].iteritems(): room = Room.get(v.room.id) if room is None: print cformat( ' %{red!}skipping resv for dead room {0.room.id}: {0.id} ({0._utcCreatedDT})' ).format(v) continue repeat_frequency, repeat_interval = RepeatMapping.convert_legacy_repeatability( v.repeatability) booked_for_id = getattr(v, 'bookedForId', None) r = Reservation( id=v.id, created_dt=as_utc(v._utcCreatedDT), start_dt=utc_to_local(v._utcStartDT), end_dt=utc_to_local(v._utcEndDT), booked_for_id=self.merged_avatars.get(booked_for_id, booked_for_id) or None, booked_for_name=convert_to_unicode(v.bookedForName), contact_email=convert_to_unicode(v.contactEmail), contact_phone=convert_to_unicode( getattr(v, 'contactPhone', None)), created_by_id=self.merged_avatars.get(v.createdBy, v.createdBy) or None, is_cancelled=v.isCancelled, is_accepted=v.isConfirmed, is_rejected=v.isRejected, booking_reason=convert_to_unicode(v.reason), rejection_reason=convert_to_unicode( getattr(v, 'rejectionReason', None)), repeat_frequency=repeat_frequency, repeat_interval=repeat_interval, uses_vc=getattr(v, 'usesAVC', False), needs_vc_assistance=getattr(v, 'needsAVCSupport', False), needs_assistance=getattr(v, 'needsAssistance', False)) for eq_name in getattr(v, 'useVC', []): eq = room.location.get_equipment_by_name(eq_name) if eq: r.used_equipment.append(eq) occurrence_rejection_reasons = {} if getattr(v, 'resvHistory', None): for h in reversed(v.resvHistory._entries): ts = as_utc(parse_dt_string(h._timestamp)) if len(h._info) == 2: possible_rejection_date, possible_rejection_reason = h._info m = re.match( r'Booking occurrence of the (\d{1,2} \w{3} \d{4}) rejected', possible_rejection_reason) if m: d = datetime.strptime(m.group(1), '%d %b %Y') occurrence_rejection_reasons[ d] = possible_rejection_reason[9:].strip('\'') el = ReservationEditLog(timestamp=ts, user_name=h._responsibleUser, info=map(convert_to_unicode, h._info)) r.edit_logs.append(el) notifications = getattr(v, 'startEndNotification', []) or [] excluded_days = getattr(v, '_excludedDays', []) or [] ReservationOccurrence.create_series_for_reservation(r) for occ in r.occurrences: occ.notification_sent = occ.date in notifications occ.is_rejected = r.is_rejected occ.is_cancelled = r.is_cancelled or occ.date in excluded_days occ.rejection_reason = ( convert_to_unicode(occurrence_rejection_reasons[occ.date]) if occ.date in occurrence_rejection_reasons else None) event_id = getattr(v, '_ReservationBase__owner', None) if hasattr(event_id, '_Impersistant__obj'): # Impersistant object event_id = event_id._Impersistant__obj if event_id is not None: event = self.zodb_root['conferences'].get(event_id) if event: # For some stupid reason there are bookings in the database which have a completely unrelated parent guids = getattr(event, '_Conference__roomBookingGuids', []) if any( int(x.id) == v.id for x in guids if x.id is not None): r.event_id = int(event_id) else: print cformat( ' %{red}event {} does not contain booking {}' ).format(event_id, v.id) print cformat( '- [%{cyan}{}%{reset}/%{green!}{}%{reset}] %{grey!}{}%{reset} {}' ).format(room.location_name, room.name, r.id, r.created_dt.date()) room.reservations.append(r) db.session.add(room) i = (i + 1) % 1000 if not i: db.session.commit() db.session.commit()
def convert_reservation_repeatability(old): return RepeatMapping.getNewMapping(old)