<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><style type="text/css"><!--
#msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre, #msg p { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; }
#msg ul { overflow: auto; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<title>[2206] CalendarServer/trunk/twistedcaldav</title>
</head>
<body>

<div id="msg">
<dl>
<dt>Revision</dt> <dd><a href="http://trac.macosforge.org/projects/calendarserver/changeset/2206">2206</a></dd>
<dt>Author</dt> <dd>wsanchez@apple.com</dd>
<dt>Date</dt> <dd>2008-03-06 12:12:32 -0800 (Thu, 06 Mar 2008)</dd>
</dl>

<h3>Log Message</h3>
<pre>Store calendar data by GUID.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunktwistedcaldavdirectorycalendarpy">CalendarServer/trunk/twistedcaldav/directory/calendar.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavdirectoryprincipalpy">CalendarServer/trunk/twistedcaldav/directory/principal.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavextensionspy">CalendarServer/trunk/twistedcaldav/extensions.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavschedulepy">CalendarServer/trunk/twistedcaldav/schedule.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavstaticpy">CalendarServer/trunk/twistedcaldav/static.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunktwistedcaldavdirectorycalendarpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/directory/calendar.py (2205 => 2206)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/directory/calendar.py        2008-03-06 20:12:04 UTC (rev 2205)
+++ CalendarServer/trunk/twistedcaldav/directory/calendar.py        2008-03-06 20:12:32 UTC (rev 2206)
</span><span class="lines">@@ -19,8 +19,10 @@
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> __all__ = [
</span><ins>+    &quot;uidsResourceName&quot;,
</ins><span class="cx">     &quot;DirectoryCalendarHomeProvisioningResource&quot;,
</span><span class="cx">     &quot;DirectoryCalendarHomeTypeProvisioningResource&quot;,
</span><ins>+    &quot;DirectoryCalendarHomeUIDProvisioningResource&quot;,
</ins><span class="cx">     &quot;DirectoryCalendarHomeResource&quot;,
</span><span class="cx"> ]
</span><span class="cx"> 
</span><span class="lines">@@ -39,6 +41,9 @@
</span><span class="cx"> from twistedcaldav.directory.idirectory import IDirectoryService
</span><span class="cx"> from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn
</span><span class="cx"> 
</span><ins>+# Use __underbars__ convention to avoid conflicts with directory resource types.
+uidsResourceName = &quot;__uids__&quot;
+
</ins><span class="cx"> class DirectoryCalendarHomeProvisioningResource (AutoProvisioningResourceMixIn, ReadOnlyResourceMixIn, DAVResource):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Resource which provisions calendar home collections as needed.    
</span><span class="lines">@@ -59,10 +64,17 @@
</span><span class="cx">         # FIXME: Smells like a hack
</span><span class="cx">         directory.calendarHomesCollection = self
</span><span class="cx"> 
</span><ins>+        #
</ins><span class="cx">         # Create children
</span><ins>+        #
+        def provisionChild(name):
+            self.putChild(name, self.provisionChild(name))
+
</ins><span class="cx">         for recordType in self.directory.recordTypes():
</span><del>-            self.putChild(recordType, self.provisionChild(recordType))
</del><ins>+            provisionChild(recordType)
</ins><span class="cx"> 
</span><ins>+        provisionChild(uidsResourceName)
+
</ins><span class="cx">     def provisionChild(self, recordType):
</span><span class="cx">         raise NotImplementedError(&quot;Subclass must implement provisionChild()&quot;)
</span><span class="cx"> 
</span><span class="lines">@@ -86,11 +98,11 @@
</span><span class="cx">         return self.directory.principalCollection.principalForRecord(record)
</span><span class="cx"> 
</span><span class="cx">     def homeForDirectoryRecord(self, record):
</span><del>-        typeResource = self.getChild(record.recordType)
-        if typeResource is None:
</del><ins>+        uidResource = self.getChild(uidsResourceName)
+        if uidResource is None:
</ins><span class="cx">             return None
</span><span class="cx">         else:
</span><del>-            return typeResource.getChild(record.shortName)
</del><ins>+            return uidResource.getChild(record.guid)
</ins><span class="cx"> 
</span><span class="cx">     ##
</span><span class="cx">     # DAV
</span><span class="lines">@@ -113,8 +125,7 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     def __init__(self, parent, recordType):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        @param path: the path to the file which will back the resource.
-        @param directory: an L{IDirectoryService} to provision calendars from.
</del><ins>+        @param parent: the parent of this resource
</ins><span class="cx">         @param recordType: the directory record type to provision.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         assert parent is not None
</span><span class="lines">@@ -131,7 +142,6 @@
</span><span class="cx"> 
</span><span class="cx">     def getChild(self, name, record=None):
</span><span class="cx">         self.provision()
</span><del>-
</del><span class="cx">         if name == &quot;&quot;:
</span><span class="cx">             return self
</span><span class="cx"> 
</span><span class="lines">@@ -139,11 +149,8 @@
</span><span class="cx">             record = self.directory.recordWithShortName(self.recordType, name)
</span><span class="cx">             if record is None:
</span><span class="cx">                 return None
</span><del>-        else:
-            assert name is None
-            name = record.shortName
</del><span class="cx"> 
</span><del>-        return self.provisionChild(name)
</del><ins>+        return self._parent.homeForDirectoryRecord(record)
</ins><span class="cx"> 
</span><span class="cx">     def listChildren(self):
</span><span class="cx">         return (
</span><span class="lines">@@ -173,6 +180,61 @@
</span><span class="cx">         return self._parent.principalForRecord(record)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+class DirectoryCalendarHomeUIDProvisioningResource (AutoProvisioningResourceMixIn, ReadOnlyResourceMixIn, DAVResource):
+    def __init__(self, parent):
+        &quot;&quot;&quot;
+        @param parent: the parent of this resource
+        &quot;&quot;&quot;
+        assert parent is not None
+
+        DAVResource.__init__(self)
+
+        self.directory = parent.directory
+        self.parent = parent
+
+    def url(self):
+        return joinURL(self.parent.url(), uidsResourceName)
+
+    def getChild(self, name, record=None):
+        self.provision()
+        if name == &quot;&quot;:
+            return self
+
+        if record is None:
+            record = self.directory.recordWithGUID(name)
+            if record is None:
+                return None
+
+        return self.provisionChild(name)
+
+    def listChildren(self):
+        return (
+            record.guid
+            for record in self.directory.listRecords(self.recordType)
+            if record.enabledForCalendaring
+        )
+
+    ##
+    # DAV
+    ##
+    
+    def isCollection(self):
+        return True
+
+    ##
+    # ACL
+    ##
+
+    def defaultAccessControlList(self):
+        return readOnlyACL
+
+    def principalCollections(self):
+        return self.parent.principalCollections()
+
+    def principalForRecord(self, record):
+        return self.parent.principalForRecord(record)
+
+
</ins><span class="cx"> class DirectoryCalendarHomeResource (AutoProvisioningResourceMixIn, CalDAVResource):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Calendar home collection resource.
</span><span class="lines">@@ -187,7 +249,7 @@
</span><span class="cx">         CalDAVResource.__init__(self)
</span><span class="cx"> 
</span><span class="cx">         self.record = record
</span><del>-        self._parent = parent
</del><ins>+        self.parent = parent
</ins><span class="cx"> 
</span><span class="cx">         # Cache children which must be of a specific type
</span><span class="cx">         childlist = (
</span><span class="lines">@@ -243,7 +305,13 @@
</span><span class="cx">         raise NotImplementedError(&quot;Subclass must implement provisionChild()&quot;)
</span><span class="cx"> 
</span><span class="cx">     def url(self):
</span><del>-        return joinURL(self._parent.url(), self.record.shortName)
</del><ins>+        return joinURL(self.parent.url(), self.record.guid)
+        ##
+        ## While the underlying primary location is GUID-based, we want
+        ## the canonical user-facing location to be recordType &amp;
+        ## shortName-based, because that's friendlier.
+        ##
+        #return joinURL(self.parent.parent.getChild(self.record.recordType).url(), self.record.shortName)
</ins><span class="cx"> 
</span><span class="cx">     ##
</span><span class="cx">     # DAV
</span><span class="lines">@@ -260,8 +328,6 @@
</span><span class="cx">         return succeed(davxml.HRef(self.principalForRecord().principalURL()))
</span><span class="cx"> 
</span><span class="cx">     def defaultAccessControlList(self):
</span><del>-        # FIXME: directory.principalCollection smells like a hack
-        # See DirectoryPrincipalProvisioningResource.__init__()
</del><span class="cx">         myPrincipal = self.principalForRecord()
</span><span class="cx"> 
</span><span class="cx">         aces = (
</span><span class="lines">@@ -306,10 +372,10 @@
</span><span class="cx">         return davxml.ACL(*aces)
</span><span class="cx"> 
</span><span class="cx">     def principalCollections(self):
</span><del>-        return self._parent.principalCollections()
</del><ins>+        return self.parent.principalCollections()
</ins><span class="cx"> 
</span><span class="cx">     def principalForRecord(self):
</span><del>-        return self._parent.principalForRecord(self.record)
</del><ins>+        return self.parent.principalForRecord(self.record)
</ins><span class="cx"> 
</span><span class="cx">     ##
</span><span class="cx">     # Quota
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavdirectoryprincipalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py (2205 => 2206)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/directory/principal.py        2008-03-06 20:12:04 UTC (rev 2205)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py        2008-03-06 20:12:32 UTC (rev 2206)
</span><span class="lines">@@ -19,8 +19,10 @@
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> __all__ = [
</span><ins>+    &quot;DirectoryProvisioningResource&quot;,
</ins><span class="cx">     &quot;DirectoryPrincipalProvisioningResource&quot;,
</span><span class="cx">     &quot;DirectoryPrincipalTypeProvisioningResource&quot;,
</span><ins>+    &quot;DirectoryPrincipalUIDProvisioningResource&quot;,
</ins><span class="cx">     &quot;DirectoryPrincipalResource&quot;,
</span><span class="cx">     &quot;DirectoryCalendarPrincipalResource&quot;,
</span><span class="cx"> ]
</span><span class="lines">@@ -58,11 +60,7 @@
</span><span class="cx">     def defaultAccessControlList(self):
</span><span class="cx">         return authReadACL
</span><span class="cx"> 
</span><del>-    def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
-        # Permissions here are fixed, and are not subject to inherritance rules, etc.
-        return succeed(self.defaultAccessControlList())
-
-class DirectoryProvisioningResource(
</del><ins>+class DirectoryProvisioningResource (
</ins><span class="cx">     AutoProvisioningFileMixIn,
</span><span class="cx">     PermissionsMixIn,
</span><span class="cx">     CalendarPrincipalCollectionResource,
</span><span class="lines">@@ -184,6 +182,8 @@
</span><span class="cx">         if record is not None:
</span><span class="cx">             return self.principalForRecord(record)
</span><span class="cx"> 
</span><ins>+        log.err(&quot;No principal for calendar user address: %r&quot; % (address,))
+
</ins><span class="cx">         return None
</span><span class="cx"> 
</span><span class="cx">     ##
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavextensionspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/extensions.py (2205 => 2206)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/extensions.py        2008-03-06 20:12:04 UTC (rev 2205)
+++ CalendarServer/trunk/twistedcaldav/extensions.py        2008-03-06 20:12:32 UTC (rev 2206)
</span><span class="lines">@@ -620,6 +620,10 @@
</span><span class="cx">     def writeProperty(self, property, request):
</span><span class="cx">         raise HTTPError(self.readOnlyResponse)
</span><span class="cx"> 
</span><ins>+    def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
+        # Permissions here are fixed, and are not subject to inherritance rules, etc.
+        return succeed(self.defaultAccessControlList())
+
</ins><span class="cx"> class XMLResponse (Response):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     XML L{Response} object.
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavschedulepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/schedule.py (2205 => 2206)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/schedule.py        2008-03-06 20:12:04 UTC (rev 2205)
+++ CalendarServer/trunk/twistedcaldav/schedule.py        2008-03-06 20:12:32 UTC (rev 2206)
</span><span class="lines">@@ -35,7 +35,6 @@
</span><span class="cx"> from twisted.web2.dav.util import joinURL
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav import caldavxml
</span><del>-from twistedcaldav import customxml
</del><span class="cx"> from twistedcaldav import itip
</span><span class="cx"> from twistedcaldav import logging
</span><span class="cx"> from twistedcaldav.resource import CalDAVResource
</span><span class="lines">@@ -355,7 +354,7 @@
</span><span class="cx">             # Map recipient to their inbox
</span><span class="cx">             inbox = None
</span><span class="cx">             if principal is None:
</span><del>-                logging.err(&quot;No principal for calendar user address: %s&quot; % (recipient,), system=&quot;CalDAV Outbox POST&quot;)
</del><ins>+                logging.err(&quot;No schedulable principal for calendar user address: %r&quot; % (recipient,), system=&quot;CalDAV Outbox POST&quot;)
</ins><span class="cx">             else:
</span><span class="cx">                 inboxURL = principal.scheduleInboxURL()
</span><span class="cx">                 if inboxURL:
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavstaticpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/static.py (2205 => 2206)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/static.py        2008-03-06 20:12:04 UTC (rev 2205)
+++ CalendarServer/trunk/twistedcaldav/static.py        2008-03-06 20:12:32 UTC (rev 2206)
</span><span class="lines">@@ -22,7 +22,9 @@
</span><span class="cx">     &quot;CalDAVFile&quot;,
</span><span class="cx">     &quot;AutoProvisioningFileMixIn&quot;,
</span><span class="cx">     &quot;CalendarHomeProvisioningFile&quot;,
</span><ins>+    &quot;CalendarHomeUIDProvisioningFile&quot;,
</ins><span class="cx">     &quot;CalendarHomeFile&quot;,
</span><ins>+    &quot;ScheduleFile&quot;,
</ins><span class="cx">     &quot;ScheduleInboxFile&quot;,
</span><span class="cx">     &quot;ScheduleOutboxFile&quot;,
</span><span class="cx">     &quot;DropBoxHomeFile&quot;,
</span><span class="lines">@@ -62,8 +64,10 @@
</span><span class="cx"> from twistedcaldav.resource import CalDAVResource, isCalendarCollectionResource, isPseudoCalendarCollectionResource
</span><span class="cx"> from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource
</span><span class="cx"> from twistedcaldav.dropbox import DropBoxHomeResource, DropBoxCollectionResource, DropBoxChildResource
</span><ins>+from twistedcaldav.directory.calendar import uidsResourceName
</ins><span class="cx"> from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
</span><span class="cx"> from twistedcaldav.directory.calendar import DirectoryCalendarHomeTypeProvisioningResource
</span><ins>+from twistedcaldav.directory.calendar import DirectoryCalendarHomeUIDProvisioningResource
</ins><span class="cx"> from twistedcaldav.directory.calendar import DirectoryCalendarHomeResource
</span><span class="cx"> from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn
</span><span class="cx"> 
</span><span class="lines">@@ -439,43 +443,68 @@
</span><span class="cx">         DirectoryCalendarHomeProvisioningResource.__init__(self, directory, url)
</span><span class="cx"> 
</span><span class="cx">     def provisionChild(self, name):
</span><ins>+        if name == uidsResourceName:
+            return CalendarHomeUIDProvisioningFile(self.fp.child(name).path, self)
+
</ins><span class="cx">         return CalendarHomeTypeProvisioningFile(self.fp.child(name).path, self, name)
</span><span class="cx"> 
</span><span class="cx">     def createSimilarFile(self, path):
</span><span class="cx">         raise HTTPError(responsecode.NOT_FOUND)
</span><span class="cx"> 
</span><span class="cx"> class CalendarHomeTypeProvisioningFile (AutoProvisioningFileMixIn, DirectoryCalendarHomeTypeProvisioningResource, DAVFile):
</span><del>-    &quot;&quot;&quot;
-    Resource which provisions calendar home collections of a specific
-    record type as needed.
-    &quot;&quot;&quot;
</del><span class="cx">     def __init__(self, path, parent, recordType):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param path: the path to the file which will back the resource.
</span><del>-        @param directory: an L{IDirectoryService} to provision calendars from.
</del><ins>+        @param parent: the parent of this resource
</ins><span class="cx">         @param recordType: the directory record type to provision.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         DAVFile.__init__(self, path)
</span><span class="cx">         DirectoryCalendarHomeTypeProvisioningResource.__init__(self, parent, recordType)
</span><span class="cx"> 
</span><ins>+class CalendarHomeUIDProvisioningFile (AutoProvisioningFileMixIn, DirectoryCalendarHomeUIDProvisioningResource, DAVFile):
+    def __init__(self, path, parent):
+        &quot;&quot;&quot;
+        @param path: the path to the file which will back the resource.
+        &quot;&quot;&quot;
+        DAVFile.__init__(self, path)
+        DirectoryCalendarHomeUIDProvisioningResource.__init__(self, parent)
+
</ins><span class="cx">     def provisionChild(self, name):
</span><del>-        record = self.directory.recordWithShortName(self.recordType, name)
</del><ins>+        record = self.directory.recordWithGUID(name)
</ins><span class="cx"> 
</span><span class="cx">         if record is None:
</span><del>-            log.msg(&quot;No directory record %r of type %r&quot; % (name, self.recordType))
</del><ins>+            log.msg(&quot;No directory record with GUID %r&quot; % (name,))
</ins><span class="cx">             return None
</span><span class="cx"> 
</span><span class="cx">         if not record.enabledForCalendaring:
</span><del>-            log.msg(&quot;Directory record %r of type %r is not enabled for calendaring&quot; % (name, self.recordType))
</del><ins>+            log.msg(&quot;Directory record %r is not enabled for calendaring&quot; % (record,))
</ins><span class="cx">             return None
</span><span class="cx"> 
</span><del>-        child = CalendarHomeFile(self.fp.child(name).path, self, record)
</del><ins>+        childPath = self.fp.child(name)
+        child = CalendarHomeFile(childPath.path, self, record)
</ins><span class="cx">         if not child.exists():
</span><del>-            # NOTE: provisionDefaultCalendars() returns a deferred, which we are ignoring.
-            # The result being that the default calendars will be present at some point
-            # in the future, not necessarily right now, and we don't have a way to wait
-            # on that to finish.
-            child.provisionDefaultCalendars()
</del><ins>+            #
+            # Find out if the child exists at the old (pre-1.2)
+            # location (ie. in the types hierarchy instead of the GUID
+            # hierarchy).
+            #
+            oldPath = self.parent.getChild(record.recordType).fp.child(record.shortName)
+            if oldPath.exists():
+                log.msg(&quot;Moving calendar home from old location %r to new location %r.&quot; % (oldPath, childPath))
+                try:
+                    oldPath.moveTo(childPath)
+                except (OSError, IOError), e:
+                    log.err(&quot;Error moving calendar home %r: %s&quot; % (oldPath, e))
+                    raise HTTPError(StatusResponse(
+                        responsecode.INTERNAL_SERVER_ERROR,
+                        &quot;Unable to move calendar home.&quot;
+                    ))
+            else:
+                # NOTE: provisionDefaultCalendars() returns a deferred, which we are ignoring.
+                # The result being that the default calendars will be present at some point
+                # in the future, not necessarily right now, and we don't have a way to wait
+                # on that to finish.
+                child.provisionDefaultCalendars()
</ins><span class="cx">         return child
</span><span class="cx"> 
</span><span class="cx">     def createSimilarFile(self, path):
</span><span class="lines">@@ -674,7 +703,7 @@
</span><span class="cx">     http_MKCOL =               NotificationsCollectionResource.http_MKCOL
</span><span class="cx">     http_MKCALENDAR =          NotificationsCollectionResource.http_MKCALENDAR
</span><span class="cx"> 
</span><del>-class NotificationFile(NotificationResource, DAVFile):
</del><ins>+class NotificationFile (NotificationResource, DAVFile):
</ins><span class="cx">     def __init__(self, path, parent):
</span><span class="cx">         super(NotificationFile, self).__init__(path, principalCollections=parent.principalCollections())
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>