def init_perinstance_component(): peruser = Component(PerUserDataFilter.PERINSTANCE_COMPONENT) rid = component.getRecurrenceIDUTC() if rid: peruser.addProperty(Property("RECURRENCE-ID", rid)) perinstance_components[rid] = peruser return peruser
def test_single_events(self): """ Single events in calendar collection """ work = [] stream = self.openHolidays() calendar = Component.fromStream(stream) for subcomponent in calendar.subcomponents(): if subcomponent.name() == "VEVENT": subcalendar = Component("VCALENDAR") subcalendar.addComponent(subcomponent) for property in calendar.properties(): subcalendar.addProperty(property) work.append((MemoryStream(str(subcalendar)), responsecode.CREATED)) return self._test_file_in_calendar("single event in calendar", *work)
def compFilter(self, comp, component): """ Returns a calendar component object containing the data in the given component which is specified by this CalendarComponent. """ if comp.type != component.name(): raise ValueError( "%s of type %r can't get data from component of type %r" % (comp.sname(), comp.type, component.name())) result = Component(comp.type) xml_components = comp.components xml_properties = comp.properties # Empty element means do all properties and components if xml_components is None and xml_properties is None: xml_components = AllComponents() xml_properties = AllProperties() if xml_components is not None: if xml_components == AllComponents(): for ical_subcomponent in component.subcomponents(): result.addComponent(ical_subcomponent) else: for xml_subcomponent in xml_components: for ical_subcomponent in component.subcomponents(): if ical_subcomponent.name() == xml_subcomponent.type: result.addComponent( self.compFilter(xml_subcomponent, ical_subcomponent)) if xml_properties is not None: if xml_properties == AllProperties(): for ical_property in component.properties(): result.addProperty(ical_property) else: for xml_property in xml_properties: name = xml_property.property_name for ical_property in component.properties(name): result.addProperty(ical_property) return result
def compFilter(self, comp, component): """ Returns a calendar component object containing the data in the given component which is specified by this CalendarComponent. """ if comp.type != component.name(): raise ValueError("%s of type %r can't get data from component of type %r" % (comp.sname(), comp.type, component.name())) result = Component(comp.type) xml_components = comp.components xml_properties = comp.properties # Empty element means do all properties and components if xml_components is None and xml_properties is None: xml_components = AllComponents() xml_properties = AllProperties() if xml_components is not None: if xml_components == AllComponents(): for ical_subcomponent in component.subcomponents(): result.addComponent(ical_subcomponent) else: for xml_subcomponent in xml_components: for ical_subcomponent in component.subcomponents(): if ical_subcomponent.name() == xml_subcomponent.type: result.addComponent(self.compFilter(xml_subcomponent, ical_subcomponent)) if xml_properties is not None: if xml_properties == AllProperties(): for ical_property in component.properties(): result.addProperty(ical_property) else: for xml_property in xml_properties: name = xml_property.property_name for ical_property in component.properties(name): result.addProperty(ical_property) return result
def buildFreeBusyResult(self, fbinfo, method=None): """ Generate a VCALENDAR object containing a single VFREEBUSY that is the aggregate of the free busy info passed in. @param fbinfo: the array of busy periods to use. @param method: the METHOD property value to insert. @return: the L{Component} containing the calendar data. """ # Merge overlapping time ranges in each fb info section normalizePeriodList(fbinfo.busy) normalizePeriodList(fbinfo.tentative) normalizePeriodList(fbinfo.unavailable) # Now build a new calendar object with the free busy info we have fbcalendar = Component("VCALENDAR") fbcalendar.addProperty(Property("VERSION", "2.0")) fbcalendar.addProperty(Property("PRODID", iCalendarProductID)) if method: fbcalendar.addProperty(Property("METHOD", method)) fb = Component("VFREEBUSY") fbcalendar.addComponent(fb) if self.organizerProp is not None: fb.addProperty(self.organizerProp) if self.attendeeProp is not None: fb.addProperty(self.attendeeProp) fb.addProperty(Property("DTSTART", self.timerange.getStart())) fb.addProperty(Property("DTEND", self.timerange.getEnd())) fb.addProperty(Property("DTSTAMP", DateTime.getNowUTC())) if len(fbinfo.busy) != 0: fb.addProperty(Property("FREEBUSY", fbinfo.busy, {"FBTYPE": "BUSY"})) if len(fbinfo.tentative) != 0: fb.addProperty(Property("FREEBUSY", fbinfo.tentative, {"FBTYPE": "BUSY-TENTATIVE"})) if len(fbinfo.unavailable) != 0: fb.addProperty(Property("FREEBUSY", fbinfo.unavailable, {"FBTYPE": "BUSY-UNAVAILABLE"})) if self.uid is not None: fb.addProperty(Property("UID", self.uid)) else: uid = str(uuid.uuid4()) fb.addProperty(Property("UID", uid)) if self.event_details: for vevent in self.event_details: fbcalendar.addComponent(vevent) return fbcalendar
def init_peruser_component(): peruser = Component(PERUSER_COMPONENT) peruser.addProperty(Property("UID", ical.resourceUID())) peruser.addProperty(Property(PERUSER_UID, self.uid)) return peruser
calendar = Component("VCALENDAR") # Ignore first line reader.next() priorities = { "High" : "1", "Medium" : "5", "Low" : "9", } for row in reader: event = Component("VEVENT") title = row[0] event.addProperty(Property("SUMMARY", title)) start = parse_datetime(row[1], row[2]) event.addProperty(Property("DTSTART", start)) end = None if row[5] == "1": assert row[3] == row[4] == "" end = start + datetime.timedelta(1) else: end = parse_datetime(row[3], row[4]) if end is not None: event.addProperty(Property("DTEND", end)) categories = row[6] event.addProperty(Property("CATEGORIES", categories))
def buildFreeBusyResult(fbinfo, timerange, organizer=None, attendee=None, uid=None, method=None, event_details=None): """ Generate a VCALENDAR object containing a single VFREEBUSY that is the aggregate of the free busy info passed in. @param fbinfo: the array of busy periods to use. @param timerange: the L{TimeRange} for the query. @param organizer: the L{Property} for the Organizer of the free busy request, or None. @param attendee: the L{Property} for the Attendee responding to the free busy request, or None. @param uid: the UID value from the free busy request. @param method: the METHOD property value to insert. @param event_details: VEVENT components to add. @return: the L{Component} containing the calendar data. """ # Merge overlapping time ranges in each fb info section normalizePeriodList(fbinfo[0]) normalizePeriodList(fbinfo[1]) normalizePeriodList(fbinfo[2]) # Now build a new calendar object with the free busy info we have fbcalendar = Component("VCALENDAR") fbcalendar.addProperty(Property("VERSION", "2.0")) fbcalendar.addProperty(Property("PRODID", iCalendarProductID)) if method: fbcalendar.addProperty(Property("METHOD", method)) fb = Component("VFREEBUSY") fbcalendar.addComponent(fb) if organizer is not None: fb.addProperty(organizer) if attendee is not None: fb.addProperty(attendee) fb.addProperty(Property("DTSTART", timerange.start)) fb.addProperty(Property("DTEND", timerange.end)) fb.addProperty(Property("DTSTAMP", PyCalendarDateTime.getNowUTC())) if len(fbinfo[0]) != 0: fb.addProperty(Property("FREEBUSY", fbinfo[0], {"FBTYPE": "BUSY"})) if len(fbinfo[1]) != 0: fb.addProperty(Property("FREEBUSY", fbinfo[1], {"FBTYPE": "BUSY-TENTATIVE"})) if len(fbinfo[2]) != 0: fb.addProperty(Property("FREEBUSY", fbinfo[2], {"FBTYPE": "BUSY-UNAVAILABLE"})) if uid is not None: fb.addProperty(Property("UID", uid)) else: uid = str(uuid.uuid4()) fb.addProperty(Property("UID", uid)) if event_details: for vevent in event_details: fbcalendar.addComponent(vevent) return fbcalendar
from twistedcaldav.ical import Component monolithic_filename = os.path.join(os.path.dirname(__file__), "Holidays.ics") calendar = Component.fromStream(file(monolithic_filename)) assert calendar.name() == "VCALENDAR" for subcomponent in calendar.subcomponents(): subcalendar = Component("VCALENDAR") # # Add top-level properties from monolithic calendar to top-level properties # of subcomponent calendar. # for property in calendar.properties(): subcalendar.addProperty(property) subcalendar.addComponent(subcomponent) uid = subcalendar.resourceUID() subcalendar_filename = os.path.join(os.path.dirname(__file__), "Holidays", uid + ".ics") print "Writing %s" % (subcalendar_filename,) subcalendar_file = file(subcalendar_filename, "w") try: subcalendar_file.write(str(subcalendar)) finally: subcalendar_file.close()
def buildFreeBusyResult(fbinfo, timerange, organizer=None, attendee=None, uid=None, method=None, event_details=None): """ Generate a VCALENDAR object containing a single VFREEBUSY that is the aggregate of the free busy info passed in. @param fbinfo: the array of busy periods to use. @param timerange: the L{TimeRange} for the query. @param organizer: the L{Property} for the Organizer of the free busy request, or None. @param attendee: the L{Property} for the Attendee responding to the free busy request, or None. @param uid: the UID value from the free busy request. @param method: the METHOD property value to insert. @param event_details: VEVENT components to add. @return: the L{Component} containing the calendar data. """ # Merge overlapping time ranges in each fb info section normalizePeriodList(fbinfo[0]) normalizePeriodList(fbinfo[1]) normalizePeriodList(fbinfo[2]) # Now build a new calendar object with the free busy info we have fbcalendar = Component("VCALENDAR") fbcalendar.addProperty(Property("VERSION", "2.0")) fbcalendar.addProperty(Property("PRODID", iCalendarProductID)) if method: fbcalendar.addProperty(Property("METHOD", method)) fb = Component("VFREEBUSY") fbcalendar.addComponent(fb) if organizer is not None: fb.addProperty(organizer) if attendee is not None: fb.addProperty(attendee) fb.addProperty(Property("DTSTART", timerange.start)) fb.addProperty(Property("DTEND", timerange.end)) fb.addProperty(Property("DTSTAMP", DateTime.getNowUTC())) if len(fbinfo[0]) != 0: fb.addProperty(Property("FREEBUSY", fbinfo[0], {"FBTYPE": "BUSY"})) if len(fbinfo[1]) != 0: fb.addProperty( Property("FREEBUSY", fbinfo[1], {"FBTYPE": "BUSY-TENTATIVE"})) if len(fbinfo[2]) != 0: fb.addProperty( Property("FREEBUSY", fbinfo[2], {"FBTYPE": "BUSY-UNAVAILABLE"})) if uid is not None: fb.addProperty(Property("UID", uid)) else: uid = str(uuid.uuid4()) fb.addProperty(Property("UID", uid)) if event_details: for vevent in event_details: fbcalendar.addComponent(vevent) return fbcalendar
def generateCancel(original, attendees, instances=None, full_cancel=False): itip = Component("VCALENDAR") itip.addProperty(Property("VERSION", "2.0")) itip.addProperty(Property("PRODID", iCalendarProductID)) itip.addProperty(Property("METHOD", "CANCEL")) if instances is None: instances = (None,) tzids = set() for instance_rid in instances: # Create a new component matching the type of the original comp = Component(original.mainType()) itip.addComponent(comp) # Use the master component when the instance is None if not instance_rid: instance = original.masterComponent() else: instance = original.overriddenComponent(instance_rid) if instance is None: instance = original.deriveInstance(instance_rid) assert instance is not None, "Need a master component" # Add some required properties extracted from the original comp.addProperty(Property("DTSTAMP", datetime.datetime.now(tz=utc))) comp.addProperty(Property("UID", instance.propertyValue("UID"))) seq = instance.propertyValue("SEQUENCE") seq = str(int(seq) + 1) if seq else "1" comp.addProperty(Property("SEQUENCE", seq)) comp.addProperty(instance.getOrganizerProperty()) if instance_rid: comp.addProperty(Property("RECURRENCE-ID", asUTC(instance_rid))) def addProperties(propname): for property in instance.properties(propname): comp.addProperty(property) addProperties("SUMMARY") addProperties("DTSTART") addProperties("DTEND") addProperties("DURATION") if not instance_rid: addProperties("RRULE") addProperties("RDATE") addProperties("EXDATE") # Extract the matching attendee property for attendee in attendees: if full_cancel: attendeeProp = original.getAttendeeProperty((attendee,)) else: attendeeProp = instance.getAttendeeProperty((attendee,)) assert attendeeProp is not None, "Must have matching ATTENDEE property" comp.addProperty(attendeeProp) tzids.update(comp.timezoneIDs()) # Now include any referenced tzids for comp in original.subcomponents(): if comp.name() == "VTIMEZONE": tzid = comp.propertyValue("TZID") if tzid in tzids: itip.addComponent(comp) # Strip out unwanted bits iTipGenerator.prepareSchedulingMessage(itip) return itip
def generateCancel(original, attendees, instances=None, full_cancel=False): """ This assumes that SEQUENCE is not already at its new value in the original calendar data. This is because the component passed in is the one that originally contained the attendee that is being removed. """ itip = Component("VCALENDAR") itip.addProperty(Property("VERSION", "2.0")) itip.addProperty(Property("PRODID", iCalendarProductID)) itip.addProperty(Property("METHOD", "CANCEL")) if instances is None: instances = (None,) tzids = set() added = False for instance_rid in instances: # Create a new component matching the type of the original comp = Component(original.mainType()) # Use the master component when the instance is None if not instance_rid: instance = original.masterComponent() assert instance is not None, "Need a master component" else: instance = original.overriddenComponent(instance_rid) if instance is None: instance = original.deriveInstance(instance_rid) # If the instance to be cancelled did not exist in the original, then # do nothing if instance is None: continue # Add some required properties extracted from the original comp.addProperty(Property("DTSTAMP", instance.propertyValue("DTSTAMP"))) comp.addProperty(Property("UID", instance.propertyValue("UID"))) seq = instance.propertyValue("SEQUENCE") seq = int(seq) + 1 if seq else 1 comp.addProperty(Property("SEQUENCE", seq)) comp.addProperty(instance.getOrganizerProperty()) if instance_rid: comp.addProperty(Property("RECURRENCE-ID", instance_rid.duplicate().adjustToUTC())) def addProperties(propname): for icalproperty in instance.properties(propname): comp.addProperty(icalproperty) addProperties("SUMMARY") addProperties("DTSTART") addProperties("DTEND") addProperties("DURATION") if not instance_rid: addProperties("RRULE") addProperties("RDATE") addProperties("EXDATE") # Extract the matching attendee property for attendee in attendees: if full_cancel: attendeeProp = original.getAttendeeProperty((attendee,)) else: attendeeProp = instance.getAttendeeProperty((attendee,)) assert attendeeProp is not None, "Must have matching ATTENDEE property" comp.addProperty(attendeeProp) tzids.update(comp.timezoneIDs()) itip.addComponent(comp) added = True if added: # Now include any referenced tzids for comp in original.subcomponents(): if comp.name() == "VTIMEZONE": tzid = comp.propertyValue("TZID") if tzid in tzids: itip.addComponent(comp) # Strip out unwanted bits iTipGenerator.prepareSchedulingMessage(itip) return itip else: return None
def _splitPerUserData(self, ical): """ Split the per-user data out of the "normal" iCalendar components into separate per-user components. Along the way keep the iCalendar representation in a "minimal" state by eliminating any components that are the same as the master derived component. @param ical: calendar data to process @type ical: L{Component} """ def init_peruser_component(): peruser = Component(PERUSER_COMPONENT) peruser.addProperty(Property("UID", ical.resourceUID())) peruser.addProperty(Property(PERUSER_UID, self.uid)) return peruser components = tuple(ical.subcomponents()) peruser_component = init_peruser_component() if self.uid else None perinstance_components = {} for component in components: if component.name() == "VTIMEZONE": continue rid = component.propertyValue("RECURRENCE-ID") rid = rid.duplicate() if rid is not None else None perinstance_component = Component( PERINSTANCE_COMPONENT) if self.uid else None perinstance_id_different = False # Special case certain default property values self._defaultMerge(component) # Transfer per-user properties from main component to per-instance component for property in tuple(component.properties()): if property.name( ) in PerUserDataFilter.PERUSER_PROPERTIES or property.name( ).startswith("X-") and property.name( ) not in PerUserDataFilter.IGNORE_X_PROPERTIES: if self.uid: perinstance_component.addProperty(property) component.removeProperty(property) perinstance_id_different = True # Transfer per-user components from main component to per-instance component for subcomponent in tuple(component.subcomponents()): if subcomponent.name( ) in PerUserDataFilter.PERUSER_SUBCOMPONENTS or subcomponent.name( ).startswith("X-"): if self.uid: perinstance_component.addComponent(subcomponent) component.removeComponent(subcomponent) perinstance_id_different = True if perinstance_id_different and perinstance_component: perinstance_components[rid] = perinstance_component if self.uid: # Add unique per-instance components into the per-user component peruser_component_different = False master_perinstance = perinstance_components.get(None) if master_perinstance: peruser_component.addComponent(master_perinstance) peruser_component_different = True for rid, perinstance in sorted(perinstance_components.iteritems(), key=lambda x: x[0]): if rid is None: continue if master_perinstance is None or perinstance != master_perinstance: perinstance.addProperty(Property("RECURRENCE-ID", rid)) peruser_component.addComponent(perinstance) peruser_component_different = True if peruser_component_different: ical.addComponent(peruser_component) self._compactInstances(ical)
def _splitPerUserData(self, ical): """ Split the per-user data out of the "normal" iCalendar components into separate per-user components. Along the way keep the iCalendar representation in a "minimal" state by eliminating any components that are the same as the master derived component. @param ical: calendar data to process @type ical: L{Component} """ def init_peruser_component(): peruser = Component(PERUSER_COMPONENT) peruser.addProperty(Property("UID", ical.resourceUID())) peruser.addProperty(Property(PERUSER_UID, self.uid)) return peruser components = tuple(ical.subcomponents()) peruser_component = init_peruser_component() if self.uid else None perinstance_components = {} for component in components: if component.name() == "VTIMEZONE": continue rid = component.propertyValue("RECURRENCE-ID") rid = rid.duplicate() if rid is not None else None perinstance_component = Component(PERINSTANCE_COMPONENT) if self.uid else None perinstance_id_different = False # Transfer per-user properties from main component to per-instance component for property in tuple(component.properties()): if property.name() in PerUserDataFilter.PERUSER_PROPERTIES or property.name().startswith("X-") and property.name() not in PerUserDataFilter.IGNORE_X_PROPERTIES: if self.uid: perinstance_component.addProperty(property) component.removeProperty(property) perinstance_id_different = True # Transfer per-user components from main component to per-instance component for subcomponent in tuple(component.subcomponents()): if subcomponent.name() in PerUserDataFilter.PERUSER_SUBCOMPONENTS or subcomponent.name().startswith("X-"): if self.uid: perinstance_component.addComponent(subcomponent) component.removeComponent(subcomponent) perinstance_id_different = True if perinstance_id_different and perinstance_component: perinstance_components[rid] = perinstance_component if self.uid: # Add unique per-instance components into the per-user component peruser_component_different = False master_perinstance = perinstance_components.get(None) if master_perinstance: peruser_component.addComponent(master_perinstance) peruser_component_different = True for rid, perinstance in perinstance_components.iteritems(): if rid is None: continue if master_perinstance is None or perinstance != master_perinstance: perinstance.addProperty(Property("RECURRENCE-ID", rid)) peruser_component.addComponent(perinstance) peruser_component_different = True if peruser_component_different: ical.addComponent(peruser_component) self._compactInstances(ical)
monolithic_filename = os.path.join(os.path.dirname(__file__), "Holidays.ics") calendar = Component.fromStream(file(monolithic_filename)) assert calendar.name() == "VCALENDAR" for subcomponent in calendar.subcomponents(): subcalendar = Component("VCALENDAR") # # Add top-level properties from monolithic calendar to top-level properties # of subcomponent calendar. # for property in calendar.properties(): subcalendar.addProperty(property) subcalendar.addComponent(subcomponent) uid = subcalendar.resourceUID() subcalendar_filename = os.path.join(os.path.dirname(__file__), "Holidays", uid + ".ics") print "Writing %s" % (subcalendar_filename, ) subcalendar_file = file(subcalendar_filename, "w") try: subcalendar_file.write(str(subcalendar)) finally: subcalendar_file.close()
def init_peruser_component(): peruser = Component(PerUserDataFilter.PERUSER_COMPONENT) peruser.addProperty(Property("UID", ical.resourceUID())) peruser.addProperty(Property(PerUserDataFilter.PERUSER_UID, self.uid)) ical.addComponent(peruser) return peruser