Пример #1
0
def test_create_series_for_reservation(dummy_reservation):
    ReservationOccurrence.create_series_for_reservation(dummy_reservation)
    occurrences = ReservationOccurrence.iter_create_occurrences(start=dummy_reservation.start_dt,
                                                                end=dummy_reservation.end_dt,
                                                                repetition=dummy_reservation.repetition)
    for occ1, occ2 in izip(dummy_reservation.occurrences, occurrences):
        assert occ1.start_dt == occ2.start_dt
        assert occ1.end_dt == occ2.end_dt
        assert occ1.is_cancelled == dummy_reservation.is_cancelled
        assert occ1.is_rejected == dummy_reservation.is_rejected
        assert occ1.rejection_reason == dummy_reservation.rejection_reason
Пример #2
0
    def create_occurrences(self, skip_conflicts, user=None, allow_admin=True):
        ReservationOccurrence.create_series_for_reservation(self)
        db.session.flush()

        if user is None:
            user = self.created_by_user

        # Check for conflicts with nonbookable periods
        admin = allow_admin and rb_is_admin(user)
        if not admin and not self.room.can_manage(user, permission='override'):
            nonbookable_periods = self.room.nonbookable_periods.filter(NonBookablePeriod.end_dt > self.start_dt)
            for occurrence in self.occurrences:
                if not occurrence.is_valid:
                    continue
                for nbd in nonbookable_periods:
                    if nbd.overlaps(occurrence.start_dt, occurrence.end_dt):
                        if not skip_conflicts:
                            raise ConflictingOccurrences()
                        occurrence.cancel(user, 'Skipped due to nonbookable date', silent=True, propagate=False)
                        break

        # Check for conflicts with blockings
        blocked_rooms = self.room.get_blocked_rooms(*(occurrence.start_dt for occurrence in self.occurrences))
        for br in blocked_rooms:
            blocking = br.blocking
            if blocking.can_override(user, room=self.room, allow_admin=allow_admin):
                continue
            for occurrence in self.occurrences:
                if occurrence.is_valid and blocking.is_active_at(occurrence.start_dt.date()):
                    # Cancel OUR occurrence
                    msg = 'Skipped due to collision with a blocking ({})'
                    occurrence.cancel(user, msg.format(blocking.reason), silent=True, propagate=False)

        # Check for conflicts with other occurrences
        conflicting_occurrences = self.get_conflicting_occurrences()
        for occurrence, conflicts in conflicting_occurrences.items():
            if not occurrence.is_valid:
                continue
            if conflicts['confirmed']:
                if not skip_conflicts:
                    raise ConflictingOccurrences()
                # Cancel OUR occurrence
                msg = 'Skipped due to collision with {} reservation(s)'
                occurrence.cancel(user, msg.format(len(conflicts['confirmed'])), silent=True, propagate=False)
            elif conflicts['pending'] and self.is_accepted:
                # Reject OTHER occurrences
                for conflict in conflicts['pending']:
                    conflict.reject(user, 'Rejected due to collision with a confirmed reservation')
Пример #3
0
    def create_occurrences(self, skip_conflicts, user=None):
        ReservationOccurrence.create_series_for_reservation(self)
        db.session.flush()

        if user is None:
            user = self.created_by_user

        # Check for conflicts with nonbookable periods
        if not user.isRBAdmin():
            nonbookable_periods = self.room.nonbookable_periods.filter(NonBookablePeriod.end_dt > self.start_dt)
            for occurrence in self.occurrences:
                if not occurrence.is_valid:
                    continue
                for nbd in nonbookable_periods:
                    if nbd.overlaps(occurrence.start_dt, occurrence.end_dt):
                        if not skip_conflicts:
                            raise ConflictingOccurrences()
                        occurrence.cancel(user, u'Skipped due to nonbookable date', silent=True, propagate=False)
                        break

        # Check for conflicts with blockings
        blocked_rooms = self.room.get_blocked_rooms(*(occurrence.start_dt for occurrence in self.occurrences))
        for br in blocked_rooms:
            blocking = br.blocking
            if blocking.can_be_overridden(user, self.room):
                continue
            for occurrence in self.occurrences:
                if occurrence.is_valid and blocking.is_active_at(occurrence.start_dt.date()):
                    # Cancel OUR occurrence
                    msg = u'Skipped due to collision with a blocking ({})'
                    occurrence.cancel(user, msg.format(blocking.reason), silent=True, propagate=False)

        # Check for conflicts with other occurrences
        conflicting_occurrences = self.get_conflicting_occurrences()
        for occurrence, conflicts in conflicting_occurrences.iteritems():
            if not occurrence.is_valid:
                continue
            if conflicts['confirmed']:
                if not skip_conflicts:
                    raise ConflictingOccurrences()
                # Cancel OUR occurrence
                msg = u'Skipped due to collision with {} reservation(s)'
                occurrence.cancel(user, msg.format(len(conflicts['confirmed'])), silent=True, propagate=False)
            elif conflicts['pending'] and self.is_accepted:
                # Reject OTHER occurrences
                for conflict in conflicts['pending']:
                    conflict.reject(user, u'Rejected due to collision with a confirmed reservation')
Пример #4
0
    def create_occurrences(self, skip_conflicts, user=None):
        ReservationOccurrence.create_series_for_reservation(self)
        db.session.flush()

        if user is None:
            user = self.created_by_user

        # Check for conflicts with nonbookable periods
        if not rb_is_admin(user) and not self.room.is_owned_by(user):
            nonbookable_periods = self.room.nonbookable_periods.filter(NonBookablePeriod.end_dt > self.start_dt)
            for occurrence in self.occurrences:
                if not occurrence.is_valid:
                    continue
                for nbd in nonbookable_periods:
                    if nbd.overlaps(occurrence.start_dt, occurrence.end_dt):
                        if not skip_conflicts:
                            raise ConflictingOccurrences()
                        occurrence.cancel(user, u"Skipped due to nonbookable date", silent=True, propagate=False)
                        break

        # Check for conflicts with blockings
        blocked_rooms = self.room.get_blocked_rooms(*(occurrence.start_dt for occurrence in self.occurrences))
        for br in blocked_rooms:
            blocking = br.blocking
            if blocking.can_be_overridden(user, self.room):
                continue
            for occurrence in self.occurrences:
                if occurrence.is_valid and blocking.is_active_at(occurrence.start_dt.date()):
                    # Cancel OUR occurrence
                    msg = u"Skipped due to collision with a blocking ({})"
                    occurrence.cancel(user, msg.format(blocking.reason), silent=True, propagate=False)

        # Check for conflicts with other occurrences
        conflicting_occurrences = self.get_conflicting_occurrences()
        for occurrence, conflicts in conflicting_occurrences.iteritems():
            if not occurrence.is_valid:
                continue
            if conflicts["confirmed"]:
                if not skip_conflicts:
                    raise ConflictingOccurrences()
                # Cancel OUR occurrence
                msg = u"Skipped due to collision with {} reservation(s)"
                occurrence.cancel(user, msg.format(len(conflicts["confirmed"])), silent=True, propagate=False)
            elif conflicts["pending"] and self.is_accepted:
                # Reject OTHER occurrences
                for conflict in conflicts["pending"]:
                    conflict.reject(user, u"Rejected due to collision with a confirmed reservation")

        # Mark occurrences created within the notification window as notified
        for occurrence in self.occurrences:
            if occurrence.is_valid and occurrence.is_in_notification_window():
                occurrence.notification_sent = True

        # Mark occurrences created within the digest window as notified
        if self.repeat_frequency == RepeatFrequency.WEEK:
            if self.room.is_in_digest_window():
                digest_start = round_up_month(date.today())
            else:
                digest_start = date.today()
            digest_end = get_month_end(digest_start)
            self.occurrences.filter(ReservationOccurrence.start_dt <= digest_end).update({"notification_sent": True})
Пример #5
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()
Пример #6
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()
Пример #7
0
    def create_occurrences(self, skip_conflicts, user=None):
        ReservationOccurrence.create_series_for_reservation(self)
        db.session.flush()

        if user is None:
            user = self.created_by_user

        # Check for conflicts with nonbookable periods
        if not user.isRBAdmin() and not self.room.is_owned_by(user):
            nonbookable_periods = self.room.nonbookable_periods.filter(
                NonBookablePeriod.end_dt > self.start_dt)
            for occurrence in self.occurrences:
                if not occurrence.is_valid:
                    continue
                for nbd in nonbookable_periods:
                    if nbd.overlaps(occurrence.start_dt, occurrence.end_dt):
                        if not skip_conflicts:
                            raise ConflictingOccurrences()
                        occurrence.cancel(user,
                                          u'Skipped due to nonbookable date',
                                          silent=True,
                                          propagate=False)
                        break

        # Check for conflicts with blockings
        blocked_rooms = self.room.get_blocked_rooms(
            *(occurrence.start_dt for occurrence in self.occurrences))
        for br in blocked_rooms:
            blocking = br.blocking
            if blocking.can_be_overridden(user, self.room):
                continue
            for occurrence in self.occurrences:
                if occurrence.is_valid and blocking.is_active_at(
                        occurrence.start_dt.date()):
                    # Cancel OUR occurrence
                    msg = u'Skipped due to collision with a blocking ({})'
                    occurrence.cancel(user,
                                      msg.format(blocking.reason),
                                      silent=True,
                                      propagate=False)

        # Check for conflicts with other occurrences
        conflicting_occurrences = self.get_conflicting_occurrences()
        for occurrence, conflicts in conflicting_occurrences.iteritems():
            if not occurrence.is_valid:
                continue
            if conflicts['confirmed']:
                if not skip_conflicts:
                    raise ConflictingOccurrences()
                # Cancel OUR occurrence
                msg = u'Skipped due to collision with {} reservation(s)'
                occurrence.cancel(user,
                                  msg.format(len(conflicts['confirmed'])),
                                  silent=True,
                                  propagate=False)
            elif conflicts['pending'] and self.is_accepted:
                # Reject OTHER occurrences
                for conflict in conflicts['pending']:
                    conflict.reject(
                        user,
                        u'Rejected due to collision with a confirmed reservation'
                    )

        # Mark occurrences created within the notification window as notified
        for occurrence in self.occurrences:
            if occurrence.is_valid and occurrence.is_in_notification_window():
                occurrence.notification_sent = True

        # Mark occurrences created within the digest window as notified
        if self.repeat_frequency == RepeatFrequency.WEEK:
            if self.room.is_in_digest_window():
                digest_start = round_up_month(date.today())
            else:
                digest_start = date.today()
            digest_end = get_month_end(digest_start)
            self.occurrences.filter(
                ReservationOccurrence.start_dt <= digest_end).update(
                    {'notification_sent': True})