[CalendarServer-changes] [1625] CalendarServer/branches/users/cdaboo/more-od-schema-1617

source_changes at macosforge.org source_changes at macosforge.org
Wed Jun 27 12:08:56 PDT 2007


Revision: 1625
          http://trac.macosforge.org/projects/calendarserver/changeset/1625
Author:   cdaboo at apple.com
Date:     2007-06-27 12:08:55 -0700 (Wed, 27 Jun 2007)

Log Message:
-----------
Allow resources/locations to have their delegate/proxy information set via the directory service.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts-test.xml
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts.dtd
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts.xml
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/appleopendirectory.py
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/calendaruserproxy.py
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/directory.py
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/principal.py
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/accounts.xml
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_opendirectory.py
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_opendirectoryschema.py
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_principal.py
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_xmlfile.py
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/xmlaccountsparser.py
    CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/xmlfile.py

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts-test.xml
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts-test.xml	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts-test.xml	2007-06-27 19:08:55 UTC (rev 1625)
@@ -47,6 +47,9 @@
     <password>resource%02d</password>
     <name>Resource %02d</name>
     <auto-schedule/>
+    <delegates>
+      <member type="users">user01</member>
+    </delegates>
   </resource>
   <group>
     <uid>group01</uid>

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts.dtd
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts.dtd	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts.dtd	2007-06-27 19:08:55 UTC (rev 1625)
@@ -25,10 +25,10 @@
   <!ELEMENT group (uid, guid, password, name, members, cuaddr*)>
     <!ATTLIST group repeat CDATA "1">
 
-  <!ELEMENT resource (uid, guid, password, name, cuaddr*, auto-schedule?)>
+  <!ELEMENT resource (uid, guid, password, name, cuaddr*, auto-schedule?, delegates?)>
     <!ATTLIST resource repeat CDATA "1">
 
-  <!ELEMENT location (uid, guid, password, name, cuaddr*, auto-schedule?)>
+  <!ELEMENT location (uid, guid, password, name, cuaddr*, auto-schedule?, delegates?)>
     <!ATTLIST location repeat CDATA "1">
 
   <!ELEMENT member (#PCDATA)>
@@ -39,6 +39,7 @@
   <!ELEMENT password      (#PCDATA)>
   <!ELEMENT name          (#PCDATA)>
   <!ELEMENT cuaddr        (#PCDATA)>
+  <!ELEMENT members       (member*)>
   <!ELEMENT auto-schedule EMPTY>
-  <!ELEMENT members       (member*)>
+  <!ELEMENT delegates     (member*)>
 >

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts.xml
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts.xml	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/conf/accounts.xml	2007-06-27 19:08:55 UTC (rev 1625)
@@ -43,6 +43,9 @@
     <password>mercury</password>
     <name>Mecury Conference Room, Building 1, 2nd Floor</name>
     <auto-schedule/>
+    <delegates>
+      <member type="users">test</member>
+    </delegates>
   </location>
 </accounts>
 

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/appleopendirectory.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/appleopendirectory.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -25,6 +25,7 @@
     "OpenDirectoryInitError",
 ]
 
+import itertools
 import sys
 
 import opendirectory
@@ -335,14 +336,14 @@
 
         @param plist: the plist that is the attribute value.
         @type plist: str
-        @return: a C{bool} indicating whether the AutoAcceptsInvitation key was set to true or false,
-            and return C{False} if the key was not present at all.
+        @return: a C{tuple} of C{bool} for auto-accept and C{str} for delegate GUID.
         """
         plist = readPlistFromString(plist)
         wpframework = plist.get("com.apple.WhitePagesFramework", {})
         autoaccept = wpframework.get("AutoAcceptsInvitation", False)
+        delegate = wpframework.get("CalendaringDelegate")
         
-        return autoaccept
+        return (autoaccept, delegate,)
 
     def recordTypes(self):
         return (
@@ -503,10 +504,13 @@
 
             # Special case for resources and locations
             autoSchedule = False
+            delegateGUIDs = ()
             if recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
                 resourceInfo = value.get(dsattributes.kDSNAttrResourceInfo)
                 if resourceInfo is not None:
-                    autoSchedule = self._parseResourceInfo(resourceInfo)
+                    autoSchedule, delegate = self._parseResourceInfo(resourceInfo)
+                    if delegate:
+                        delegateGUIDs = (delegate,)
 
             records[recordShortName] = OpenDirectoryRecord(
                 service               = self,
@@ -517,6 +521,7 @@
                 calendarUserAddresses = cuaddrset,
                 memberGUIDs           = memberGUIDs,
                 autoSchedule          = autoSchedule,
+                delegateGUIDs         = delegateGUIDs,
             )
 
             #log.debug("Populated record: %s" % (records[recordShortName],))
@@ -554,7 +559,7 @@
     """
     Open Directory implementation of L{IDirectoryRecord}.
     """
-    def __init__(self, service, recordType, guid, shortName, fullName, calendarUserAddresses, memberGUIDs, autoSchedule):
+    def __init__(self, service, recordType, guid, shortName, fullName, calendarUserAddresses, memberGUIDs, autoSchedule, delegateGUIDs):
         super(OpenDirectoryRecord, self).__init__(
             service               = service,
             recordType            = recordType,
@@ -565,6 +570,7 @@
             autoSchedule          = autoSchedule,
         )
         self._memberGUIDs = tuple(memberGUIDs)
+        self._delegateGUIDs = tuple(delegateGUIDs)
 
     def members(self):
         if self.recordType != DirectoryService.recordType_groups:
@@ -582,6 +588,25 @@
             if self.guid in groupRecord._memberGUIDs:
                 yield groupRecord
 
+    def delegates(self):
+        if self.recordType not in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+            return
+
+        for guid in self._delegateGUIDs:
+            delegateRecord = self.service.recordWithGUID(guid)
+            if delegateRecord is None:
+                log.err("No record for delegate in %s with GUID %s" % (self.shortName, guid))
+            else:
+                yield delegateRecord
+
+    def delegateFor(self):
+        for delegateRecord in itertools.chain(
+                                  self.service.recordsForType(DirectoryService.recordType_resources).itervalues(),
+                                  self.service.recordsForType(DirectoryService.recordType_locations).itervalues()
+                              ):
+            if self.guid in delegateRecord._delegateGUIDs:
+                yield delegateRecord
+
     def verifyCredentials(self, credentials):
         if isinstance(credentials, UsernamePassword):
             try:

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/calendaruserproxy.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/calendaruserproxy.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -33,6 +33,7 @@
 from twisted.web2.dav.util import joinURL
 from twisted.web2.http import HTTPError, StatusResponse
 
+from twistedcaldav.config import config
 from twistedcaldav.extensions import DAVFile, DAVPrincipalResource
 from twistedcaldav.extensions import ReadOnlyWritePropertiesResourceMixIn
 from twistedcaldav.sql import AbstractSQLDatabase
@@ -56,6 +57,14 @@
             ),
         )
         
+        # Add admins
+        aces += tuple([davxml.ACE(
+                    davxml.Principal(davxml.HRef(principal)),
+                    davxml.Grant(davxml.Privilege(davxml.All())),
+                    davxml.Protected(),
+                 ) for principal in config.AdminPrincipals
+                ])
+
         return davxml.ACL(*aces)
 
     def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
@@ -121,7 +130,15 @@
         assert isinstance(property, davxml.WebDAVElement)
 
         if property.qname() == (dav_namespace, "group-member-set"):
-            return self.setGroupMemberSet(property, request)
+            if self.parent.lockedDelegates():
+                raise HTTPError(
+                    StatusResponse(
+                        responsecode.FORBIDDEN,
+                        "Delegates cannot be changed."
+                    )
+                )
+            else:
+                return self.setGroupMemberSet(property, request)
 
         return super(CalendarUserProxyPrincipalResource, self).writeProperty(property, request)
 
@@ -202,7 +219,7 @@
                 """Principal UID: %s\n"""          % (self.principalUID(),),
                 """Principal URL: %s\n"""          % (link(self.principalURL()),),
                 """\nAlternate URIs:\n"""          , format_list(self.alternateURIs()),
-                """\nGroup members:\n"""           , format_list(link(p.principalURL()) for p in self.groupMembers()),
+                """\nGroup members (%s):\n"""      % ({False:"Unlocked", True:"Locked"}[self.parent.lockedDelegates()]), format_list(link(p.principalURL()) for p in self.groupMembers()),
                 """\nGroup memberships:\n"""       , format_list(link(p.principalURL()) for p in self.groupMemberships()),
                 """</pre></blockquote></div>""",
                 output
@@ -237,9 +254,17 @@
         return self.parent.principalCollections()
 
     def groupMembers(self):
-        # Get member GUIDs and map to principal resources
-        members = self._index().getMembers(self.guid)
-        return [self.pcollection.principalForGUID(guid) for guid in members]
+        # If parent principal has fixed set of delegates use those
+        if self.parent.lockedDelegates():
+            # Fixed delegates are only for read-write - the read-only list is empty
+            if self.proxyType == "calendar-proxy-write":
+                return self.parent.delegates()
+            else:
+                return ()
+        else:
+            # Get member GUIDs and map to principal resources
+            members = self._index().getMembers(self.guid)
+            return [self.pcollection.principalForGUID(guid) for guid in members]
 
     def groupMemberships(self):
         # Get membership GUIDs and map to principal resources

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/directory.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/directory.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -195,6 +195,15 @@
     def groups(self):
         return ()
 
+    def delegates(self):
+        return ()
+
+    def delegateFor(self):
+        return ()
+
+    def lockedDelegates(self):
+        return self.recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations)
+
     def verifyCredentials(self, credentials):
         return False
 

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/principal.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/principal.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -359,7 +359,7 @@
     def principalURL(self):
         return self._url
 
-    def _getRelatives(self, method, record=None, relatives=None, records=None):
+    def _getRelatives(self, method, record=None, relatives=None, records=None, proxy=False):
         if record is None:
             record = self.record
         if relatives is None:
@@ -373,9 +373,14 @@
             for relative in getattr(record, method)():
                 if relative not in records:
                     if relative.recordType == myRecordType: 
-                        relatives.add(self.parent.getChild(None, record=relative))
+                        found = self.parent.getChild(None, record=relative)
                     else:
-                        relatives.add(self.parent.parent.getChild(relative.recordType).getChild(None, record=relative))
+                        found = self.parent.parent.getChild(relative.recordType).getChild(None, record=relative)
+                    
+                    if proxy:
+                        found = found.getChild("calendar-proxy-write")
+                    relatives.add(found)
+
                     self._getRelatives(method, relative, relatives, records)
 
         return relatives
@@ -426,10 +431,15 @@
 
     def groupMemberships(self):
         groups = self._getRelatives("groups")
+
         if config.EnableProxyPrincipals:
+            # Get any directory specified delegates
+            groups.update(self._getRelatives("delegateFor", proxy=True))
+
             # Get proxy group GUIDs and map to principal resources
             proxies = self._map_calendar_user_proxy_guids(self._calendar_user_proxy_index().getMemberships(self.principalUID()))
             groups.update(proxies)
+
         return groups
 
     def principalCollections(self):
@@ -457,7 +467,13 @@
 
     def autoSchedule(self):
         return self.record.autoSchedule
-        
+    
+    def delegates(self):
+        return self._getRelatives("delegates")
+
+    def lockedDelegates(self):
+        return self.record.lockedDelegates()
+
     def scheduleInbox(self, request):
         home = self._calendarHome()
         if home is None:

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/accounts.xml
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/accounts.xml	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/accounts.xml	2007-06-27 19:08:55 UTC (rev 1625)
@@ -123,6 +123,9 @@
     <name>Gemini Twelve</name>
     <cuaddr>mailto:gemini at example.com</cuaddr>
     <auto-schedule/>
+    <delegates>
+      <member>wsanchez</member>
+    </delegates>
   </location>
   <location>
     <uid>apollo</uid>

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_opendirectory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_opendirectory.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_opendirectory.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -69,7 +69,8 @@
                 "GUID",
                 set("mailtoguid at example.com",),
                 [],
-                False
+                False,
+                ()
             )
 
             digestFields = {}

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_opendirectoryschema.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_opendirectoryschema.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_opendirectoryschema.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -1002,6 +1002,8 @@
         <false/>
         <key>Label</key>
         <string>Location</string>
+        <key>CalendaringDelegate</key>
+        <string>1234-GUID-5678</string>
     </dict>
 </dict>
 </plist>
@@ -1017,6 +1019,8 @@
         <true/>
         <key>Label</key>
         <string>Location</string>
+        <key>CalendaringDelegate</key>
+        <string></string>
     </dict>
 </dict>
 </plist>
@@ -1055,16 +1059,18 @@
         <true/>
         <key>Label</key>
         <string>Location</string>
+        <key>CalendaringDelegate</key>
+        <string>1234-GUID-5678</string>
     </dict>
 </dict>
 </plist>
 """
 
         test_bool = (
-            (plist_good_false, False),
-            (plist_good_true, True),
-            (plist_good_missing, False),
-            (plist_wrong, False),
+            (plist_good_false, False, "1234-GUID-5678"),
+            (plist_good_true, True, ""),
+            (plist_good_missing, False, None),
+            (plist_wrong, False, None),
         )
 
         test_exception = (
@@ -1075,7 +1081,8 @@
             service = OpenDirectoryService(node="/Search", dosetup=False)
             
             for item in ODResourceInfoParse.test_bool:
-                self.assertEqual(service._parseResourceInfo(item[0]), item[1])
+                self.assertEqual(service._parseResourceInfo(item[0])[0], item[1])
+                self.assertEqual(service._parseResourceInfo(item[0])[1], item[2])
             
             for item in ODResourceInfoParse.test_exception:
                 self.assertRaises(item[1], service._parseResourceInfo, item[0])

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_principal.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_principal.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -227,8 +227,16 @@
         DirectoryPrincipalResource.groupMemberships()
         """
         for provisioningResource, recordType, recordResource, record in self._allRecords():
-            self.failUnless(set(record.groups()).issubset(set(r.record for r in recordResource.groupMemberships())))
+            self.failUnless(set(record.groups()).issubset(set(r.record for r in recordResource.groupMemberships() if hasattr(r, "record"))))
 
+    def test_delegates(self):
+        """
+        DirectoryPrincipalResource.delegates()
+        """
+        for provisioningResource, recordType, recordResource, record in self._allRecords():
+            self.failUnless(set(record.delegates()).issubset(set(r.record for r in recordResource.delegates())))
+            self.assertEqual(record.lockedDelegates(), recordResource.lockedDelegates())
+
     def test_principalUID(self):
         """
         DirectoryPrincipalResource.principalUID()

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_xmlfile.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_xmlfile.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/test/test_xmlfile.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -163,3 +163,64 @@
             set(r.shortName for r in service.listRecords(DirectoryService.recordType_users))
 
         self.assertRaises(ValueError, _findRecords)
+
+    def test_okDelegates(self):
+        service = self.service()
+
+        self.xmlFile().open("w").write(
+"""<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE accounts SYSTEM "accounts.dtd">
+<accounts realm="Test Realm">
+  <user>
+    <uid>test</uid>
+    <password>nimda</password>
+    <name>Test</name>
+  </user>
+  <location>
+    <uid>my office</uid>
+    <password>nimda</password>
+    <name>Super User</name>
+    <auto-schedule/>
+    <delegates>
+        <member>test</member>
+    </delegates>
+  </location>
+</accounts>
+"""
+        )
+        for recordType, expectedRecords in (
+            ( DirectoryService.recordType_users     , ("test",)      ),
+            ( DirectoryService.recordType_groups    , ()             ),
+            ( DirectoryService.recordType_locations , ("my office",) ),
+            ( DirectoryService.recordType_resources , ()             ),
+        ):
+            self.assertEquals(
+                set(r.shortName for r in service.listRecords(recordType)),
+                set(expectedRecords)
+            )
+        self.assertEqual(set([("users", "test",)],), service.recordWithShortName(DirectoryService.recordType_locations, "my office")._delegates)
+        self.assertEqual(set([("locations", "my office",)],), service.recordWithShortName(DirectoryService.recordType_users, "test")._delegateFor)
+
+    def test_badDelegates(self):
+        service = self.service()
+
+        self.xmlFile().open("w").write(
+"""<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE accounts SYSTEM "accounts.dtd">
+<accounts realm="Test Realm">
+  <user>
+    <uid>my office</uid>
+    <password>nimda</password>
+    <name>Super User</name>
+    <delegates>
+        <member>12345-GUID-67890</member>
+    </delegates>
+  </user>
+</accounts>
+"""
+        )
+        
+        def _findRecords():
+            set(r.shortName for r in service.listRecords(DirectoryService.recordType_users))
+
+        self.assertRaises(ValueError, _findRecords)

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/xmlaccountsparser.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/xmlaccountsparser.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/xmlaccountsparser.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -45,6 +45,7 @@
 ELEMENT_MEMBER       = "member"
 ELEMENT_CUADDR       = "cuaddr"
 ELEMENT_AUTOSCHEDULE = "auto-schedule"
+ELEMENT_DELEGATES    = "delegates"
 
 ATTRIBUTE_REALM      = "realm"
 ATTRIBUTE_REPEAT     = "repeat"
@@ -102,6 +103,13 @@
                 if item is not None:
                     item.groups.add(group.shortName)
 
+        def updateDelegateFor(delegatee):
+            # Update delegate membership
+            for recordType, shortName in delegatee.delegates:
+                item = self.items[recordType].get(shortName, None)
+                if item is not None:
+                    item.delegateFor.add((delegatee.recordType, delegatee.shortName))
+
         for child in node._get_childNodes():
             child_name = child._get_localName()
             if child_name is None:
@@ -124,9 +132,11 @@
                     newprincipal = principal.repeat(i)
                     self.items[recordType][newprincipal.shortName] = newprincipal
                     updateMembership(newprincipal)
+                    updateDelegateFor(newprincipal)
             else:
                 self.items[recordType][principal.shortName] = principal
                 updateMembership(principal)
+                updateDelegateFor(principal)
 
 class XMLAccountRecord (object):
     """
@@ -145,6 +155,8 @@
         self.groups = set()
         self.calendarUserAddresses = set()
         self.autoSchedule = False
+        self.delegates = set()
+        self.delegateFor = set()
 
     def repeat(self, ctr):
         """
@@ -178,6 +190,7 @@
         result.members = self.members
         result.calendarUserAddresses = calendarUserAddresses
         result.autoSchedule = self.autoSchedule
+        result.delegates = self.delegates
         return result
 
     def parseXML(self, node):
@@ -198,7 +211,7 @@
                 if child.firstChild is not None:
                     self.name = child.firstChild.data.encode("utf-8")
             elif child_name == ELEMENT_MEMBERS:
-                self._parseMembers(child)
+                self._parseMembers(child, self.members)
             elif child_name == ELEMENT_CUADDR:
                 if child.firstChild is not None:
                     self.calendarUserAddresses.add(child.firstChild.data.encode("utf-8"))
@@ -207,10 +220,15 @@
                 if self.recordType not in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
                     raise ValueError("<auto-schedule> element only allowed for Resources and Locations: %s" % (child_name,))
                 self.autoSchedule = True
+            elif child_name == ELEMENT_DELEGATES:
+                # Only Resources & Locations
+                if self.recordType not in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+                    raise ValueError("<auto-schedule> element only allowed for Resources and Locations: %s" % (child_name,))
+                self._parseMembers(child, self.delegates)
             else:
                 raise RuntimeError("Unknown account attribute: %s" % (child_name,))
 
-    def _parseMembers(self, node):
+    def _parseMembers(self, node, addto):
         for child in node._get_childNodes():
             if child._get_localName() == ELEMENT_MEMBER:
                 if child.hasAttribute(ATTRIBUTE_RECORDTYPE):
@@ -218,4 +236,4 @@
                 else:
                     recordType = DirectoryService.recordType_users
                 if child.firstChild is not None:
-                    self.members.add((recordType, child.firstChild.data.encode("utf-8")))
+                    addto.add((recordType, child.firstChild.data.encode("utf-8")))

Modified: CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/xmlfile.py	2007-06-27 19:04:16 UTC (rev 1624)
+++ CalendarServer/branches/users/cdaboo/more-od-schema-1617/twistedcaldav/directory/xmlfile.py	2007-06-27 19:08:55 UTC (rev 1625)
@@ -111,9 +111,11 @@
             autoSchedule          = xmlPrincipal.autoSchedule,
         )
 
-        self.password = xmlPrincipal.password
-        self._members = xmlPrincipal.members
-        self._groups  = xmlPrincipal.groups
+        self.password     = xmlPrincipal.password
+        self._members     = xmlPrincipal.members
+        self._groups      = xmlPrincipal.groups
+        self._delegates   = xmlPrincipal.delegates
+        self._delegateFor = xmlPrincipal.delegateFor
 
     def members(self):
         for recordType, shortName in self._members:
@@ -123,6 +125,14 @@
         for shortName in self._groups:
             yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName)
 
+    def delegates(self):
+        for recordType, shortName in self._delegates:
+            yield self.service.recordWithShortName(recordType, shortName)
+
+    def delegateFor(self):
+        for recordType, shortName in self._delegateFor:
+            yield self.service.recordWithShortName(recordType, shortName)
+
     def verifyCredentials(self, credentials):
         if isinstance(credentials, UsernamePassword):
             return credentials.password == self.password

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


More information about the calendarserver-changes mailing list