[CalendarServer-changes] [2220] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Mar 10 13:57:54 PDT 2008


Revision: 2220
          http://trac.macosforge.org/projects/calendarserver/changeset/2220
Author:   wsanchez at apple.com
Date:     2008-03-10 13:57:53 -0700 (Mon, 10 Mar 2008)

Log Message:
-----------
Merge http://svn.calendarserver.org/repository/calendarserver/CalendarServer/branches/users/wsanchez/guid-calendars.

Modified Paths:
--------------
    CalendarServer/trunk/testcaldav
    CalendarServer/trunk/twistedcaldav/directory/calendar.py
    CalendarServer/trunk/twistedcaldav/directory/principal.py
    CalendarServer/trunk/twistedcaldav/directory/test/test_guidchange.py
    CalendarServer/trunk/twistedcaldav/schedule.py
    CalendarServer/trunk/twistedcaldav/static.py
    CalendarServer/trunk/twistedcaldav/test/data/makelargecalendars.py

Modified: CalendarServer/trunk/testcaldav
===================================================================
--- CalendarServer/trunk/testcaldav	2008-03-10 20:55:07 UTC (rev 2219)
+++ CalendarServer/trunk/testcaldav	2008-03-10 20:57:53 UTC (rev 2220)
@@ -71,8 +71,8 @@
   svn checkout http://svn.macosforge.org/repository/calendarserver/CalDAVTester/trunk "${cdt}"
 fi;
 
-if [ ! -e "${documentroot}/calendars/users/user01" ]; then
-	curl "http://localhost:8008/calendars/users/user01/";
+if [ ! -e "${documentroot}/calendars/__uids__/user01" ]; then
+  curl "http://localhost:8008/calendars/__uids__/user01/";
 fi;
 
 python twistedcaldav/test/data/makelargecalendars.py -n 1 -d "${documentroot}";

Modified: CalendarServer/trunk/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/calendar.py	2008-03-10 20:55:07 UTC (rev 2219)
+++ CalendarServer/trunk/twistedcaldav/directory/calendar.py	2008-03-10 20:57:53 UTC (rev 2220)
@@ -19,8 +19,10 @@
 """
 
 __all__ = [
+    "uidsResourceName",
     "DirectoryCalendarHomeProvisioningResource",
     "DirectoryCalendarHomeTypeProvisioningResource",
+    "DirectoryCalendarHomeUIDProvisioningResource",
     "DirectoryCalendarHomeResource",
 ]
 
@@ -39,6 +41,9 @@
 from twistedcaldav.directory.idirectory import IDirectoryService
 from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn
 
+# Use __underbars__ convention to avoid conflicts with directory resource types.
+uidsResourceName = "__uids__"
+
 class DirectoryCalendarHomeProvisioningResource (AutoProvisioningResourceMixIn, ReadOnlyResourceMixIn, DAVResource):
     """
     Resource which provisions calendar home collections as needed.    
@@ -59,10 +64,17 @@
         # FIXME: Smells like a hack
         directory.calendarHomesCollection = self
 
+        #
         # Create children
+        #
+        def provisionChild(name):
+            self.putChild(name, self.provisionChild(name))
+
         for recordType in self.directory.recordTypes():
-            self.putChild(recordType, self.provisionChild(recordType))
+            provisionChild(recordType)
 
+        provisionChild(uidsResourceName)
+
     def provisionChild(self, recordType):
         raise NotImplementedError("Subclass must implement provisionChild()")
 
@@ -86,11 +98,11 @@
         return self.directory.principalCollection.principalForRecord(record)
 
     def homeForDirectoryRecord(self, record):
-        typeResource = self.getChild(record.recordType)
-        if typeResource is None:
+        uidResource = self.getChild(uidsResourceName)
+        if uidResource is None:
             return None
         else:
-            return typeResource.getChild(record.shortName)
+            return uidResource.getChild(record.guid)
 
     ##
     # DAV
@@ -113,8 +125,7 @@
     """
     def __init__(self, parent, recordType):
         """
-        @param path: the path to the file which will back the resource.
-        @param directory: an L{IDirectoryService} to provision calendars from.
+        @param parent: the parent of this resource
         @param recordType: the directory record type to provision.
         """
         assert parent is not None
@@ -131,7 +142,6 @@
 
     def getChild(self, name, record=None):
         self.provision()
-
         if name == "":
             return self
 
@@ -139,11 +149,8 @@
             record = self.directory.recordWithShortName(self.recordType, name)
             if record is None:
                 return None
-        else:
-            assert name is None
-            name = record.shortName
 
-        return self.provisionChild(name)
+        return self._parent.homeForDirectoryRecord(record)
 
     def listChildren(self):
         return (
@@ -173,6 +180,61 @@
         return self._parent.principalForRecord(record)
 
 
+class DirectoryCalendarHomeUIDProvisioningResource (AutoProvisioningResourceMixIn, ReadOnlyResourceMixIn, DAVResource):
+    def __init__(self, parent):
+        """
+        @param parent: the parent of this resource
+        """
+        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 == "":
+            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)
+
+
 class DirectoryCalendarHomeResource (AutoProvisioningResourceMixIn, CalDAVResource):
     """
     Calendar home collection resource.
@@ -187,7 +249,7 @@
         CalDAVResource.__init__(self)
 
         self.record = record
-        self._parent = parent
+        self.parent = parent
 
         # Cache children which must be of a specific type
         childlist = (
@@ -243,7 +305,13 @@
         raise NotImplementedError("Subclass must implement provisionChild()")
 
     def url(self):
-        return joinURL(self._parent.url(), self.record.shortName)
+        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 &
+        ## shortName-based, because that's friendlier.
+        ##
+        #return joinURL(self.parent.parent.getChild(self.record.recordType).url(), self.record.shortName)
 
     ##
     # DAV
@@ -260,8 +328,6 @@
         return succeed(davxml.HRef(self.principalForRecord().principalURL()))
 
     def defaultAccessControlList(self):
-        # FIXME: directory.principalCollection smells like a hack
-        # See DirectoryPrincipalProvisioningResource.__init__()
         myPrincipal = self.principalForRecord()
 
         aces = (
@@ -306,10 +372,10 @@
         return davxml.ACL(*aces)
 
     def principalCollections(self):
-        return self._parent.principalCollections()
+        return self.parent.principalCollections()
 
     def principalForRecord(self):
-        return self._parent.principalForRecord(self.record)
+        return self.parent.principalForRecord(self.record)
 
     ##
     # Quota

Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/principal.py	2008-03-10 20:55:07 UTC (rev 2219)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py	2008-03-10 20:57:53 UTC (rev 2220)
@@ -19,8 +19,10 @@
 """
 
 __all__ = [
+    "DirectoryProvisioningResource",
     "DirectoryPrincipalProvisioningResource",
     "DirectoryPrincipalTypeProvisioningResource",
+    "DirectoryPrincipalUIDProvisioningResource",
     "DirectoryPrincipalResource",
     "DirectoryCalendarPrincipalResource",
 ]
@@ -62,7 +64,7 @@
         # Permissions here are fixed, and are not subject to inherritance rules, etc.
         return succeed(self.defaultAccessControlList())
 
-class DirectoryProvisioningResource(
+class DirectoryProvisioningResource (
     AutoProvisioningFileMixIn,
     PermissionsMixIn,
     CalendarPrincipalCollectionResource,
@@ -184,6 +186,8 @@
         if record is not None:
             return self.principalForRecord(record)
 
+        log.err("No principal for calendar user address: %r" % (address,))
+
         return None
 
     ##

Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_guidchange.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_guidchange.py	2008-03-10 20:55:07 UTC (rev 2219)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_guidchange.py	2008-03-10 20:57:53 UTC (rev 2220)
@@ -45,7 +45,7 @@
         self.directoryService = XMLDirectoryService(self.xmlfile)
         
         # Set up a principals hierarchy for each service we're testing with
-        name = 'principals'
+        name = "principals"
         url = "/" + name + "/"
         path = os.path.join(self.docroot, url[1:])
 
@@ -55,7 +55,7 @@
 
         provisioningResource = DirectoryPrincipalProvisioningResource(path, url, self.directoryService)
 
-        self.site.resource.putChild('principals', provisioningResource)
+        self.site.resource.putChild("principals", provisioningResource)
 
         self.setupCalendars()
 
@@ -63,25 +63,29 @@
 
     def setupCalendars(self):
         calendarCollection = CalendarHomeProvisioningFile(
-            os.path.join(self.docroot, 'calendars'),
+            os.path.join(self.docroot, "calendars"),
             self.directoryService,
-            '/calendars/'
+            "/calendars/"
         )
-        self.site.resource.putChild('calendars', calendarCollection)
+        self.site.resource.putChild("calendars", calendarCollection)
 
     def resetCalendars(self):
-        del self.site.resource.putChildren['calendars']
+        del self.site.resource.putChildren["calendars"]
         self.setupCalendars()
 
     def test_guidchange(self):
         """
         DirectoryPrincipalResource.proxies()
         """
+        oldUID = "5A985493-EE2C-4665-94CF-4DFEA3A89500"
+        newUID = "38D8AC00-5490-4425-BE3A-05FFB9862444"
+
+        homeResource = "/calendars/users/cdaboo/"
         
         def privs1(result):
             # Change GUID in record
             fd = open(self.xmlfile, "w")
-            fd.write(open(xmlFile.path, "r").read().replace("5A985493-EE2C-4665-94CF-4DFEA3A89500", "38D8AC00-5490-4425-BE3A-05FFB9862444"))
+            fd.write(open(xmlFile.path, "r").read().replace(oldUID, newUID))
             fd.close()
             fd = None
 
@@ -93,31 +97,43 @@
             self.resetCalendars()
             
             # Make sure new user cannot access old user's calendar home
-            return self._checkPrivileges(None, "/calendars/users/cdaboo/", davxml.HRef("/principals/__uids__/38D8AC00-5490-4425-BE3A-05FFB9862444/"), davxml.Write, False)
+            return self._checkPrivileges(None, homeResource, davxml.HRef("/principals/__uids__/" + newUID + "/"), davxml.Write, False)
             
         # Make sure current user has access to their calendar home
-        d = self._checkPrivileges(None, "/calendars/users/cdaboo/", davxml.HRef("/principals/__uids__/5A985493-EE2C-4665-94CF-4DFEA3A89500/"), davxml.Write, True)
+        d = self._checkPrivileges(None, homeResource, davxml.HRef("/principals/__uids__/" + oldUID + "/"), davxml.Write, True)
         d.addCallback(privs1)
         return d
-        
 
+    #
+    # This test fails because /calendars/users/cdaboo/ actually is a
+    # different resource (ie. the /calendars/__uids__/... URL would be
+    # different) when the GUID for cdaboo changes.
+    #
+    # The test needs to create a fixed resource with access granted to
+    # the old cdaboo; calendar homes no longer do this.
+    #
+    # Using the __uids__ URL won't work either because the old URL
+    # goes away with the old account.
+    #
+    test_guidchange.todo = "Test no longer works."
+
     def _checkPrivileges(self, resource, url, principal, privilege, allowed):
-        request = SimpleRequest(self.site, "GET", "/calendars/users/cdaboo/")
+        request = SimpleRequest(self.site, "GET", "/")
 
         def gotResource(resource):
             d = resource.checkPrivileges(request, (privilege,), principal=davxml.Principal(principal))
             if allowed:
                 def onError(f):
                     f.trap(AccessDeniedError)
-                    #print resource.readDeadProperty(davxml.ACL)
-                    self.fail("%s should have %s privilege on %r" % (principal.sname(), privilege.sname(), resource))
+                    #print resource.readDeadProperty(davxml.ACL).toxml()
+                    self.fail("%s should have %s privilege on %r" % (principal, privilege.sname(), resource))
                 d.addErrback(onError)
             else:
                 def onError(f):
                     f.trap(AccessDeniedError)
                 def onSuccess(_):
-                    #print resource.readDeadProperty(davxml.ACL)
-                    self.fail("%s should not have %s privilege on %r" % (principal.sname(), privilege.sname(), resource))
+                    #print resource.readDeadProperty(davxml.ACL).toxml()
+                    self.fail("%s should not have %s privilege on %r" % (principal, privilege.sname(), resource))
                 d.addCallback(onSuccess)
                 d.addErrback(onError)
             return d

Modified: CalendarServer/trunk/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/schedule.py	2008-03-10 20:55:07 UTC (rev 2219)
+++ CalendarServer/trunk/twistedcaldav/schedule.py	2008-03-10 20:57:53 UTC (rev 2220)
@@ -35,7 +35,6 @@
 from twisted.web2.dav.util import joinURL
 
 from twistedcaldav import caldavxml
-from twistedcaldav import customxml
 from twistedcaldav import itip
 from twistedcaldav import logging
 from twistedcaldav.resource import CalDAVResource
@@ -201,9 +200,9 @@
         x.getResult()
 
         # Must be content-type text/calendar
-        content_type = request.headers.getHeader("content-type")
-        if content_type is not None and (content_type.mediaType, content_type.mediaSubtype) != ("text", "calendar"):
-            logging.err("MIME type %s not allowed in calendar collection" % (content_type,), system="CalDAV Outbox POST")
+        contentType = request.headers.getHeader("content-type")
+        if contentType is not None and (contentType.mediaType, contentType.mediaSubtype) != ("text", "calendar"):
+            logging.err("MIME type %s not allowed in calendar collection" % (contentType,), system="CalDAV Outbox POST")
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-calendar-data")))
     
         # Must have Originator header
@@ -215,37 +214,37 @@
             originator = originator[0]
     
         # Verify that Originator is a valid calendar user (has an INBOX)
-        oprincipal = self.principalForCalendarUserAddress(originator)
-        if oprincipal is None:
+        originatorPrincipal = self.principalForCalendarUserAddress(originator)
+        if originatorPrincipal is None:
             logging.err("Could not find principal for originator: %s" % (originator,), system="CalDAV Outbox POST")
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
 
-        inboxURL = oprincipal.scheduleInboxURL()
+        inboxURL = originatorPrincipal.scheduleInboxURL()
         if inboxURL is None:
             logging.err("Could not find inbox for originator: %s" % (originator,), system="CalDAV Outbox POST")
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
     
         # Verify that Originator matches the authenticated user
-        if davxml.Principal(davxml.HRef(oprincipal.principalURL())) != self.currentPrincipal(request):
+        if davxml.Principal(davxml.HRef(originatorPrincipal.principalURL())) != self.currentPrincipal(request):
             logging.err("Originator: %s does not match authorized user: %s" % (originator, self.currentPrincipal(request).children[0],), system="CalDAV Outbox POST")
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
 
         # Get list of Recipient headers
-        rawrecipients = request.headers.getRawHeaders("recipient")
-        if rawrecipients is None or (len(rawrecipients) == 0):
+        rawRecipients = request.headers.getRawHeaders("recipient")
+        if rawRecipients is None or (len(rawRecipients) == 0):
             logging.err("POST request must have at least one Recipient header", system="CalDAV Outbox POST")
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-specified")))
 
         # Recipient header may be comma separated list
         recipients = []
-        for rawrecipient in rawrecipients:
-            for r in rawrecipient.split(","):
+        for rawRecipient in rawRecipients:
+            for r in rawRecipient.split(","):
                 r = r.strip()
                 if len(r):
                     recipients.append(r)
 
-        timerange = TimeRange(start="20000101", end="20000102")
-        recipients_state = {"OK":0, "BAD":0}
+        timeRange = TimeRange(start="20000101", end="20000102")
+        recipientsState = {"OK":0, "BAD":0}
 
         # Parse the calendar object from the HTTP request stream
         try:
@@ -279,18 +278,21 @@
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (calendarserver_namespace, "no-access-restrictions")))
     
         # Verify that the ORGANIZER's cu address maps to the request.uri
-        outboxURL = None
         organizer = calendar.getOrganizer()
-        if organizer is not None:
-            oprincipal = self.principalForCalendarUserAddress(organizer)
-            if oprincipal is not None:
-                outboxURL = oprincipal.scheduleOutboxURL()
-        if outboxURL is None:
+        if organizer is None:
+            organizerPrincipal = None
+        else:
+            organizerPrincipal = self.principalForCalendarUserAddress(organizer)
+
+        if organizerPrincipal is None:
             logging.err("ORGANIZER in calendar data is not valid: %s" % (calendar,), system="CalDAV Outbox POST")
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
 
         # Prevent spoofing of ORGANIZER with specific METHODs
-        if (calendar.propertyValue("METHOD") in ("PUBLISH", "REQUEST", "ADD", "CANCEL", "DECLINECOUNTER")) and (outboxURL != request.uri):
+        if (
+            calendar.propertyValue("METHOD") in ("PUBLISH", "REQUEST", "ADD", "CANCEL", "DECLINECOUNTER") and
+            organizerPrincipal.record != self.parent.record
+        ):
             logging.err("ORGANIZER in calendar data does not match owner of Outbox: %s" % (calendar,), system="CalDAV Outbox POST")
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
 
@@ -306,11 +308,8 @@
                 raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
             
             # Attendee's Outbox MUST be the request URI
-            aoutboxURL = None
-            aprincipal = self.principalForCalendarUserAddress(attendees[0])
-            if aprincipal is not None:
-                aoutboxURL = aprincipal.scheduleOutboxURL()
-            if aoutboxURL is None or aoutboxURL != request.uri:
+            attendeePrincipal = self.principalForCalendarUserAddress(attendees[0])
+            if attendeePrincipal is None or attendeePrincipal.record != self.parent.record:
                 logging.err("ATTENDEE in calendar data does not match owner of Outbox: %s" % (calendar,), system="CalDAV Outbox POST")
                 raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
 
@@ -327,11 +326,11 @@
             if dtstart is None or dtend is None:
                 logging.err("VFREEBUSY start/end not valid: %s" % (calendar,), system="CalDAV Outbox POST")
                 raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-            timerange.start = dtstart
-            timerange.end = dtend
+            timeRange.start = dtstart
+            timeRange.end = dtend
 
             # Look for maksed UID
-            excludeuid = calendar.getMaskUID()
+            excludeUID = calendar.getMaskUID()
 
             # Do free busy operation
             freebusy = True
@@ -342,10 +341,6 @@
         # Prepare for multiple responses
         responses = ScheduleResponseQueue("POST", responsecode.OK)
     
-        # Extract the ORGANIZER property and UID value from the calendar data for use later
-        organizerProp = calendar.getOrganizerProperty()
-        uid = calendar.resourceUID()
-
         # Loop over each recipient and do appropriate action.
         autoresponses = []
         for recipient in recipients:
@@ -355,7 +350,7 @@
             # Map recipient to their inbox
             inbox = None
             if principal is None:
-                logging.err("No principal for calendar user address: %s" % (recipient,), system="CalDAV Outbox POST")
+                logging.err("No schedulable principal for calendar user address: %r" % (recipient,), system="CalDAV Outbox POST")
             else:
                 inboxURL = principal.scheduleInboxURL()
                 if inboxURL:
@@ -368,7 +363,7 @@
             if inbox is None:
                 err = HTTPError(ErrorResponse(responsecode.NOT_FOUND, (caldav_namespace, "recipient-exists")))
                 responses.add(recipient, Failure(exc_value=err), reqstatus="3.7;Invalid Calendar User")
-                recipients_state["BAD"] += 1
+                recipientsState["BAD"] += 1
             
                 # Process next recipient
                 continue
@@ -377,14 +372,14 @@
                 # Check access controls
                 #
                 try:
-                    d = waitForDeferred(inbox.checkPrivileges(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef(oprincipal.principalURL()))))
+                    d = waitForDeferred(inbox.checkPrivileges(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef(organizerPrincipal.principalURL()))))
                     yield d
                     d.getResult()
                 except AccessDeniedError:
                     logging.err("Could not access Inbox for recipient: %s" % (recipient,), system="CalDAV Outbox POST")
                     err = HTTPError(ErrorResponse(responsecode.NOT_FOUND, (caldav_namespace, "recipient-permisions")))
                     responses.add(recipient, Failure(exc_value=err), reqstatus="3.8;No authority")
-                    recipients_state["BAD"] += 1
+                    recipientsState["BAD"] += 1
                 
                     # Process next recipient
                     continue
@@ -413,46 +408,54 @@
                             yield availability
                             availability = availability.getResult()
                             availability = availability.calendar()
-                            report_common.processAvailabilityFreeBusy(availability, fbinfo, timerange)
+                            report_common.processAvailabilityFreeBusy(availability, fbinfo, timeRange)
 
                         # Check to see if the recipient is the same calendar user as the organizer.
                         # Needed for masked UID stuff.
-                        same_calendar_user = oprincipal.principalURL() == principal.principalURL()
+                        same_calendar_user = organizerPrincipal.principalURL() == principal.principalURL()
 
                         # Now process free-busy set calendars
                         matchtotal = 0
-                        for calURL in fbset:
-                            cal = waitForDeferred(request.locateResource(calURL))
-                            yield cal
-                            cal = cal.getResult()
-                            if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
+                        for calendarResourceURL in fbset:
+                            calendarResource = waitForDeferred(request.locateResource(calendarResourceURL))
+                            yield calendarResource
+                            calendarResource = calendarResource.getResult()
+                            if calendarResource is None or not calendarResource.exists() or not isCalendarCollectionResource(calendarResource):
                                 # We will ignore missing calendars. If the recipient has failed to
                                 # properly manage the free busy set that should not prevent us from working.
                                 continue
                          
                             matchtotal = waitForDeferred(report_common.generateFreeBusyInfo(
                                 request,
-                                cal,
+                                calendarResource,
                                 fbinfo,
-                                timerange,
+                                timeRange,
                                 matchtotal,
-                                excludeuid=excludeuid,
-                                organizer=organizer,
-                                same_calendar_user=same_calendar_user))
+                                excludeuid = excludeUID,
+                                organizer = organizer,
+                                same_calendar_user = same_calendar_user
+                            ))
                             yield matchtotal
                             matchtotal = matchtotal.getResult()
                     
                         # Build VFREEBUSY iTIP reply for this recipient
-                        fbresult = report_common.buildFreeBusyResult(fbinfo, timerange, organizer=organizerProp, attendee=attendeeProp, uid=uid, method="REPLY")
+                        fbresult = report_common.buildFreeBusyResult(
+                            fbinfo,
+                            timeRange,
+                            organizer = calendar.getOrganizerProperty(),
+                            attendee = attendeeProp,
+                            uid = calendar.resourceUID(),
+                            method="REPLY"
+                        )
 
                         responses.add(recipient, responsecode.OK, reqstatus="2.0;Success", calendar=fbresult)
-                        recipients_state["OK"] += 1
+                        recipientsState["OK"] += 1
                 
                     except:
                         logging.err("Could not determine free busy information: %s" % (recipient,), system="CalDAV Outbox POST")
                         err = HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-permissions")))
                         responses.add(recipient, Failure(exc_value=err), reqstatus="3.8;No authority")
-                        recipients_state["BAD"] += 1
+                        recipientsState["BAD"] += 1
                 
                 else:
                     # Hash the iCalendar data for use as the last path element of the URI path
@@ -482,7 +485,7 @@
                     try:
                         d.getResult()
                         responses.add(recipient, responsecode.OK, reqstatus="2.0;Success")
-                        recipients_state["OK"] += 1
+                        recipientsState["OK"] += 1
         
                         # Store CALDAV:originator property
                         child.writeDeadProperty(caldavxml.Originator(davxml.HRef(originator)))
@@ -497,7 +500,7 @@
                         logging.err("Could not store data in Inbox : %s" % (inbox,), system="CalDAV Outbox POST")
                         err = HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-permissions")))
                         responses.add(recipient, Failure(exc_value=err), reqstatus="3.8;No authority")
-                        recipients_state["BAD"] += 1
+                        recipientsState["BAD"] += 1
 
         # Now we have to do auto-respond
         if len(autoresponses) != 0:

Modified: CalendarServer/trunk/twistedcaldav/static.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/static.py	2008-03-10 20:55:07 UTC (rev 2219)
+++ CalendarServer/trunk/twistedcaldav/static.py	2008-03-10 20:57:53 UTC (rev 2220)
@@ -22,7 +22,9 @@
     "CalDAVFile",
     "AutoProvisioningFileMixIn",
     "CalendarHomeProvisioningFile",
+    "CalendarHomeUIDProvisioningFile",
     "CalendarHomeFile",
+    "ScheduleFile",
     "ScheduleInboxFile",
     "ScheduleOutboxFile",
     "DropBoxHomeFile",
@@ -62,8 +64,10 @@
 from twistedcaldav.resource import CalDAVResource, isCalendarCollectionResource, isPseudoCalendarCollectionResource
 from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource
 from twistedcaldav.dropbox import DropBoxHomeResource, DropBoxCollectionResource, DropBoxChildResource
+from twistedcaldav.directory.calendar import uidsResourceName
 from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
 from twistedcaldav.directory.calendar import DirectoryCalendarHomeTypeProvisioningResource
+from twistedcaldav.directory.calendar import DirectoryCalendarHomeUIDProvisioningResource
 from twistedcaldav.directory.calendar import DirectoryCalendarHomeResource
 from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn
 
@@ -439,43 +443,71 @@
         DirectoryCalendarHomeProvisioningResource.__init__(self, directory, url)
 
     def provisionChild(self, name):
+        if name == uidsResourceName:
+            return CalendarHomeUIDProvisioningFile(self.fp.child(name).path, self)
+
         return CalendarHomeTypeProvisioningFile(self.fp.child(name).path, self, name)
 
     def createSimilarFile(self, path):
         raise HTTPError(responsecode.NOT_FOUND)
 
 class CalendarHomeTypeProvisioningFile (AutoProvisioningFileMixIn, DirectoryCalendarHomeTypeProvisioningResource, DAVFile):
-    """
-    Resource which provisions calendar home collections of a specific
-    record type as needed.
-    """
     def __init__(self, path, parent, recordType):
         """
         @param path: the path to the file which will back the resource.
-        @param directory: an L{IDirectoryService} to provision calendars from.
+        @param parent: the parent of this resource
         @param recordType: the directory record type to provision.
         """
         DAVFile.__init__(self, path)
         DirectoryCalendarHomeTypeProvisioningResource.__init__(self, parent, recordType)
 
+class CalendarHomeUIDProvisioningFile (AutoProvisioningFileMixIn, DirectoryCalendarHomeUIDProvisioningResource, DAVFile):
+    def __init__(self, path, parent):
+        """
+        @param path: the path to the file which will back the resource.
+        """
+        DAVFile.__init__(self, path)
+        DirectoryCalendarHomeUIDProvisioningResource.__init__(self, parent)
+
     def provisionChild(self, name):
-        record = self.directory.recordWithShortName(self.recordType, name)
+        record = self.directory.recordWithGUID(name)
 
         if record is None:
-            log.msg("No directory record %r of type %r" % (name, self.recordType))
+            log.msg("No directory record with GUID %r" % (name,))
             return None
 
         if not record.enabledForCalendaring:
-            log.msg("Directory record %r of type %r is not enabled for calendaring" % (name, self.recordType))
+            log.msg("Directory record %r is not enabled for calendaring" % (record,))
             return None
 
-        child = CalendarHomeFile(self.fp.child(name).path, self, record)
+        childPath = self.fp.child(name)
+        child = CalendarHomeFile(childPath.path, self, record)
         if not child.exists():
-            # 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()
+            self.provision()
+
+            oldPath = self.parent.getChild(record.recordType).fp.child(record.shortName)
+            if oldPath.exists():
+                #
+                # The child exists at the old (pre-1.2) location (ie. in the types
+                # hierarchy instead of the GUID hierarchy).  Move to new location.
+                #
+                log.msg("Moving calendar home from old location %r to new location %r." % (oldPath, childPath))
+                try:
+                    oldPath.moveTo(childPath)
+                except (OSError, IOError), e:
+                    log.err("Error moving calendar home %r: %s" % (oldPath, e))
+                    raise HTTPError(StatusResponse(
+                        responsecode.INTERNAL_SERVER_ERROR,
+                        "Unable to move calendar home."
+                    ))
+            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()
         return child
 
     def createSimilarFile(self, path):
@@ -674,7 +706,7 @@
     http_MKCOL =               NotificationsCollectionResource.http_MKCOL
     http_MKCALENDAR =          NotificationsCollectionResource.http_MKCALENDAR
 
-class NotificationFile(NotificationResource, DAVFile):
+class NotificationFile (NotificationResource, DAVFile):
     def __init__(self, path, parent):
         super(NotificationFile, self).__init__(path, principalCollections=parent.principalCollections())
 

Modified: CalendarServer/trunk/twistedcaldav/test/data/makelargecalendars.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/data/makelargecalendars.py	2008-03-10 20:55:07 UTC (rev 2219)
+++ CalendarServer/trunk/twistedcaldav/test/data/makelargecalendars.py	2008-03-10 20:57:53 UTC (rev 2220)
@@ -39,7 +39,7 @@
 
     
     for ctr in xrange(1, user_max + 1): 
-        path = os.path.join(document_root, "calendars/users/user%02d" % (ctr,))
+        path = os.path.join(document_root, "calendars/__uids__/user%02d" % (ctr,))
     
         try: os.makedirs(path)
         except OSError: pass

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080310/a82936cc/attachment-0001.html 


More information about the calendarserver-changes mailing list