[CalendarServer-changes] [4685] CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/ twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Fri Oct 30 13:11:26 PDT 2009
Revision: 4685
http://trac.macosforge.org/projects/calendarserver/changeset/4685
Author: cdaboo at apple.com
Date: 2009-10-30 13:11:23 -0700 (Fri, 30 Oct 2009)
Log Message:
-----------
New datafilters module used to transform data on the way in or out of the server.
Added Paths:
-----------
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/
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/datafilters/test/
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/__init__.py
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_calendardata.py
CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_privateevents.py
Added: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/__init__.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/__init__.py 2009-10-30 20:11:23 UTC (rev 4685)
@@ -0,0 +1,19 @@
+##
+# 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.
+##
+
+"""
+Data filtering module.
+"""
Added: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/calendardata.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/calendardata.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/calendardata.py 2009-10-30 20:11:23 UTC (rev 4685)
@@ -0,0 +1,178 @@
+##
+# 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.ical import Component
+from twistedcaldav.dateops import clipPeriod
+from twistedcaldav.caldavxml import LimitRecurrenceSet, Expand, AllComponents,\
+ AllProperties
+
+__all__ = [
+ "CalendarDataFilter",
+]
+
+class CalendarDataFilter(object):
+ """
+ Filter using the CALDAV:calendar-data element specification
+ """
+
+ def __init__(self, calendardata, timezone=None):
+ """
+
+ @param calendardata: the XML element describing how to filter
+ @type calendardata: L{CalendarData}
+ @param timezone: the VTIMEZONE to use for floating/all-day
+ @type timezone: L{Component}
+ """
+
+ self.calendardata = calendardata
+ self.timezone = timezone
+
+ def filter(self, ical):
+ """
+ Filter the supplied iCalendar (vobject) data using the request information.
+
+ @param ical: iCalendar object
+ @type ical: L{Component} or C{str}
+
+ @return: L{Component} for the filtered calendar data
+ """
+
+ # Empty element: get all data
+ if not self.calendardata.children:
+ return ical
+
+ # If we were passed a string, parse it out as a Component
+ if isinstance(ical, str):
+ try:
+ calendar = Component.fromString(ical)
+ except ValueError:
+ raise ValueError("Not a calendar: %r" % (ical,))
+
+ if calendar is None or calendar.name() != "VCALENDAR":
+ raise ValueError("Not a calendar: %r" % (calendar,))
+
+ # Pre-process the calendar data based on expand and limit options
+ if self.calendardata.freebusy_set:
+ calendar = self.limitFreeBusy(calendar)
+
+ # Filter data based on any provided CALDAV:comp element, or use all current data
+ if self.calendardata.component is not None:
+ calendar = self.compFilter(self.calendardata.component, calendar)
+
+ # Post-process the calendar data based on the expand and limit options
+ if self.calendardata.recurrence_set:
+ if isinstance(self.calendardata.recurrence_set, LimitRecurrenceSet):
+ calendar = self.limitRecurrence(calendar)
+ elif isinstance(self.calendardata.recurrence_set, Expand):
+ calendar = self.expandRecurrence(calendar, self.timezone)
+
+ return calendar
+
+ 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 expandRecurrence(self, calendar, timezone=None):
+ """
+ Expand the recurrence set into individual items.
+ @param calendar: the L{Component} for the calendar to operate on.
+ @param timezone: the L{Component} the VTIMEZONE to use for floating/all-day.
+ @return: the L{Component} for the result.
+ """
+ return calendar.expand(self.calendardata.recurrence_set.start, self.calendardata.recurrence_set.end, timezone)
+
+ def limitRecurrence(self, calendar):
+ """
+ Limit the set of overridden instances returned to only those
+ that are needed to describe the range of instances covered
+ by the specified time range.
+ @param calendar: the L{Component} for the calendar to operate on.
+ @return: the L{Component} for the result.
+ """
+ raise NotImplementedError()
+ return calendar
+
+ def limitFreeBusy(self, calendar):
+ """
+ Limit the range of any FREEBUSY properties in the calendar, returning
+ a new calendar if limits were applied, or the same one if no limits were applied.
+ @param calendar: the L{Component} for the calendar to operate on.
+ @return: the L{Component} for the result.
+ """
+
+ # First check for any VFREEBUSYs - can ignore limit if there are none
+ if calendar.mainType() != "VFREEBUSY":
+ return calendar
+
+ # Create duplicate calendar and filter FREEBUSY properties
+ calendar = calendar.duplicate()
+ for component in calendar.subcomponents():
+ if component.name() != "VFREEBUSY":
+ continue
+ for property in component.properties("FREEBUSY"):
+ newvalue = []
+ for period in property.value():
+ clipped = clipPeriod(period, (self.calendardata.freebusy_set.start, self.calendardata.freebusy_set.end))
+ if clipped:
+ newvalue.append(clipped)
+ if len(newvalue):
+ property.setValue(newvalue)
+ else:
+ component.removeProperty(property)
+ return calendar
+
+ def merge(self, icalnew, icalold):
+ """
+ Calendar-data merging does not happen
+ """
+ raise NotImplementedError
Added: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/filter.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/filter.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/filter.py 2009-10-30 20:11:23 UTC (rev 4685)
@@ -0,0 +1,50 @@
+##
+# 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.
+##
+
+__all__ = [
+ "ICalendarFilter",
+]
+
+class ICalendarFilter(object):
+ """
+ Abstract class that defines an iCalendar filter/merge object
+ """
+
+
+ def __init__(self):
+ pass
+
+ def filter(self, ical):
+ """
+ Filter the supplied iCalendar (vobject) data using the request information.
+
+ @param ical: iCalendar object
+ @type ical: L{Component}
+
+ @return: L{Component} for the filtered calendar data
+ """
+ raise NotImplementedError
+
+ def merge(self, icalnew, icalold):
+ """
+ Merge the old iCalendar (vobject) data into the new iCalendar data using the request information.
+
+ @param icalnew: new iCalendar object to merge data into
+ @type icalnew: L{Component}
+ @param icalold: old iCalendar data to merge data from
+ @type icalold: L{Component}
+ """
+ raise NotImplementedError
Added: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/privateevents.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/privateevents.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/privateevents.py 2009-10-30 20:11:23 UTC (rev 4685)
@@ -0,0 +1,195 @@
+##
+# 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 twisted.web2 import responsecode
+from twisted.web2.http import HTTPError, StatusResponse
+from twistedcaldav.caldavxml import Property, CalendarData, CalendarComponent,\
+ AllProperties, AllComponents
+from twistedcaldav.datafilters.calendardata import CalendarDataFilter
+
+__all__ = [
+ "PrivateEventFilter",
+]
+
+class PrivateEventFilter(object):
+ """
+ Filter a private event to match the rights of the non-owner user accessing the data
+ """
+
+ # Private Event access levels.
+ ACCESS_PROPERTY = "X-CALENDARSERVER-ACCESS"
+ ACCESS_PUBLIC = "PUBLIC"
+ ACCESS_PRIVATE = "PRIVATE"
+ ACCESS_CONFIDENTIAL = "CONFIDENTIAL"
+ ACCESS_RESTRICTED = "RESTRICTED"
+
+ accessMap = {
+ "PUBLIC" : ACCESS_PUBLIC,
+ "PRIVATE" : ACCESS_PRIVATE,
+ "CONFIDENTIAL" : ACCESS_CONFIDENTIAL,
+ "RESTRICTED" : ACCESS_RESTRICTED,
+ }
+
+ confidentialPropertiesMap = {
+ "VCALENDAR": ("PRODID", "VERSION", "CALSCALE", ACCESS_PROPERTY),
+ "VEVENT": ("UID", "RECURRENCE-ID", "SEQUENCE", "DTSTAMP", "STATUS", "TRANSP", "DTSTART", "DTEND", "DURATION", "RRULE", "RDATE", "EXRULE", "EXDATE", ),
+ "VTODO": ("UID", "RECURRENCE-ID", "SEQUENCE", "DTSTAMP", "STATUS", "DTSTART", "COMPLETED", "DUE", "DURATION", "RRULE", "RDATE", "EXRULE", "EXDATE", ),
+ "VJOURNAL": ("UID", "RECURRENCE-ID", "SEQUENCE", "DTSTAMP", "STATUS", "DTSTART", "RRULE", "RDATE", "EXRULE", "EXDATE", ),
+ "VFREEBUSY": ("UID", "DTSTAMP", "DTSTART", "DTEND", "DURATION", "FREEBUSY", ),
+ "VTIMEZONE": None,
+ }
+ extraRestrictedProperties = ("SUMMARY", "LOCATION",)
+
+ def __init__(self, accessRestriction, isowner):
+ """
+
+ @param accessRestriction: one of the access levels in L{Component}
+ @type accessRestriction: C{str}
+ @param isowner: whether the current user is the owner of the data
+ @type isowner: C{bool}
+ """
+
+ self.accessRestriction = accessRestriction
+ self.isowner = isowner
+
+ def filter(self, ical):
+ """
+ Filter the supplied iCalendar (vobject) data using the request information.
+
+ @param ical: iCalendar object
+ @type ical: L{Component} or C{str}
+
+ @return: L{Component} for the filtered calendar data
+ """
+
+ if self.isowner or self.accessRestriction == PrivateEventFilter.ACCESS_PUBLIC:
+ # No need to filter for the owner or public event
+ return ical
+
+ elif self.accessRestriction == PrivateEventFilter.ACCESS_PRIVATE:
+ # We should never get here because ACCESS_PRIVATE is protected via an ACL
+ raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Access Denied"))
+
+ elif self.accessRestriction == PrivateEventFilter.ACCESS_PUBLIC:
+ return ical
+ elif self.accessRestriction in (PrivateEventFilter.ACCESS_CONFIDENTIAL, PrivateEventFilter.ACCESS_RESTRICTED):
+ # Create a CALDAV:calendar-data element with the appropriate iCalendar Component/Property
+ # filter in place for the access restriction in use
+
+ extra_access = ()
+ if self.accessRestriction == PrivateEventFilter.ACCESS_RESTRICTED:
+ extra_access = (
+ Property(name="SUMMARY"),
+ Property(name="LOCATION"),
+ )
+
+ calendardata = CalendarData(
+ CalendarComponent(
+
+ # VCALENDAR properties
+ Property(name="PRODID"),
+ Property(name="VERSION"),
+ Property(name="CALSCALE"),
+ Property(name=PrivateEventFilter.ACCESS_PROPERTY),
+
+ # VEVENT
+ CalendarComponent(
+ Property(name="UID"),
+ Property(name="RECURRENCE-ID"),
+ Property(name="SEQUENCE"),
+ Property(name="DTSTAMP"),
+ Property(name="STATUS"),
+ Property(name="TRANSP"),
+ Property(name="DTSTART"),
+ Property(name="DTEND"),
+ Property(name="DURATION"),
+ Property(name="RRULE"),
+ Property(name="RDATE"),
+ Property(name="EXRULE"),
+ Property(name="EXDATE"),
+ *extra_access,
+ **{"name":"VEVENT"}
+ ),
+
+ # VTODO
+ CalendarComponent(
+ Property(name="UID"),
+ Property(name="RECURRENCE-ID"),
+ Property(name="SEQUENCE"),
+ Property(name="DTSTAMP"),
+ Property(name="STATUS"),
+ Property(name="DTSTART"),
+ Property(name="COMPLETED"),
+ Property(name="DUE"),
+ Property(name="DURATION"),
+ Property(name="RRULE"),
+ Property(name="RDATE"),
+ Property(name="EXRULE"),
+ Property(name="EXDATE"),
+ *extra_access,
+ **{"name":"VTODO"}
+ ),
+
+ # VJOURNAL
+ CalendarComponent(
+ Property(name="UID"),
+ Property(name="RECURRENCE-ID"),
+ Property(name="SEQUENCE"),
+ Property(name="DTSTAMP"),
+ Property(name="STATUS"),
+ Property(name="TRANSP"),
+ Property(name="DTSTART"),
+ Property(name="RRULE"),
+ Property(name="RDATE"),
+ Property(name="EXRULE"),
+ Property(name="EXDATE"),
+ *extra_access,
+ **{"name":"VJOURNAL"}
+ ),
+
+ # VFREEBUSY
+ CalendarComponent(
+ Property(name="UID"),
+ Property(name="DTSTAMP"),
+ Property(name="DTSTART"),
+ Property(name="DTEND"),
+ Property(name="DURATION"),
+ Property(name="FREEBUSY"),
+ *extra_access,
+ **{"name":"VFREEBUSY"}
+ ),
+
+ # VTIMEZONE
+ CalendarComponent(
+ AllProperties(),
+ AllComponents(),
+ name="VTIMEZONE",
+ ),
+ name="VCALENDAR",
+ ),
+ )
+
+ # Now "filter" the resource calendar data through the CALDAV:calendar-data element
+ return CalendarDataFilter(calendardata).filter(ical)
+ else:
+ # Unknown access restriction
+ raise HTTPError(StatusResponse(responsecode.FORBIDDEN))
+
+ def merge(self, icalnew, icalold):
+ """
+ Private event merging does not happen
+ """
+ raise NotImplementedError
Added: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/__init__.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/__init__.py 2009-10-30 20:11:23 UTC (rev 4685)
@@ -0,0 +1,19 @@
+##
+# Copyright (c) 2005-2007 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.
+##
+
+"""
+Tests for the twistedcaldav.datafilters module.
+"""
Added: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_calendardata.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_calendardata.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_calendardata.py 2009-10-30 20:11:23 UTC (rev 4685)
@@ -0,0 +1,361 @@
+##
+# 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.datafilters.calendardata import CalendarDataFilter
+from twistedcaldav.caldavxml import CalendarData, CalendarComponent,\
+ AllComponents, AllProperties, Property
+
+class CalendarDataTest (twistedcaldav.test.util.TestCase):
+
+ def test_empty(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")
+
+ empty = CalendarData()
+ self.assertEqual(str(CalendarDataFilter(empty).filter(data)), data)
+
+ def test_vcalendar_no_effect(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")
+
+ no_effect = CalendarData(
+ CalendarComponent(
+ name="VCALENDAR"
+ )
+ )
+ self.assertEqual(str(CalendarDataFilter(no_effect).filter(data)), data)
+
+ no_effect = CalendarData(
+ CalendarComponent(
+ AllComponents(),
+ AllProperties(),
+ name="VCALENDAR"
+ )
+ )
+ self.assertEqual(str(CalendarDataFilter(no_effect).filter(data)), data)
+
+ def test_vcalendar_no_props(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-WR-CALNAME:Help
+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")
+
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//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")
+
+ empty = CalendarData(
+ CalendarComponent(
+ AllComponents(),
+ name="VCALENDAR"
+ )
+ )
+ self.assertEqual(str(CalendarDataFilter(empty).filter(data)), result)
+
+ def test_vcalendar_no_comp(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-WR-CALNAME:Help
+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")
+
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-WR-CALNAME:Help
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ empty = CalendarData(
+ CalendarComponent(
+ AllProperties(),
+ name="VCALENDAR"
+ )
+ )
+ self.assertEqual(str(CalendarDataFilter(empty).filter(data)), result)
+
+ def test_vevent_no_effect(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")
+
+ no_effect = CalendarData(
+ CalendarComponent(
+ CalendarComponent(
+ name="VEVENT"
+ ),
+ AllProperties(),
+ name="VCALENDAR"
+ )
+ )
+ self.assertEqual(str(CalendarDataFilter(no_effect).filter(data)), data)
+
+ def test_vevent_other_component(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")
+
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ other_component = CalendarData(
+ CalendarComponent(
+ CalendarComponent(
+ name="VTODO"
+ ),
+ AllProperties(),
+ name="VCALENDAR"
+ )
+ )
+ self.assertEqual(str(CalendarDataFilter(other_component).filter(data)), result)
+
+ def test_vevent_no_props(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
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ empty = CalendarData(
+ CalendarComponent(
+ CalendarComponent(
+ AllComponents(),
+ name="VEVENT"
+ ),
+ AllProperties(),
+ name="VCALENDAR"
+ )
+ )
+
+ filtered = str(CalendarDataFilter(empty).filter(data))
+ filtered = "".join([line for line in filtered.splitlines(True) if not line.startswith("UID:")])
+
+ self.assertEqual(str(CalendarDataFilter(empty).filter(data)), result)
+
+ def test_vevent_no_comp(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
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ result = """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")
+
+ empty = CalendarData(
+ CalendarComponent(
+ CalendarComponent(
+ AllProperties(),
+ name="VEVENT"
+ ),
+ AllProperties(),
+ name="VCALENDAR"
+ )
+ )
+ self.assertEqual(str(CalendarDataFilter(empty).filter(data)), result)
+
+ def test_vevent_some_props(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
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ result = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Test
+TRIGGER;RELATED=START:-PT10M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ empty = CalendarData(
+ CalendarComponent(
+ CalendarComponent(
+ AllComponents(),
+ Property(
+ name="UID",
+ ),
+ Property(
+ name="DTSTART",
+ ),
+ Property(
+ name="DTEND",
+ ),
+ name="VEVENT"
+ ),
+ AllProperties(),
+ name="VCALENDAR"
+ )
+ )
+
+ self.assertEqual(str(CalendarDataFilter(empty).filter(data)), result)
+
Added: CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_privateevents.py
===================================================================
--- CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_privateevents.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/per-user-icalendar-4669/twistedcaldav/datafilters/test/test_privateevents.py 2009-10-30 20:11:23 UTC (rev 4685)
@@ -0,0 +1,153 @@
+##
+# 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 twisted.web2.http import HTTPError
+import twistedcaldav.test.util
+from twistedcaldav.datafilters.privateevents import PrivateEventFilter
+
+class PrivateEventsTest (twistedcaldav.test.util.TestCase):
+
+ def test_public_default(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")
+
+ self.assertEqual(str(PrivateEventFilter(PrivateEventFilter.ACCESS_PUBLIC, True).filter(data)), data)
+ self.assertEqual(str(PrivateEventFilter(PrivateEventFilter.ACCESS_PUBLIC, False).filter(data)), data)
+
+ def test_public(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:PUBLIC
+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")
+
+ self.assertEqual(str(PrivateEventFilter(PrivateEventFilter.ACCESS_PUBLIC, True).filter(data)), data)
+ self.assertEqual(str(PrivateEventFilter(PrivateEventFilter.ACCESS_PUBLIC, False).filter(data)), data)
+
+ def test_private(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:PRIVATE
+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")
+
+ self.assertEqual(str(PrivateEventFilter(PrivateEventFilter.ACCESS_PRIVATE, True).filter(data)), data)
+ pfilter = PrivateEventFilter(PrivateEventFilter.ACCESS_PRIVATE, False)
+ self.assertRaises(HTTPError, pfilter.filter, data)
+
+ def test_confidential(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:CONFIDENTIAL
+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
+SUMMARY:Confidential
+DESCRIPTION:In confidence
+LOCATION:My office
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ filtered = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+END:VEVENT
+X-CALENDARSERVER-ACCESS:CONFIDENTIAL
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ self.assertEqual(str(PrivateEventFilter(PrivateEventFilter.ACCESS_CONFIDENTIAL, True).filter(data)), data)
+ self.assertEqual(str(PrivateEventFilter(PrivateEventFilter.ACCESS_CONFIDENTIAL, False).filter(data)), filtered)
+
+ def test_restricted(self):
+
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+X-CALENDARSERVER-ACCESS:CONFIDENTIAL
+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
+SUMMARY:Confidential
+DESCRIPTION:In confidence
+LOCATION:My office
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ filtered = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+LOCATION:My office
+SUMMARY:Confidential
+END:VEVENT
+X-CALENDARSERVER-ACCESS:CONFIDENTIAL
+END:VCALENDAR
+""".replace("\n", "\r\n")
+
+ self.assertEqual(str(PrivateEventFilter(PrivateEventFilter.ACCESS_RESTRICTED, True).filter(data)), data)
+ self.assertEqual(str(PrivateEventFilter(PrivateEventFilter.ACCESS_RESTRICTED, False).filter(data)), filtered)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20091030/9658ad35/attachment-0001.html>
More information about the calendarserver-changes
mailing list