[CalendarServer-changes] [4693] CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/ twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Mon Nov 2 13:47:42 PST 2009
Revision: 4693
http://trac.macosforge.org/projects/calendarserver/changeset/4693
Author: cdaboo at apple.com
Date: 2009-11-02 13:47:40 -0800 (Mon, 02 Nov 2009)
Log Message:
-----------
Filtering (reading only) of per-user calendar data. This defines the object model used in the iCalendar data
to represent per-user data. Next piece is to do the merge (write) behavior.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/__init__.py
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/calendardata.py
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/filter.py
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/privateevents.py
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/ical.py
Added Paths:
-----------
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/peruserdata.py
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_peruserdata.py
Modified: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/__init__.py 2009-11-02 19:11:51 UTC (rev 4692)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/__init__.py 2009-11-02 21:47:40 UTC (rev 4693)
@@ -14,6 +14,34 @@
# limitations under the License.
##
+from vobject.base import registerBehavior
+from vobject.icalendar import VCalendarComponentBehavior, VCalendar2_0
+
"""
Data filtering module.
"""
+
+# This is where we register our special components with vobject
+
+class X_CALENDARSERVER_PERUSER(VCalendarComponentBehavior):
+ name='X-CALENDARSERVER-PERUSER'
+ description='A component used to encapsulate per-user data.'
+ sortFirst = ('uid', 'x-calendarserver-peruser-uid')
+ knownChildren = {
+ 'UID': (1, 1, None),#min, max, behaviorRegistry id
+ 'X-CALENDARSERVER-PERUSER': (1, 1, None),
+ 'X-CALENDARSERVER-PERINSTANCE': (0, None, None),
+ }
+
+registerBehavior(X_CALENDARSERVER_PERUSER)
+VCalendar2_0.knownChildren['X-CALENDARSERVER-PERUSER'] = (0, None, None)
+
+class X_CALENDARSERVER_PERINSTANCE(VCalendarComponentBehavior):
+ name='X-CALENDARSERVER-PERINSTANCE'
+ description='A component used to encapsulate per-user instance data.'
+ sortFirst = ('recurrence-id',)
+ knownChildren = {
+ 'RECURRENCE-ID':(0, 1, None),#min, max, behaviorRegistry id
+ }
+
+registerBehavior(X_CALENDARSERVER_PERINSTANCE)
Modified: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/calendardata.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/calendardata.py 2009-11-02 19:11:51 UTC (rev 4692)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/calendardata.py 2009-11-02 21:47:40 UTC (rev 4693)
@@ -14,16 +14,17 @@
# limitations under the License.
##
-from twistedcaldav.ical import Component
-from twistedcaldav.dateops import clipPeriod
from twistedcaldav.caldavxml import LimitRecurrenceSet, Expand, AllComponents,\
AllProperties
+from twistedcaldav.datafilters.filter import CalendarFilter
+from twistedcaldav.dateops import clipPeriod
+from twistedcaldav.ical import Component
__all__ = [
"CalendarDataFilter",
]
-class CalendarDataFilter(object):
+class CalendarDataFilter(CalendarFilter):
"""
Filter using the CALDAV:calendar-data element specification
"""
@@ -54,16 +55,9 @@
if not self.calendardata.children:
return ical
- # If we were passed a string, parse it out as a Component
- if isinstance(ical, str):
- try:
- ical = Component.fromString(ical)
- except ValueError:
- raise ValueError("Not a calendar: %r" % (ical,))
+ # Make sure input is valid
+ ical = self.validCalendar(ical)
- if ical is None or ical.name() != "VCALENDAR":
- raise ValueError("Not a calendar: %r" % (ical,))
-
# Pre-process the calendar data based on expand and limit options
if self.calendardata.freebusy_set:
ical = self.limitFreeBusy(ical)
Modified: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/filter.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/filter.py 2009-11-02 19:11:51 UTC (rev 4692)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/filter.py 2009-11-02 21:47:40 UTC (rev 4693)
@@ -13,12 +13,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
+from twistedcaldav.ical import Component
__all__ = [
- "ICalendarFilter",
+ "CalendarFilter",
]
-class ICalendarFilter(object):
+class CalendarFilter(object):
"""
Abstract class that defines an iCalendar filter/merge object
"""
@@ -48,3 +49,17 @@
@type icalold: L{Component}
"""
raise NotImplementedError
+
+ def validCalendar(self, ical):
+
+ # If we were passed a string, parse it out as a Component
+ if isinstance(ical, str):
+ try:
+ ical = Component.fromString(ical)
+ except ValueError:
+ raise ValueError("Not a calendar: %r" % (ical,))
+
+ if ical is None or ical.name() != "VCALENDAR":
+ raise ValueError("Not a calendar: %r" % (ical,))
+
+ return ical
Added: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/peruserdata.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/peruserdata.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/peruserdata.py 2009-11-02 21:47:40 UTC (rev 4693)
@@ -0,0 +1,180 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from twistedcaldav.datafilters.filter import CalendarFilter
+
+__all__ = [
+ "PerUserDataFilter",
+]
+
+"""
+Object model for calendar data is as follows:
+
+VCALENDAR
+ VTIMEZONE*
+ VEVENT* / VTODO* / VJOURNAL*
+ BEGIN:X-CALENDARSERVER-PERUSER*
+ X-CALENDARSERVER-PERUSER-UID
+ UID
+ BEGIN:X-CALENDARSERVER-PERINSTANCE
+ RECURRENCE-ID?
+ TRANSP?
+ VALARM*
+
+So we will store per user data inside the top-level component (alongside VEVENT, VTODO etc). That new component will
+contain properties to identify the user and the UID of the VEVENT, VTODO it affects. It will contain sub-components
+for each instance overridden by the per-user data. These per-user overridden components may not correspond to an
+actual overridden component. In that situation the server has to re-construct the per-user data appropriately:
+
+e.g.,
+
+1. VEVENT contains an overridden instance, but X-CALENDARSERVER-PERUSER does not - server uses the must instance
+X-CALENDARSERVER-PERUSER data (if any) for the overridden instance.
+
+2. VEVENT does not contain an overridden instance, but X-CALENDARSERVER-PERUSER does - server synthesizes an
+overridden instance to match the X-CALENDARSERVER-PERUSER one.
+
+3. VEVENT contains overridden instance and X-CALENDARSERVER-PERUSER does - server merges X-CALENDARSERVER-PERUSER
+data into overridden instance.
+
+"""
+
+class PerUserDataFilter(CalendarFilter):
+ """
+ Filter per-user data
+ """
+
+ PERUSER_COMPONENT = "X-CALENDARSERVER-PERUSER"
+ PERUSER_UID = "X-CALENDARSERVER-PERUSER-UID"
+ PERINSTANCE_COMPONENT = "X-CALENDARSERVER-PERINSTANCE"
+
+ def __init__(self, uid):
+ """
+
+ @param uid: unique identifier of the user for whom the data is being filtered
+ @type uid: C{str}
+ """
+
+ self.uid = uid
+
+ def filter(self, ical):
+ """
+ Filter the supplied iCalendar (vobject) data using the request information.
+ Assume that the object is a CalDAV calendar resource.
+
+ @param ical: iCalendar object - this will be modified and returned
+ @type ical: L{Component} or C{str}
+
+ @return: L{Component} for the filtered calendar data
+ """
+
+ # Make sure input is valid
+ ical = self.validCalendar(ical)
+
+ # Look for matching per-user sub-component, removing all the others
+ peruser_component = None
+ for component in tuple(ical.subcomponents()):
+ if component.name() == PerUserDataFilter.PERUSER_COMPONENT:
+
+ # Check user id - remove if not matches
+ if component.propertyValue(PerUserDataFilter.PERUSER_UID) != self.uid:
+ ical.removeComponent(component)
+ elif peruser_component is None:
+ peruser_component = component
+ ical.removeComponent(component)
+ else:
+ raise AssertionError("Can't have two X-CALENDARSERVER-PERUSER components for the same user")
+
+ # Now transfer any components over
+ if peruser_component:
+ self._mergeBack(ical, peruser_component)
+
+ return ical
+
+ def merge(self, icalnew, icalold):
+ """
+ Private event merging does not happen
+ """
+ raise NotImplementedError
+
+ def _mergeBack(self, ical, peruser):
+ """
+ Merge the per-user data back into the main calendar data.
+
+ @param ical: main calendar data to merge into
+ @type ical: L{Component}
+ @param peruser: the per-user data to merge in
+ @type peruser: L{Component}
+ """
+
+ # Iterate over each instance in the per-user data and build mapping
+ peruser_recurrence_map = {}
+ for subcomponent in peruser.subcomponents():
+ if subcomponent.name() != PerUserDataFilter.PERINSTANCE_COMPONENT:
+ raise AssertionError("Wrong sub-component '%s' in a X-CALENDARSERVER-PERUSER component" % (subcomponent.name(),))
+ peruser_recurrence_map[subcomponent.getRecurrenceIDUTC()] = subcomponent
+
+ ical_recurrence_set = set(ical.getComponentInstances())
+ peruser_recurrence_set = set(peruser_recurrence_map.keys())
+
+ # Set operations to find union and differences
+ union_set = ical_recurrence_set.intersection(peruser_recurrence_set)
+ ical_only_set = ical_recurrence_set.difference(peruser_recurrence_set)
+ peruser_only_set = peruser_recurrence_set.difference(ical_recurrence_set)
+
+ # For ones in per-user data but no main data, we synthesize an instance and copy over per-user data
+ # NB We have to do this before we do any merge that may change the master
+ if ical.masterComponent() is not None:
+ for rid in peruser_only_set:
+ ical_component = ical.deriveInstance(rid)
+ peruser_component = peruser_recurrence_map[rid]
+ self._mergeBackComponent(ical_component, peruser_component)
+ ical.addComponent(ical_component)
+ elif peruser_only_set:
+ raise AssertionError("Cannot derive a per-user instance when there is no master component.")
+
+ # Process the unions by merging in per-user data
+ for rid in union_set:
+ ical_component = ical.overriddenComponent(rid)
+ peruser_component = peruser_recurrence_map[rid]
+ self._mergeBackComponent(ical_component, peruser_component)
+
+ # For ones in main data but no per-user data, we try and copy over the master per-user data
+ if ical_only_set:
+ peruser_master = peruser_recurrence_map.get(None)
+ if peruser_master:
+ for rid in ical_only_set:
+ ical_component = ical.overriddenComponent(rid)
+ self._mergeBackComponent(ical_component, peruser_master)
+
+ def _mergeBackComponent(self, ical, peruser):
+ """
+ Copy all properties and sub-components from per-user data into the main component
+ @param ical:
+ @type ical:
+ @param peruser:
+ @type peruser:
+ """
+
+ # Each sub-component
+ for subcomponent in peruser.subcomponents():
+ ical.addComponent(subcomponent)
+
+ # Each property except RECURRENCE-ID
+ for property in peruser.properties():
+ if property.name() == "RECURRENCE-ID":
+ continue
+ ical.addProperty(property)
Modified: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/privateevents.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/privateevents.py 2009-11-02 19:11:51 UTC (rev 4692)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/privateevents.py 2009-11-02 21:47:40 UTC (rev 4693)
@@ -19,13 +19,14 @@
from twistedcaldav.caldavxml import Property, CalendarData, CalendarComponent,\
AllProperties, AllComponents
from twistedcaldav.datafilters.calendardata import CalendarDataFilter
+from twistedcaldav.datafilters.filter import CalendarFilter
from twistedcaldav.ical import Component
__all__ = [
"PrivateEventFilter",
]
-class PrivateEventFilter(object):
+class PrivateEventFilter(CalendarFilter):
"""
Filter a private event to match the rights of the non-owner user accessing the data
"""
Added: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_peruserdata.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_peruserdata.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_peruserdata.py 2009-11-02 21:47:40 UTC (rev 4693)
@@ -0,0 +1,837 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+import twistedcaldav.test.util
+from twistedcaldav.ical import Component
+from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
+
+class PerUserDataTestNotRecurring (twistedcaldav.test.util.TestCase):
+
+ def test_public_noperuser(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), data)
+
+ def test_public_oneuser(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:OPAQUE
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result01 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result02 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), result01)
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user02").filter(item)), result02)
+
+ def test_public_twousers(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test01
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:OPAQUE
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user02
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test02
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:TRANSPARENT
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result01 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test01
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result02 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:TRANSPARENT
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test02
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result03 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), result01)
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user02").filter(item)), result02)
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user03").filter(item)), result03)
+
+class PerUserDataTestRecurring (twistedcaldav.test.util.TestCase):
+
+ def test_public_noperuser(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), data)
+
+ def test_public_oneuser_master(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:OPAQUE
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result01 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result02 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), result01)
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user02").filter(item)), result02)
+
+ def test_public_oneuser_master_and_override(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-master
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:OPAQUE
+END:X-CALENDARSERVER-PERINSTANCE
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+RECURRENCE-ID:20080602T120000Z
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:TRANSPARENT
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result01 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-master
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:TRANSPARENT
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result02 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), result01)
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user02").filter(item)), result02)
+
+ def test_public_oneuser_override(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+RECURRENCE-ID:20080602T120000Z
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:TRANSPARENT
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result01 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:TRANSPARENT
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result02 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), result01)
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user02").filter(item)), result02)
+
+ def test_public_oneuser_master_derived_override(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-master
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:OPAQUE
+END:X-CALENDARSERVER-PERINSTANCE
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+RECURRENCE-ID:20080602T120000Z
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:TRANSPARENT
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result01 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-master
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:TRANSPARENT
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result02 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), result01)
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user02").filter(item)), result02)
+
+ def test_public_oneuser_master_derived_override_x2(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-master-1
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:OPAQUE
+END:X-CALENDARSERVER-PERINSTANCE
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+RECURRENCE-ID:20080602T120000Z
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override-1
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:TRANSPARENT
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user02
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-master-2
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:OPAQUE
+END:X-CALENDARSERVER-PERINSTANCE
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+RECURRENCE-ID:20080603T120000Z
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override-2
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:TRANSPARENT
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result01 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-master-1
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T120000Z
+DTEND:20080602T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:TRANSPARENT
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override-1
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result02 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+RRULE:FREQ=DAILY
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-master-2
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080603T120000Z
+DTSTART:20080603T120000Z
+DTEND:20080603T130000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:TRANSPARENT
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override-2
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), result01)
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user02").filter(item)), result02)
+
+ def test_public_oneuser_no_master_and_override(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+BEGIN:X-CALENDARSERVER-PERUSER
+UID:12345-67890
+X-CALENDARSERVER-PERUSER-UID:user01
+BEGIN:X-CALENDARSERVER-PERINSTANCE
+RECURRENCE-ID:20080602T120000Z
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+TRANSP:TRANSPARENT
+END:X-CALENDARSERVER-PERINSTANCE
+END:X-CALENDARSERVER-PERUSER
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result01 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+TRANSP:TRANSPARENT
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test-override
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+ result02 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T130000Z
+DTEND:20080602T140000Z
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER;CN=User 01:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user01").filter(item)), result01)
+ for item in (data, Component.fromString(data),):
+ self.assertEqual(str(PerUserDataFilter("user02").filter(item)), result02)
+
Modified: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/ical.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/ical.py 2009-11-02 19:11:51 UTC (rev 4692)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/ical.py 2009-11-02 21:47:40 UTC (rev 4693)
@@ -418,7 +418,7 @@
mtype = None
for component in self.subcomponents():
- if component.name() == "VTIMEZONE":
+ if component.name() == "VTIMEZONE" or component.name().startswith("X-"):
continue
elif mtype and (mtype != component.name()):
raise ValueError("Component contains more than one type of primary type: %r" % (self,))
@@ -437,7 +437,7 @@
result = None
for component in self.subcomponents():
- if component.name() == "VTIMEZONE":
+ if component.name() == "VTIMEZONE" or component.name().startswith("X-"):
continue
elif not allow_multiple and (result is not None):
raise ValueError("Calendar contains more than one primary component: %r" % (self,))
@@ -457,7 +457,7 @@
assert self.name() == "VCALENDAR", "Must be a VCALENDAR: %r" % (self,)
for component in self.subcomponents():
- if component.name() == "VTIMEZONE":
+ if component.name() == "VTIMEZONE" or component.name().startswith("X-"):
continue
if not component.hasProperty("RECURRENCE-ID"):
return component
@@ -476,7 +476,7 @@
assert self.name() == "VCALENDAR", "Must be a VCALENDAR: %r" % (self,)
for component in self.subcomponents():
- if component.name() == "VTIMEZONE":
+ if component.name() == "VTIMEZONE" or component.name().startswith("X-"):
continue
rid = component.getRecurrenceIDUTC()
if rid and recurrence_id and compareDateTime(rid, recurrence_id) == 0:
@@ -1018,7 +1018,7 @@
if self.name() == "VCALENDAR":
result = ()
for component in self.subcomponents():
- if component.name() != "VTIMEZONE":
+ if component.name() != "VTIMEZONE" and not component.name().startswith("X-"):
result += component.getComponentInstances()
return result
else:
@@ -1033,7 +1033,7 @@
# Extract appropriate sub-component if this is a VCALENDAR
if self.name() == "VCALENDAR":
for component in self.subcomponents():
- if component.name() != "VTIMEZONE" and component.isRecurring():
+ if component.name() != "VTIMEZONE" and not component.name().startswith("X-") and component.isRecurring():
return True
else:
for propname in ("RRULE", "RDATE", "EXDATE", "RECURRENCE-ID",):
@@ -1161,7 +1161,7 @@
if not hasattr(self, "_resource_uid"):
for subcomponent in self.subcomponents():
- if subcomponent.name() != "VTIMEZONE":
+ if subcomponent.name() != "VTIMEZONE" and not subcomponent.name().startswith("X-"):
self._resource_uid = subcomponent.propertyValue("UID")
break
else:
@@ -1183,6 +1183,8 @@
name = subcomponent.name()
if name == "VTIMEZONE":
has_timezone = True
+ elif subcomponent.name().startswith("X-"):
+ continue
else:
self._resource_type = name
break
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20091102/5f2ca6ed/attachment-0001.html>
More information about the calendarserver-changes
mailing list