def getVFreeBusyFB(self, period, fb): # First create expanded set # TODO: fix this # list = ExpandedComponents() self.getVEvents(period, list) if len(list) == 0: return # Get start/end list for each non-all-day expanded components dtstart = [] dtend = [] for dt in list: # Ignore if all-day if dt.getInstanceStart().isDateOnly(): continue # Ignore if transparent to free-busy transp = "" if dt.getOwner().getProperty( definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT): continue # Add start/end to list dtstart.append(dt.getInstanceStart()) dtend.append(dt.getInstanceEnd()) # No longer need the expanded items list.clear() # Create non-overlapping periods as properties in the freebusy component temp = Period(dtstart.front(), dtend.front()) dtstart_iter = dtstart.iter() dtstart_iter.next() dtend_iter = dtend.iter() dtend_iter.next() for i in i: # Check for non-overlap if dtstart_iter > temp.getEnd(): # Current period is complete fb.addProperty( Property(definitions.cICalProperty_FREEBUSY, temp)) # Reset period to new range temp = Period(dtstart_iter, dtend_iter) # They overlap - check for extended end if dtend_iter > temp.getEnd(): # Extend the end temp = Period(temp.getStart(), dtend_iter) # Add remaining period as property fb.addProperty(Property(definitions.cICalProperty_FREEBUSY, temp))
def getVFreeBusyFB(self, period, fb): # First create expanded set # TODO: fix this # list = ExpandedComponents() self.getVEvents(period, list) if len(list) == 0: return # Get start/end list for each non-all-day expanded components dtstart = [] dtend = [] for dt in list: # Ignore if all-day if dt.getInstanceStart().isDateOnly(): continue # Ignore if transparent to free-busy transp = "" if dt.getOwner().getProperty(definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT): continue # Add start/end to list dtstart.append(dt.getInstanceStart()) dtend.append(dt.getInstanceEnd()) # No longer need the expanded items list.clear() # Create non-overlapping periods as properties in the freebusy component temp = Period(dtstart.front(), dtend.front()) dtstart_iter = dtstart.iter() dtstart_iter.next() dtend_iter = dtend.iter() dtend_iter.next() for i in i: # Check for non-overlap if dtstart_iter > temp.getEnd(): # Current period is complete fb.addProperty(Property(definitions.cICalProperty_FREEBUSY, temp)) # Reset period to new range temp = Period(dtstart_iter, dtend_iter) # They overlap - check for extended end if dtend_iter > temp.getEnd(): # Extend the end temp = Period(temp.getStart(), dtend_iter) # Add remaining period as property fb.addProperty(Property(definitions.cICalProperty_FREEBUSY, temp))
def _getNormalizedDateTimeProperties(self, component): # Basic time properties if component.name() in ("VEVENT", "VJOURNAL", "VPOLL"): dtstart = component.getProperty("DTSTART") dtend = component.getProperty("DTEND") duration = component.getProperty("DURATION") timeRange = Period( start=dtstart.value() if dtstart is not None else None, end=dtend.value() if dtend is not None else None, duration=duration.value() if duration is not None else None, ) newdue = None elif component.name() == "VTODO": dtstart = component.getProperty("DTSTART") duration = component.getProperty("DURATION") if dtstart or duration: timeRange = Period( start=dtstart.value() if dtstart is not None else None, duration=duration.value() if duration is not None else None, ) else: timeRange = Period() newdue = component.getProperty("DUE") if newdue is not None: newdue = newdue.value().duplicate().adjustToUTC() else: timeRange = Period() newdue = None # Recurrence rules - we need to normalize the order of the value parts newrrules = set() rrules = component.properties("RRULE") for rrule in rrules: indexedTokens = {} indexedTokens.update([valuePart.split("=") for valuePart in rrule.value().getText().split(";")]) sortedValue = ";".join(["%s=%s" % (key, value,) for key, value in sorted(indexedTokens.iteritems(), key=lambda x:x[0])]) newrrules.add(sortedValue) # RDATEs newrdates = set() rdates = component.properties("RDATE") for rdate in rdates: for value in rdate.value(): if isinstance(value, DateTime): value = value.duplicate().adjustToUTC() newrdates.add(value) # EXDATEs newexdates = set() exdates = component.properties("EXDATE") for exdate in exdates: newexdates.update([exvalue.getValue().duplicate().adjustToUTC() for exvalue in exdate.value()]) return timeRange.getStart(), timeRange.getEnd(), newdue, newrrules, newrdates, newexdates
def processAvailabilityFreeBusy(self, calendar, fbinfo): """ Extract free-busy data from a VAVAILABILITY component. @param calendar: the L{Component} that is the VCALENDAR containing the VAVAILABILITY's. @param fbinfo: the tuple used to store the three types of fb data. """ for vav in [ x for x in calendar.subcomponents() if x.name() == "VAVAILABILITY" ]: # Get overall start/end start = vav.getStartDateUTC() if start is None: start = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone.UTCTimezone) end = vav.getEndDateUTC() if end is None: end = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone.UTCTimezone) period = Period(start, end) overall = clipPeriod(period, self.timerange) if overall is None: continue # Now get periods for each instance of AVAILABLE sub-components periods = self.processAvailablePeriods(vav) # Now invert the periods and store in accumulator busyperiods = [] last_end = self.timerange.getStart() for period in periods: if last_end < period.getStart(): busyperiods.append(Period(last_end, period.getStart())) last_end = period.getEnd() if last_end < self.timerange.getEnd(): busyperiods.append(Period(last_end, self.timerange.getEnd())) # Add to actual results mapped by busy type fbtype = vav.propertyValue("BUSYTYPE") if fbtype is None: fbtype = "BUSY-UNAVAILABLE" getattr(fbinfo, self.FBInfo_mapper.get(fbtype, "unavailable")).extend(busyperiods)
def processAvailabilityFreeBusy(calendar, fbinfo, timerange): """ Extract free-busy data from a VAVAILABILITY component. @param calendar: the L{Component} that is the VCALENDAR containing the VAVAILABILITY's. @param fbinfo: the tuple used to store the three types of fb data. @param timerange: the time range to restrict free busy data to. """ for vav in [x for x in calendar.subcomponents() if x.name() == "VAVAILABILITY"]: # Get overall start/end start = vav.getStartDateUTC() if start is None: start = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) end = vav.getEndDateUTC() if end is None: end = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) period = Period(start, end) overall = clipPeriod(period, Period(timerange.start, timerange.end)) if overall is None: continue # Now get periods for each instance of AVAILABLE sub-components periods = processAvailablePeriods(vav, timerange) # Now invert the periods and store in accumulator busyperiods = [] last_end = timerange.start for period in periods: if last_end < period.getStart(): busyperiods.append(Period(last_end, period.getStart())) last_end = period.getEnd() if last_end < timerange.end: busyperiods.append(Period(last_end, timerange.end)) # Add to actual results mapped by busy type fbtype = vav.propertyValue("BUSYTYPE") if fbtype is None: fbtype = "BUSY-UNAVAILABLE" fbinfo[fbtype_mapper.get(fbtype, 2)].extend(busyperiods)