Example #1
0
 def cabinet(self):
     if self.cabinet_id is not None:
         if self.cabinet_id == self.event_id:
             return self
         else:
             from uw_r25.events import get_event_by_id
             return get_event_by_id(self.cabinet_id)
Example #2
0
 def parent(self):
     if not hasattr(self, "_parent"):
         self._parent = None
         if self.parent_id is not None:
             from uw_r25.events import get_event_by_id
             self._parent = get_event_by_id(self.parent_id)
     return self._parent
Example #3
0
    def test_cabinet_event(self):
        event = get_event_by_id("100002")
        cabinet = event.cabinet()
        self.assertEquals(cabinet.event_id, event.cabinet_id, "cabinet_id")

        # cabinet is self
        cabinet2 = cabinet.cabinet()
        self.assertEquals(cabinet2.event_id, cabinet.event_id, "cabinet_id")
Example #4
0
    def test_parent_event(self):
        event = get_event_by_id("100002")
        parent = event.parent()
        self.assertEquals(parent.event_id, event.parent_id, "parent_id")

        # No parent event
        parent2 = parent.parent()
        self.assertEquals(parent2, None, "parent_id")
Example #5
0
    def test_child_events(self):
        event = get_event_by_id("100000")
        children = event.children()
        self.assertEquals(len(children), 1, "child event count")

        # No child events
        child = children[0]
        children = child.children()
        self.assertEquals(len(children), 0, "child event count")
Example #6
0
 def test_event_by_id(self):
     event = get_event_by_id("100000")
     self.assertEquals(event.event_id, "100000", "event_id")
     self.assertEquals(event.name, "BOTHELL WINTER 2013 CABINET", "name")
     self.assertEquals(event.title, "BOTHELL WINTER 2013 CABINET", "title")
     self.assertEquals(event.alien_uid, None, "alien_uid")
     self.assertEquals(event.start_date, "2013-01-01", "start_date")
     self.assertEquals(event.end_date, "2013-03-28", "end_date")
     self.assertEquals(event.state, "1", "state")
     self.assertEquals(event.parent_id, None, "parent_id")
     self.assertEquals(event.cabinet_id, event.event_id, "cabinet_id")
     self.assertEquals(event.cabinet_name, event.name, "cabinet_name")
     self.assertEquals(event.state_name(), "Tentative", "state_name")
     self.assertEquals(len(event.reservations), 1, "reservations")
     self.assertEquals(len(event.binding_reservations), 1,
                       "binding_reservations")
Example #7
0
    def handle(self, *args, **options):
        messages = []

        self.set_logger(options.get("verbosity"))

        if options["changed"]:
            if options["start"]:
                start_date = parse(options["start"]).date()
            else:
                start_date = datetime.date.today()
            if options["end"]:
                end_date = parse(options["end"]).date()
            else:
                end_date = datetime.date.today()

        else:
            if options["start"]:
                start_date = parse(options["start"]).date()
            else:
                start_date = datetime.date.today()
            if options["end"] == "max":
                end_date = datetime.date.max
            elif options["end"]:
                end_date = parse(options["end"]).date()
            else:
                end_date = start_date + datetime.timedelta(days=7)
        logger.info("Considering bookings from %s to %s" %
                    (start_date, end_date))

        _ems = Service()

        if settings.DEBUG:
            requests.urllib3.disable_warnings(InsecureRequestWarning)
        space_ids = update_get_space_ids(_ems.get_all_rooms())
        logger.info("Found %d R25 spaces linked to EMS rooms" % len(space_ids))

        status_list = _ems.get_statuses()
        statuses = {}
        search_statuses = []
        for status in status_list:
            statuses[status.id] = status
            if status.description not in settings.EMS_R25_IGNORE_STATUSES:
                search_statuses.append(status.id)
        logger.info("Considering statuses %s" %
                    ", ".join(statuses[status].description
                              for status in search_statuses))

        # Get all bookings in range, regardless of room, status, or event type.
        # We do this because a now-unwanted booking might already have been
        # Created in R25, and we need to cancel it there.
        if options["booking"]:
            logger.info("Looking for single booking %s" % options["booking"])
            try:
                bookings = [_ems.get_booking(options["booking"])]
            except IndexError:
                bookings = []
        elif options["reservation"]:
            logger.info("Looking for reservation %s" % options["reservation"])
            bookings = _ems.get_bookings2(
                reservation_id=options["reservation"],
                start_date=start_date.isoformat(),
                end_date=end_date.isoformat(),
            )
        elif options["changed"]:
            logger.info("Looking for changed bookings")
            bookings = _ems.get_changed_bookings(
                start_date=start_date.isoformat(),
                end_date=end_date.isoformat(),
                statuses=search_statuses,
            )
        else:
            logger.info("Looking for all bookings")
            bookings = _ems.get_bookings(
                start_date=start_date.isoformat(),
                end_date=end_date.isoformat(),
                statuses=search_statuses,
            )
        logger.info("Found %d bookings" % len(bookings))

        ems_reservations = {}
        current_num = 0
        for booking in bookings:
            current_num += 1
            if booking.date_changed is None:
                # get_booking doesn't return date_changed...
                booking.date_changed = datetime.date.min

            if options["changed"]:
                # Booking hasn't changed, EMS Reservation has...
                if (booking.date_changed.date() < start_date
                        or booking.date_changed.date() > end_date):
                    continue

            booking.status = statuses[booking.status_id]

            if booking.reservation_id not in ems_reservations:
                # Use data from first booking as reservation data.
                # FIXME: we need a way to grab actual EMS Reservation data
                # FIXME: instead of just Bookings
                ems_reservations[booking.reservation_id] = booking
                ems_reservations[booking.reservation_id].bookings = {}
            ems_reservations[booking.reservation_id].bookings[
                booking.id] = booking

            logger.debug(
                "Processing EMS Booking %d/%d %d: '%s'" %
                (current_num, len(bookings), booking.id, booking.event_name))
            logger.debug("\tStatus: %s, space_id: %s" % ((
                booking.status.description,
                space_ids.get(booking.room_id),
            )))
            logger.debug("\tStart: %s, End: %s, Changed: %s" % (
                booking.time_booking_start.isoformat(),
                booking.time_booking_end.isoformat(),
                booking.date_changed.isoformat(),
            ))

            r25_event = None
            try:
                events = get_events(
                    starts_with="%d_" % booking.id,
                    scope="extended",
                    include="reservations",
                )

                r25_event = events[0]

                if len(events) > 1:
                    logger.warning("\tFound multiple R25 events")
                    messages.append("\tFound multiple R25 events")
                    for event in events:
                        if event.reservations[0].space_reservation is None:
                            logger.warning("\tFound R25 event with no space "
                                           "reservation %s: %s" %
                                           (event.event_id, event.name))
                            messages.append("\tFound R25 event with no space "
                                            "reservation %s: %s" %
                                            (event.event_id, event.name))
                            if options["update"]:
                                logger.debug("\tDeleting!")
                                delete_event(event.event_id)
                        else:
                            r25_event = event

                logger.debug("\tFound R25 event %s: '%s'" %
                             (r25_event.event_id, r25_event.name))

            except IndexError:
                # No R25 event matching this EMS Booking
                logger.debug("\tNo R25 event found")
                pass
            except HTTPError as ex:
                # Server timeout, etc
                self.stdout.write("HTTP Error retrieving R25 Event, skipping "
                                  "Booking %s: %s" % (booking.id, ex))
                messages.append("HTTP Error retrieving R25 Event, skipping "
                                "Booking %s: %s" % (booking.id, ex))
                continue
            except XMLSyntaxError as ex:
                # Bad response from R25 server - usually means outage
                self.stdout.write("XML Error retrieving R25 Event, skipping "
                                  "Booking %s: %s" % (booking.id, ex))
                messages.append("XML Error retrieving R25 Event, skipping "
                                "Booking %s: %s" % (booking.id, ex))
                continue

            if options["delete"]:
                if r25_event:
                    logger.debug("\tDeleting!")
                    delete_event(r25_event.event_id)
                else:
                    logger.debug("\tNothing to delete.")
                continue

            wanted_booking = True
            if booking.status_type_id != Status.STATUS_TYPE_BOOKED_SPACE:
                wanted_booking = False
            elif booking.room_id not in space_ids:
                wanted_booking = False
            elif (booking.status.description
                  in settings.EMS_R25_REMOVE_STATUSES):
                wanted_booking = False
            elif (booking.status.description
                  in settings.EMS_R25_IGNORE_STATUSES):
                wanted_booking = False

            if r25_event is None:
                # Do we even want in r25?
                if not wanted_booking:
                    logger.debug("\t\tGood")
                    continue

                # Need to create r25 event
                logger.debug("\t\tWill create")
                r25_event = Event()
                r25_event.reservations = []

                r25_res = Reservation()
                r25_res.space_reservation = None
                r25_event.reservations.append(r25_res)

            event_name = booking.event_name
            if isinstance(event_name, six.text_type):
                event_name = unicodedata.normalize("NFKD", event_name).encode(
                    "ascii", "ignore")
                event_name = six.ensure_text(event_name)

            r25_event.name = "%d_%s" % (
                booking.id,
                event_name[:30].strip().upper(),
            )
            r25_event.title = event_name.strip()
            r25_event.state = r25_event.CONFIRMED_STATE
            r25_event.event_type_id = settings.EMS_R25_EVENTTYPE_MAP.get(
                booking.status.description, settings.EMS_R25_EVENTTYPE_DEFAULT)

            r25_res = r25_event.reservations[0]

            if wanted_booking:
                r25_res.start_datetime = booking.time_booking_start.isoformat()
                r25_res.end_datetime = booking.time_booking_end.isoformat()
                r25_res.state = r25_res.STANDARD_STATE
                if r25_res.space_reservation is None:
                    r25_res.space_reservation = Space()

                r25_res.space_reservation.space_id = space_ids[booking.room_id]

            else:
                # Cancel this unwanted r25 event
                logger.debug("\t\tSetting event state to cancelled")
                r25_event.state = r25_event.CANCELLED_STATE
                r25_res.state = r25_res.CANCELLED_STATE
                # r25_res.space_reservation = None

            # by default, don't actually make changes
            if not options["update"]:
                continue

            try:
                logger.debug("\tUpdating event")
                updated = update_event(r25_event)
                logger.debug("\t\tUpdated event %s" % updated.event_id)

            except R25MessageException as ex:
                while ex:
                    if ex.msg_id == "EV_I_SPACECON":
                        logger.warning(
                            "Conflict while syncing EMS Booking %s: %s" %
                            (booking.id, ex.text))
                        messages.append(
                            "Conflict while syncing EMS Booking %s: %s" %
                            (booking.id, ex.text))
                        match = re.search(r"\[(?P<event_id>\d+)\]", ex.text)
                        if match:
                            old_event = get_event_by_id(
                                match.group("event_id"))
                            logger.warning("Existing event: %s" %
                                           old_event.live_url())
                            messages.append("Existing event: %s" %
                                            old_event.live_url())
                            logger.warning("Is blocking event: %s" %
                                           r25_event.live_url())
                            messages.append("Is blocking event: %s" %
                                            r25_event.live_url())

                    else:
                        logger.warning(
                            "R25 message while syncing EMS Booking %s to "
                            "R25 Event %s: %s" %
                            (booking.id, r25_event.event_id, ex))
                        messages.append(
                            "R25 message while syncing EMS Booking %s to "
                            "R25 Event %s: %s" %
                            (booking.id, r25_event.event_id, ex))

                    ex = ex.next_msg

            except R25ErrorException as ex:
                logger.warning(
                    "R25 error while syncing EMS Booking %s to R25 Event "
                    " %s: %s" % (booking.id, r25_event.event_id, ex))
                messages.append(
                    "R25 error while syncing EMS Booking %s to R25 Event "
                    " %s: %s" % (booking.id, r25_event.event_id, ex))

            except HTTPError as ex:
                logger.warning(
                    "HTTP error while syncing EMS Booking %s to R25 Event "
                    " %s: %s" % (booking.id, r25_event.event_id, ex))
                messages.append(
                    "HTTP error while syncing EMS Booking %s to R25 Event "
                    " %s: %s" % (booking.id, r25_event.event_id, ex))

            except TooManyRequestsException:
                self.stdout.write(
                    "Too Many Requests while syncing EMS Booking %s to "
                    "R25 Event %s" % (booking.id, r25_event.event_id))
                messages.append(
                    "Too Many Requests while syncing EMS Booking %s to "
                    "R25 Event %s" % (booking.id, r25_event.event_id))

        # send email
        if len(messages) > 0:
            send_mail(
                'EMS2R25 report',
                '\n'.join(messages),
                settings.EMS2R25_EMAIL_HOST_USER,
                settings.EMS2R25_EMAIL_RECIPIENTS,
                fail_silently=False,
                auth_user=settings.EMS2R25_EMAIL_HOST_USER,
                auth_password=settings.EMS2R25_EMAIL_HOST_PASSWORD,
            )