Beispiel #1
0
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
Beispiel #2
0
 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)
Beispiel #3
0
 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)
Beispiel #4
0
 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)
Beispiel #5
0
    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()
Beispiel #6
0
    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()
Beispiel #7
0
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
Beispiel #8
0
 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
Beispiel #9
0
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
Beispiel #10
0
    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()
Beispiel #11
0
def test_repeat_mapping(repetition, message):
    assert RepeatMapping.get_message(*repetition) == message
Beispiel #12
0
    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
Beispiel #13
0
def test_repeat_mapping(repetition, message):
    assert RepeatMapping.get_message(*repetition) == message
Beispiel #14
0
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
Beispiel #16
0
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 test_repeat_mapping_invalid_legacy():
    with pytest.raises(IndicoError):
        RepeatMapping.convert_legacy_repeatability(123)
Beispiel #18
0
    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)