[CalendarServer-changes] [1889] CalendarServer/trunk/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Thu Sep 20 14:25:51 PDT 2007


Revision: 1889
          http://trac.macosforge.org/projects/calendarserver/changeset/1889
Author:   wsanchez at apple.com
Date:     2007-09-20 14:25:50 -0700 (Thu, 20 Sep 2007)

Log Message:
-----------
Add an enabledForCalendaring option (default=True) on IDirectoryRecord
which determines whether a calendar home should be provisioned for the
record.

In the OpenDirectory case (this should be extended to other
directories as well), load up all groups, but set
enabledForCalendaring to False (and force calendarUserAddresses to be
an empty list) if the group doesn't have a ServicesLocator from this
server.

Rename DirectoryPrincipalResource to
DirectoryCalendarPrincipalResource and create a new superclass
DirectoryPrincipalResource which is not a CalDAV principal, but is
instead a generic WebDAV principal (which doesn't have all of the
CalDAV live properties).  Records that do not have calendar homes are
provisioned with generic WebDAV principals, while those that do get
CalDAV principals.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py
    CalendarServer/trunk/twistedcaldav/directory/calendar.py
    CalendarServer/trunk/twistedcaldav/directory/directory.py
    CalendarServer/trunk/twistedcaldav/directory/idirectory.py
    CalendarServer/trunk/twistedcaldav/directory/principal.py
    CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectory.py
    CalendarServer/trunk/twistedcaldav/extensions.py
    CalendarServer/trunk/twistedcaldav/static.py

Modified: CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py	2007-09-20 20:39:17 UTC (rev 1888)
+++ CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py	2007-09-20 21:25:50 UTC (rev 1889)
@@ -519,7 +519,11 @@
                     query = dsquery.expression(dsquery.expression.OR,
                                                guidQueries)
 
-            else:
+            #
+            # For groups, we'll load all entries, even if they don't
+            # have a services locator for this server.
+            #
+            elif recordType != DirectoryService.recordType_groups:
                 subquery = dsquery.match(dsattributes.kDSNAttrServicesLocator, self.servicetag, dsattributes.eDSExact)
                 if query is None:
                     query = subquery
@@ -568,13 +572,17 @@
         guids   = {}
 
         for (key, value) in results.iteritems():
+            enabledForCalendaring = True
+
             if self.requireComputerRecord:
-                services = value.get(dsattributes.kDSNAttrServicesLocator)
+                if not value.get(dsattributes.kDSNAttrServicesLocator):
+                    if recordType == DirectoryService.recordType_groups:
+                        enabledForCalendaring = False
+                        log.msg("Group %s is not enabled for calendaring but may be used in ACLs" % (key,))
+                    else:
+                        log.err("Directory (incorrectly) returned a record with no ServicesLocator attribute: %s" % (key,))
+                        continue
 
-                if not services:
-                    log.err("Directory (incorrectly) returned a record with no ServicesLocator attribute: %s" % (key,))
-                    continue
-
             # Now get useful record info.
             recordShortName = key
             guid = value.get(dsattributes.kDS1AttrGeneratedUID)
@@ -583,7 +591,10 @@
             realName = value.get(dsattributes.kDS1AttrDistinguishedName)
 
             # Get calendar user addresses from directory record.
-            cuaddrset = self._getCalendarUserAddresses(recordType, key, value)
+            if enabledForCalendaring:
+                calendarUserAddresses = self._getCalendarUserAddresses(recordType, key, value)
+            else:
+                calendarUserAddresses = ()
 
             # Special case for groups.
             if recordType == DirectoryService.recordType_groups:
@@ -616,9 +627,10 @@
                 guid                  = guid,
                 shortName             = recordShortName,
                 fullName              = realName,
-                calendarUserAddresses = cuaddrset,
+                calendarUserAddresses = calendarUserAddresses,
+                autoSchedule          = autoSchedule,
+                enabledForCalendaring = enabledForCalendaring,
                 memberGUIDs           = memberGUIDs,
-                autoSchedule          = autoSchedule,
                 proxyGUIDs            = proxyGUIDs,
             )
             records[recordShortName] = guids[guid] = record
@@ -662,7 +674,11 @@
     """
     Open Directory implementation of L{IDirectoryRecord}.
     """
-    def __init__(self, service, recordType, guid, shortName, fullName, calendarUserAddresses, memberGUIDs, autoSchedule, proxyGUIDs):
+    def __init__(
+        self, service, recordType, guid, shortName, fullName,
+        calendarUserAddresses, autoSchedule, enabledForCalendaring,
+        memberGUIDs, proxyGUIDs,
+    ):
         super(OpenDirectoryRecord, self).__init__(
             service               = service,
             recordType            = recordType,
@@ -671,6 +687,7 @@
             fullName              = fullName,
             calendarUserAddresses = calendarUserAddresses,
             autoSchedule          = autoSchedule,
+            enabledForCalendaring = enabledForCalendaring,
         )
         self._memberGUIDs = tuple(memberGUIDs)
         self._proxyGUIDs = tuple(proxyGUIDs)
@@ -681,9 +698,7 @@
 
         for guid in self._memberGUIDs:
             userRecord = self.service.recordWithGUID(guid)
-            if userRecord is None:
-                log.err("No record for member of group %s with GUID %s" % (self.shortName, guid))
-            else:
+            if userRecord is not None:
                 yield userRecord
 
     def groups(self):

Modified: CalendarServer/trunk/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/calendar.py	2007-09-20 20:39:17 UTC (rev 1888)
+++ CalendarServer/trunk/twistedcaldav/directory/calendar.py	2007-09-20 21:25:50 UTC (rev 1889)
@@ -149,7 +149,11 @@
         return self.provisionChild(name)
 
     def listChildren(self):
-        return (record.shortName for record in self.directory.listRecords(self.recordType))
+        return (
+            record.shortName
+            for record in self.directory.listRecords(self.recordType)
+            if record.enabledForCalendaring
+        )
 
     ##
     # DAV

Modified: CalendarServer/trunk/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/directory.py	2007-09-20 20:39:17 UTC (rev 1888)
+++ CalendarServer/trunk/twistedcaldav/directory/directory.py	2007-09-20 21:25:50 UTC (rev 1889)
@@ -155,7 +155,10 @@
             self.fullName
         )
 
-    def __init__(self, service, recordType, guid, shortName, fullName, calendarUserAddresses, autoSchedule):
+    def __init__(
+        self, service, recordType, guid, shortName, fullName,
+        calendarUserAddresses, autoSchedule, enabledForCalendaring=True,
+    ):
         assert service.realmName is not None
         assert recordType
         assert shortName
@@ -163,13 +166,17 @@
         if not guid:
             guid = uuidFromName(service.guid, "%s:%s" % (recordType, shortName))
 
-        calendarUserAddresses.add("urn:uuid:%s" % (guid,))
+        if enabledForCalendaring:
+            calendarUserAddresses.add("urn:uuid:%s" % (guid,))
+        else:
+            assert len(calendarUserAddresses) == 0
 
         self.service               = service
         self.recordType            = recordType
         self.guid                  = guid
         self.shortName             = shortName
         self.fullName              = fullName
+        self.enabledForCalendaring = enabledForCalendaring
         self.calendarUserAddresses = calendarUserAddresses
         self.autoSchedule          = autoSchedule
 

Modified: CalendarServer/trunk/twistedcaldav/directory/idirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/idirectory.py	2007-09-20 20:39:17 UTC (rev 1888)
+++ CalendarServer/trunk/twistedcaldav/directory/idirectory.py	2007-09-20 21:25:50 UTC (rev 1889)
@@ -78,6 +78,8 @@
     shortName             = Attribute("The name of this record.")
     fullName              = Attribute("The full name of this record.")
     calendarUserAddresses = Attribute("A set of calendar user addresses for this record.")
+    autoSchedule          = Attribute("Principal identified by this record should automatically accept/deny meetings.")
+    enabledForCalendaring = Attribute("Determines whether this record should be provisioned with a calendar home.")
 
     def members():
         """

Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/principal.py	2007-09-20 20:39:17 UTC (rev 1888)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py	2007-09-20 21:25:50 UTC (rev 1889)
@@ -24,6 +24,7 @@
     "DirectoryPrincipalProvisioningResource",
     "DirectoryPrincipalTypeProvisioningResource",
     "DirectoryPrincipalResource",
+    "DirectoryCalendarPrincipalResource",
 ]
 
 from cgi import escape
@@ -42,7 +43,7 @@
 from twistedcaldav.directory.calendaruserproxy import CalendarUserProxyDatabase
 from twistedcaldav.directory.calendaruserproxy import CalendarUserProxyPrincipalResource
 from twistedcaldav.directory.directory import DirectoryService
-from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVFile
+from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVFile, DAVPrincipalResource
 from twistedcaldav.resource import CalendarPrincipalCollectionResource, CalendarPrincipalResource
 from twistedcaldav.static import AutoProvisioningFileMixIn
 from twistedcaldav.directory.idirectory import IDirectoryService
@@ -316,7 +317,10 @@
             log.err("No principal found for UID: %s" % (name,))
             return None
 
-        primaryPrincipal = DirectoryPrincipalResource(self.fp.child(name).path, self, record)
+        if record.enabledForCalendaring:
+            primaryPrincipal = DirectoryCalendarPrincipalResource(self.fp.child(name).path, self, record)
+        else:
+            primaryPrincipal = DirectoryPrincipalResource(self.fp.child(name).path, self, record)
 
         if subType is None:
             return primaryPrincipal
@@ -334,7 +338,7 @@
     def principalCollections(self):
         return self.parent.principalCollections()
 
-class DirectoryPrincipalResource (AutoProvisioningFileMixIn, PermissionsMixIn, CalendarPrincipalResource, DAVFile):
+class DirectoryPrincipalResource (AutoProvisioningFileMixIn, PermissionsMixIn, DAVPrincipalResource, DAVFile):
     """
     Directory principal resource.
     """
@@ -344,6 +348,8 @@
         @param parent: the parent of this resource.
         @param record: the L{IDirectoryRecord} that this resource represents.
         """
+        super(DirectoryPrincipalResource, self).__init__(path)
+
         if self.isCollection():
             slash = "/"
         else:
@@ -353,8 +359,6 @@
 
         url = joinURL(parent.principalCollectionURL(), record.guid) + slash
 
-        super(DirectoryPrincipalResource, self).__init__(path, url)
-
         self.record = record
         self.parent = parent
         self._url   = url
@@ -419,8 +423,6 @@
                 """\nAlternate URIs:\n"""          , format_list(link(u) for u in self.alternateURIs()),
                 """\nGroup members:\n"""           , format_principals(self.groupMembers()),
                 """\nGroup memberships:\n"""       , format_principals(self.groupMemberships()),
-                """\nCalendar homes:\n"""          , format_list(link(u) for u in self.calendarHomeURLs()),
-                """\nCalendar user addresses:\n""" , format_list(link(a) for a in self.calendarUserAddresses()),
                 """</pre></blockquote></div>""",
                 output
             ))
@@ -433,6 +435,9 @@
     # DAV
     ##
 
+    def isCollection(self):
+        return True
+
     def displayName(self):
         if self.record.fullName:
             return self.record.fullName
@@ -473,6 +478,98 @@
 
         return relatives
 
+    def groupMembers(self):
+        return self._getRelatives("members")
+
+    def groupMemberships(self):
+        return self._getRelatives("groups")
+
+    def principalCollections(self):
+        return self.parent.principalCollections()
+
+    def principalUID(self):
+        return self.record.guid
+        
+    ##
+    # Static
+    ##
+
+    def createSimilarFile(self, path):
+        log.err("Attempt to create clone %r of resource %r" % (path, self))
+        raise HTTPError(responsecode.NOT_FOUND)
+
+    def getChild(self, name):
+        if name == "":
+            return self
+
+        return None
+
+    def listChildren(self):
+        return ()
+
+class DirectoryCalendarPrincipalResource (DirectoryPrincipalResource, CalendarPrincipalResource):
+    """
+    Directory calendar principal resource.
+    """
+    def renderDirectoryBody(self, request):
+        def format_list(items, *args):
+            def genlist():
+                try:
+                    item = None
+                    for item in items:
+                        yield " -> %s\n" % (item,)
+                    if item is None:
+                        yield " '()\n"
+                except Exception, e:
+                    log.err("Exception while rendering: %s" % (e,))
+                    Failure().printTraceback()
+                    yield "  ** %s **: %s\n" % (e.__class__.__name__, e)
+            return "".join(genlist())
+
+        def format_principals(principals):
+            return format_list(
+                """<a href="%s">%s</a>""" % (principal.principalURL(), escape(str(principal)))
+                for principal in principals
+            )
+
+        def link(url):
+            return """<a href="%s">%s</a>""" % (url, url)
+
+        def gotSuper(output):
+            return "".join((
+                """<div class="directory-listing">"""
+                """<h1>Principal Details</h1>"""
+                """<pre><blockquote>"""
+                """Directory Information\n"""
+                """---------------------\n"""
+                """Directory GUID: %s\n"""         % (self.record.service.guid,),
+                """Realm: %s\n"""                  % (self.record.service.realmName,),
+                """\n"""
+                """Principal Information\n"""
+                """---------------------\n"""
+                """GUID: %s\n"""                   % (self.record.guid,),
+                """Record type: %s\n"""            % (self.record.recordType,),
+                """Short name: %s\n"""             % (self.record.shortName,),
+                """Full name: %s\n"""              % (self.record.fullName,),
+                """Principal UID: %s\n"""          % (self.principalUID(),),
+                """Principal URL: %s\n"""          % (link(self.principalURL()),),
+                """\nAlternate URIs:\n"""          , format_list(link(u) for u in self.alternateURIs()),
+                """\nGroup members:\n"""           , format_principals(self.groupMembers()),
+                """\nGroup memberships:\n"""       , format_principals(self.groupMemberships()),
+                """\nCalendar homes:\n"""          , format_list(link(u) for u in self.calendarHomeURLs()),
+                """\nCalendar user addresses:\n""" , format_list(link(a) for a in self.calendarUserAddresses()),
+                """</pre></blockquote></div>""",
+                output
+            ))
+
+        d = super(DirectoryPrincipalResource, self).renderDirectoryBody(request)
+        d.addCallback(gotSuper)
+        return d
+
+    ##
+    # ACL
+    ##
+
     def _calendar_user_proxy_index(self):
         """
         Return the SQL database for calendar user proxies.
@@ -488,9 +585,6 @@
             setattr(pcollection, "calendar_user_proxy_db", CalendarUserProxyDatabase(pcollection.fp.path))
         return pcollection.calendar_user_proxy_db
 
-    def groupMembers(self):
-        return self._getRelatives("members")
-
     def groupMemberships(self):
         groups = self._getRelatives("groups")
 
@@ -509,16 +603,10 @@
 
         return groups
 
-    def principalCollections(self):
-        return self.parent.principalCollections()
-
     ##
     # CalDAV
     ##
 
-    def principalUID(self):
-        return self.record.guid
-        
     def calendarUserAddresses(self):
         # Get any CUAs defined by the directory implementation.
         addresses = set(self.record.calendarUserAddresses)
@@ -601,10 +689,6 @@
     # Static
     ##
 
-    def createSimilarFile(self, path):
-        log.err("Attempt to create clone %r of resource %r" % (path, self))
-        raise HTTPError(responsecode.NOT_FOUND)
-
     def getChild(self, name):
         if name == "":
             return self

Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectory.py	2007-09-20 20:39:17 UTC (rev 1888)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_opendirectory.py	2007-09-20 21:25:50 UTC (rev 1889)
@@ -21,9 +21,10 @@
 except ImportError:
     pass
 else:
+    import twisted.web2.auth.digest
+    import twistedcaldav.directory.test.util
     from twistedcaldav.directory.directory import DirectoryService
-    import twistedcaldav.directory.test.util
-    import twisted.web2.auth.digest
+    from twistedcaldav.directory.appleopendirectory import OpenDirectoryRecord
 
     # Wonky hack to prevent unclean reactor shutdowns
     class DummyReactor(object):
@@ -61,16 +62,17 @@
             return self._service
 
         def test_invalidODDigest(self):
-            record = twistedcaldav.directory.appleopendirectory.OpenDirectoryRecord(
-                self.service(),
-                DirectoryService.recordType_users,
-                "GUID-123",
-                "guidify",
-                "GUID",
-                set("mailtoguid at example.com",),
-                [],
-                False,
-                ()
+            record = OpenDirectoryRecord(
+                service               = self.service(),
+                recordType            = DirectoryService.recordType_users,
+                guid                  = "B1F93EB1-DA93-4772-9141-81C250DA35B3",
+                shortName             = "user",
+                fullName              = "Some user",
+                calendarUserAddresses = set(("mailtoguid at example.com",)),
+                autoSchedule          = False,
+                enabledForCalendaring = True,
+                memberGUIDs           = [],
+                proxyGUIDs            = (),
             )
 
             digestFields = {}

Modified: CalendarServer/trunk/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/extensions.py	2007-09-20 20:39:17 UTC (rev 1888)
+++ CalendarServer/trunk/twistedcaldav/extensions.py	2007-09-20 21:25:50 UTC (rev 1889)
@@ -512,8 +512,12 @@
                     property = waitForDeferred(self.readProperty(qname, request))
                     yield property
                     property = property.getResult()
-                    name = property.sname()
-                    value = property.toxml()
+                    if property is None:
+                        name = "{%s}%s" % qname
+                        value = "** None **"
+                    else:
+                        name = property.sname()
+                        value = property.toxml()
                 except HTTPError, e:
                     if e.response.code == responsecode.NOT_FOUND:
                         log.err("Property {%s}%s was returned by listProperties() but does not exist for resource %s."

Modified: CalendarServer/trunk/twistedcaldav/static.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/static.py	2007-09-20 20:39:17 UTC (rev 1888)
+++ CalendarServer/trunk/twistedcaldav/static.py	2007-09-20 21:25:50 UTC (rev 1889)
@@ -463,10 +463,15 @@
 
     def provisionChild(self, name):
         record = self.directory.recordWithShortName(self.recordType, name)
+
         if record is None:
             log.msg("No directory record %r of type %r" % (name, self.recordType))
             return None
 
+        if not record.enabledForCalendaring:
+            log.msg("Directory record %r of type %r is not enabled for calendaring" % (name, self.recordType))
+            return None
+
         child = CalendarHomeFile(self.fp.child(name).path, self, record)
         if not child.exists():
             # NOTE: provisionDefaultCalendars() returns a deferred, which we are ignoring.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070920/9fb69736/attachment.html


More information about the calendarserver-changes mailing list