Ejemplo n.º 1
0
 def testEventIndex(self):
     """Make sure eventsInRange works."""
     daysEvents = list(Calendar.eventsInRange(self.view, self.midnight,
                                              self.midnight + timedelta(1))) 
     self.assertEqual(daysEvents[0], self.pacificEvent)
     self.assertEqual(daysEvents[1], self.floatingEvent)
     self.assertEqual(daysEvents[2], self.hawaiiEvent)
Ejemplo n.º 2
0
def itemsToFreeBusy(view, start, end, calname = None):
    """
    Create FREEBUSY components corresponding to all events between start and 
    end.
        
    """
    all = schema.ns("osaf.pim", view).allCollection
    normal    = Calendar.eventsInRange(view, start, end, all)
    recurring = Calendar.recurringEventsInRange(view, start, end, all)
    events = Calendar._sortEvents(itertools.chain(normal, recurring),
                                  attrName='effectiveStartTime')
    
    def toUTC(dt):
        if dt < start: dt = start
        elif dt > end: dt = end
        return translateToTimezone(dt, view.tzinfo.UTC)
    
    cal = vobject.iCalendar()
    
    if calname is not None:
        cal.add('x-wr-calname').value = calname
    vfree = cal.add('vfreebusy')
    vfree.add('dtstart').value = toUTC(start)
    vfree.add('dtend').value   = toUTC(end)
    
    def addFB(event):
        free = vfree.add('freebusy')
        free.fbtype_param = transparencyMap[event.transparency]
        return free

    free = None
    for event in events:
        # ignore anytime events, events with no duration, and fyi events
        if (event.transparency == 'fyi' or
            ((event.anyTime or event.duration == datetime.timedelta(0)) and 
             not event.allDay)):
            continue
        if free is None or free.fbtype_param != \
                           transparencyMap[event.transparency]:
            free = addFB(event)
            free.value = [[toUTC(event.effectiveStartTime),
                           event.effectiveEndTime]]
        else:
            # compress freebusy blocks if possible
            if event.effectiveStartTime <= free.value[-1][1]:
                if event.effectiveEndTime > free.value[-1][1]:
                    free.value[-1][1] = event.effectiveEndTime
            else:
                free.value.append([toUTC(event.effectiveStartTime),
                                   event.effectiveEndTime])

    # once upon a time serialize would convert (date, date) to (date, period)
    # but no longer.  So there's no need to serialize
    # vfree.serialize()

    return cal
Ejemplo n.º 3
0
 def testReorderFloating(self):
     """Changes to floating time should cause events to be reindexed."""
     self.tzInfoItem.default = self.eastern
     daysEvents = list(Calendar.eventsInRange(self.view, self.midnight,
                                              self.midnight + timedelta(1)))
     #print [i.startTime for i in daysEvents]
     self.assertEqual(daysEvents[0], self.easternEvent)
     self.assertEqual(daysEvents[1], self.floatingEvent)
     self.assertEqual(daysEvents[2], self.pacificEvent)
     self.assertEqual(daysEvents[3], self.hawaiiEvent)
Ejemplo n.º 4
0
def itemsToFreeBusy(view, start, end, calname=None):
    """
    Create FREEBUSY components corresponding to all events between start and 
    end.
        
    """
    all = schema.ns("osaf.pim", view).allCollection
    normal = Calendar.eventsInRange(view, start, end, all)
    recurring = Calendar.recurringEventsInRange(view, start, end, all)
    events = Calendar._sortEvents(itertools.chain(normal, recurring), attrName="effectiveStartTime")

    def toUTC(dt):
        if dt < start:
            dt = start
        elif dt > end:
            dt = end
        return translateToTimezone(dt, view.tzinfo.UTC)

    cal = vobject.iCalendar()

    if calname is not None:
        cal.add("x-wr-calname").value = calname
    vfree = cal.add("vfreebusy")
    vfree.add("dtstart").value = toUTC(start)
    vfree.add("dtend").value = toUTC(end)

    def addFB(event):
        free = vfree.add("freebusy")
        free.fbtype_param = transparencyMap[event.transparency]
        return free

    free = None
    for event in events:
        # ignore anytime events, events with no duration, and fyi events
        if event.transparency == "fyi" or (
            (event.anyTime or event.duration == datetime.timedelta(0)) and not event.allDay
        ):
            continue
        if free is None or free.fbtype_param != transparencyMap[event.transparency]:
            free = addFB(event)
            free.value = [[toUTC(event.effectiveStartTime), event.effectiveEndTime]]
        else:
            # compress freebusy blocks if possible
            if event.effectiveStartTime <= free.value[-1][1]:
                if event.effectiveEndTime > free.value[-1][1]:
                    free.value[-1][1] = event.effectiveEndTime
            else:
                free.value.append([toUTC(event.effectiveStartTime), event.effectiveEndTime])

    # once upon a time serialize would convert (date, date) to (date, period)
    # but no longer.  So there's no need to serialize
    # vfree.serialize()

    return cal
Ejemplo n.º 5
0
def updateFreebusyFromVObject(view, text, busyCollection, activity=None):
    """
    Take a string, create or update freebusy events in busyCollection from that
    stream.

    Truncate differing existing freebusy events that overlap the start or end
    times.

    Returns (freebusystart, freebusyend, calname).

    """

    newItemParent = view.findPath("//userdata")

    countNew = 0
    countUpdated = 0

    freebusystart = freebusyend = None

    Calendar.ensureIndexed(busyCollection)

    # iterate over calendars, usually only one, but more are allowed
    for calendar in vobject.readComponents(text, validate=True, ignoreUnreadable=True):
        calname = calendar.getChildValue("x_wr_calname")

        for vfreebusy in calendar.vfreebusy_list:
            # RPI's server originally didn't put a VERSION:2.0 line in its
            # freebusy response.  vobject's behavior is set when a VERSION is
            # found.  Tolerate servers that export technically illegal but still
            # readable vfreebusy components
            if vfreebusy.behavior is None:
                vfreebusy.behavior = vobject.icalendar.VFreeBusy
                vfreebusy.transformToNative()

            start = vfreebusy.getChildValue("dtstart")
            end = vfreebusy.getChildValue("dtend")
            if freebusystart is None or freebusystart > start:
                freebusystart = start
            if freebusyend is None or freebusyend < end:
                freebusyend = end

            # create a list of busy blocks tuples sorted by start time
            busyblocks = []
            for fb in getattr(vfreebusy, "freebusy_list", []):
                status = getattr(fb, "fbtype_param", "BUSY").upper()
                for blockstart, duration in fb.value:
                    blockstart = translateToTimezone(blockstart, view.tzinfo.default)
                    bisect.insort(busyblocks, (blockstart, duration, status))

            # eventsInRange sorts by start time, recurring events aren't allowed
            # so we don't bother to fetch them
            existing = Calendar.eventsInRange(view, start, end, busyCollection)
            existing = itertools.chain(existing, [None])

            oldEvent = existing.next()
            for blockstart, duration, status in busyblocks:
                while oldEvent is not None and oldEvent.startTime < blockstart:
                    # this assumes no freebusy blocks overlap freebusystart
                    oldEvent.delete()
                    oldEvent = existing.next()
                if oldEvent is not None and oldEvent.startTime == blockstart:
                    oldEvent.transparency = reverseTransparencyMap[status]
                    oldEvent.duration = duration
                    countUpdated += 1
                    oldEvent = existing.next()
                else:
                    vals = {
                        "startTime": blockstart,
                        "transparency": reverseTransparencyMap[status],
                        "duration": duration,
                        "isFreeBusy": True,
                        "anyTime": False,
                        "summary": "",
                    }
                    eventItem = CalendarEvent(None, newItemParent, **vals)
                    busyCollection.add(eventItem.itsItem)
                    countNew += 1

    logger.info("...iCalendar import of %d new freebusy blocks, %d updated", countNew, countUpdated)

    return freebusystart, freebusyend, calname
Ejemplo n.º 6
0
def updateFreebusyFromVObject(view, text, busyCollection, activity=None):
    """
    Take a string, create or update freebusy events in busyCollection from that
    stream.

    Truncate differing existing freebusy events that overlap the start or end
    times.

    Returns (freebusystart, freebusyend, calname).

    """
    
    newItemParent = view.findPath("//userdata")
    
    countNew = 0
    countUpdated = 0

    freebusystart = freebusyend = None

    Calendar.ensureIndexed(busyCollection)
    
    # iterate over calendars, usually only one, but more are allowed
    for calendar in vobject.readComponents(text, validate=True,
                                           ignoreUnreadable=True):
        calname = calendar.getChildValue('x_wr_calname')
            
        for vfreebusy in calendar.vfreebusy_list:
            # RPI's server originally didn't put a VERSION:2.0 line in its
            # freebusy response.  vobject's behavior is set when a VERSION is
            # found.  Tolerate servers that export technically illegal but still 
            # readable vfreebusy components
            if vfreebusy.behavior is None:
                vfreebusy.behavior = vobject.icalendar.VFreeBusy
                vfreebusy.transformToNative()

            start = vfreebusy.getChildValue('dtstart')
            end   = vfreebusy.getChildValue('dtend')
            if freebusystart is None or freebusystart > start:
                freebusystart = start
            if freebusyend is None or freebusyend < end:
                freebusyend = end

            # create a list of busy blocks tuples sorted by start time
            busyblocks = []
            for fb in getattr(vfreebusy, 'freebusy_list', []):
                status = getattr(fb, 'fbtype_param', 'BUSY').upper()
                for blockstart, duration in fb.value:
                    blockstart = translateToTimezone(blockstart,
                                                     view.tzinfo.default)
                    bisect.insort(busyblocks, (blockstart, duration, status))
            
            # eventsInRange sorts by start time, recurring events aren't allowed
            # so we don't bother to fetch them
            existing = Calendar.eventsInRange(view, start, end, busyCollection)
            existing = itertools.chain(existing, [None])

            oldEvent = existing.next()
            for blockstart, duration, status in busyblocks:
                while oldEvent is not None and oldEvent.startTime < blockstart:
                    # this assumes no freebusy blocks overlap freebusystart
                    oldEvent.delete()
                    oldEvent = existing.next()
                if oldEvent is not None and oldEvent.startTime == blockstart:
                    oldEvent.transparency = reverseTransparencyMap[status]
                    oldEvent.duration = duration
                    countUpdated += 1
                    oldEvent = existing.next()
                else:
                    vals = { 'startTime'    : blockstart,
                             'transparency' : reverseTransparencyMap[status],
                             'duration'     : duration,
                             'isFreeBusy'   : True,
                             'anyTime'      : False,
                             'summary'  : '' }
                    eventItem = CalendarEvent(None, newItemParent, **vals)
                    busyCollection.add(eventItem.itsItem)
                    countNew += 1

    logger.info("...iCalendar import of %d new freebusy blocks, %d updated",
                countNew, countUpdated)
    
    return freebusystart, freebusyend, calname