[CalendarServer-changes] [774] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Dec 8 15:29:48 PST 2006


Revision: 774
          http://trac.macosforge.org/projects/calendarserver/changeset/774
Author:   wsanchez at apple.com
Date:     2006-12-08 15:29:47 -0800 (Fri, 08 Dec 2006)

Log Message:
-----------
Group members don't have to be users.

Modified Paths:
--------------
    CalendarServer/trunk/conf/accounts.dtd
    CalendarServer/trunk/conf/accounts.xml
    CalendarServer/trunk/twistedcaldav/directory/directory.py
    CalendarServer/trunk/twistedcaldav/directory/sqldb.py
    CalendarServer/trunk/twistedcaldav/directory/test/accounts.xml
    CalendarServer/trunk/twistedcaldav/directory/test/test_apache.py
    CalendarServer/trunk/twistedcaldav/directory/test/test_xmlfile.py
    CalendarServer/trunk/twistedcaldav/directory/test/util.py
    CalendarServer/trunk/twistedcaldav/directory/xmlaccountsparser.py
    CalendarServer/trunk/twistedcaldav/directory/xmlfile.py

Modified: CalendarServer/trunk/conf/accounts.dtd
===================================================================
--- CalendarServer/trunk/conf/accounts.dtd	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/conf/accounts.dtd	2006-12-08 23:29:47 UTC (rev 774)
@@ -28,13 +28,16 @@
   <!ELEMENT resource (uid, password, name, cuaddr*, calendar*, quota?, autorespond?, canproxy?)>
     <!ATTLIST resource repeat CDATA "1">
 
-    <!ELEMENT uid         (#PCDATA)>
-    <!ELEMENT password    (#PCDATA)>
-    <!ELEMENT name        (#PCDATA)>
-    <!ELEMENT cuaddr      (#PCDATA)>
-    <!ELEMENT calendar    (#PCDATA)>
-    <!ELEMENT quota       (#PCDATA)>
-    <!ELEMENT autorespond EMPTY>
-    <!ELEMENT canproxy    EMPTY>
-    <!ELEMENT members     (uid*)>
-    
+  <!ELEMENT member (#PCDATA)>
+    <!ATTLIST member type (user|group|resource) "user">
+
+  <!ELEMENT uid (#PCDATA)>
+  <!ELEMENT password    (#PCDATA)>
+  <!ELEMENT name        (#PCDATA)>
+  <!ELEMENT cuaddr      (#PCDATA)>
+  <!ELEMENT calendar    (#PCDATA)>
+  <!ELEMENT quota       (#PCDATA)>
+  <!ELEMENT autorespond EMPTY>
+  <!ELEMENT canproxy    EMPTY>
+  <!ELEMENT members     (member*)>
+>

Modified: CalendarServer/trunk/conf/accounts.xml
===================================================================
--- CalendarServer/trunk/conf/accounts.xml	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/conf/accounts.xml	2006-12-08 23:29:47 UTC (rev 774)
@@ -41,7 +41,7 @@
     <password>users</password>
     <name>Users Group</name>
     <members>
-      <uid>test</uid>
+      <member type="user">test</member>
     </members>
   </group>
   <resource>

Modified: CalendarServer/trunk/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/directory.py	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/twistedcaldav/directory/directory.py	2006-12-08 23:29:47 UTC (rev 774)
@@ -127,10 +127,11 @@
     implements(IDirectoryRecord)
 
     def __repr__(self):
-        return "<%s[%s@%s] %s(%s) %r>" % (
+        return "<%s[%s@%s(%s)] %s(%s) %r>" % (
             self.__class__.__name__,
             self.recordType,
-            self.service,
+            self.service.guid,
+            self.service.realmName,
             self.guid,
             self.shortName,
             self.fullName

Modified: CalendarServer/trunk/twistedcaldav/directory/sqldb.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/sqldb.py	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/twistedcaldav/directory/sqldb.py	2006-12-08 23:29:47 UTC (rev 774)
@@ -92,8 +92,9 @@
         self._db_execute("insert into SERVICE (REALM) values (:1)", parser.realm)
 
         # Now add records to db
-        for item in parser.items.itervalues():
-            self._add_to_db(item)
+        for item in parser.items.values():
+            for entry in item.itervalues():
+                self._add_to_db(entry)
         self._db_commit()
 
     def listRecords(self, recordType):
@@ -109,12 +110,12 @@
     
             # See if we have a group
             if recordType == "group":
-                rowiter = self._db_execute("select UID from GROUPS where GRPUID = :1", uid)
+                rowiter = self._db_execute("select MEMBER_RECORD_TYPE, MEMBER_UID from GROUPS where GRPUID = :1", uid)
                 for row in rowiter:
-                    members.add(row[0])
+                    members.add((row[0], row[1]))
                 
             # See if we are a member of a group
-            rowiter = self._db_execute("select GRPUID from GROUPS where UID = :1", uid)
+            rowiter = self._db_execute("select GRPUID from GROUPS where MEMBER_UID = :1", uid)
             for row in rowiter:
                 groups.add(row[0])
                 
@@ -147,12 +148,12 @@
 
         # See if we have a group
         if recordType == "group":
-            rowiter = self._db_execute("select UID from GROUPS where GRPUID = :1", uid)
+            rowiter = self._db_execute("select MEMBER_RECORD_TYPE, MEMBER_UID from GROUPS where GRPUID = :1", uid)
             for row in rowiter:
-                members.add(row[0])
+                members.add((row[0], row[1]))
             
         # See if we are a member of a group
-        rowiter = self._db_execute("select GRPUID from GROUPS where UID = :1", uid)
+        rowiter = self._db_execute("select GRPUID from GROUPS where MEMBER_UID = :1", uid)
         for row in rowiter:
             groups.add(row[0])
             
@@ -165,26 +166,27 @@
             
     def _add_to_db(self, record):
         # Do regular account entry
-        type = record.recordType
+        recordType = record.recordType
         uid = record.uid
         password = record.password
         name = record.name
         canproxy = ('F', 'T')[record.canproxy]
+
         self._db_execute(
             """
             insert into ACCOUNTS (TYPE, UID, PSWD, NAME, CANPROXY)
             values (:1, :2, :3, :4, :5)
-            """, type, uid, password, name, canproxy
+            """, recordType, uid, password, name, canproxy
         )
         
         # Check for group
-        if type == "group":
-            for member in record.members:
+        if recordType == "group":
+            for memberRecordType, memberShortName in record.members:
                 self._db_execute(
                     """
-                    insert into GROUPS (GRPUID, UID)
-                    values (:1, :2)
-                    """, uid, member
+                    insert into GROUPS (GRPUID, MEMBER_RECORD_TYPE, MEMBER_UID)
+                    values (:1, :2, :3)
+                    """, uid, memberRecordType, memberShortName
                 )
                 
         # CUAddress
@@ -204,7 +206,7 @@
         """
         self._db_execute("delete from ACCOUNTS where UID = :1", uid)
         self._db_execute("delete from GROUPS where GRPUID = :1", uid)
-        self._db_execute("delete from GROUPS where UID = :1", uid)
+        self._db_execute("delete from GROUPS where MEMBER_UID = :1", uid)
         self._db_execute("delete from CUADDRS where UID = :1", uid)
     
     def _db_type(self):
@@ -230,7 +232,7 @@
             """
             create table ACCOUNTS (
                 TYPE           text,
-                UID            text unique,
+                UID            text,
                 PSWD           text,
                 NAME           text,
                 CANPROXY       text(1)
@@ -244,8 +246,9 @@
         q.execute(
             """
             create table GROUPS (
-                GRPUID     text,
-                UID        text
+                GRPUID              text,
+                MEMBER_RECORD_TYPE  text,
+                MEMBER_UID          text
             )
             """
         )
@@ -334,8 +337,8 @@
         self._groups  = groups
 
     def members(self):
-        for shortName in self._members:
-            yield self.service.recordWithShortName("user", shortName)
+        for recordType, shortName in self._members:
+            yield self.service.recordWithShortName(recordType, shortName)
 
     def groups(self):
         for shortName in self._groups:

Modified: CalendarServer/trunk/twistedcaldav/directory/test/accounts.xml
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/accounts.xml	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/twistedcaldav/directory/test/accounts.xml	2006-12-08 23:29:47 UTC (rev 774)
@@ -22,7 +22,7 @@
   <user>
     <uid>admin</uid>
     <password>nimda</password>
-    <name>Super User</name>
+    <name>Administrators</name>
   </user>
   <user>
     <uid>proxy</uid>
@@ -64,17 +64,25 @@
     <password>managers</password>
     <name>Managers</name>
     <members>
-      <uid>lecroy</uid>
+      <member type="user">lecroy</member>
     </members>
   </group>
   <group>
+    <uid>admin</uid>
+    <password>admin</password>
+    <name>Administrators</name>
+    <members>
+      <member type="group">managers</member>
+    </members>
+  </group>
+  <group>
     <uid>grunts</uid>
     <password>grunts</password>
     <name>We do all the work</name>
     <members>
-      <uid>wsanchez</uid>
-      <uid>cdaboo</uid>
-      <uid>dreid</uid>
+      <member>wsanchez</member>
+      <member>cdaboo</member>
+      <member>dreid</member>
     </members>
   </group>
   <group>
@@ -82,7 +90,7 @@
     <password>right_coast</password>
     <name>East Coast</name>
     <members>
-      <uid>cdaboo</uid>
+      <member>cdaboo</member>
     </members>
   </group>
   <group>
@@ -90,11 +98,20 @@
     <password>left_coast</password>
     <name>West Coast</name>
     <members>
-      <uid>wsanchez</uid>
-      <uid>lecroy</uid>
-      <uid>dreid</uid>
+      <member>wsanchez</member>
+      <member>lecroy</member>
+      <member>dreid</member>
     </members>
   </group>
+  <group>
+    <uid>both_coasts</uid>
+    <password>both_coasts</password>
+    <name>Both Coasts</name>
+    <members>
+      <member type="group">right_coast</member>
+      <member type="group">left_coast</member>
+    </members>
+  </group>
   <resource>
     <uid>mercury</uid>
     <password>mercury</password>

Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_apache.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_apache.py	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_apache.py	2006-12-08 23:29:47 UTC (rev 774)
@@ -42,10 +42,10 @@
     }
 
     groups = {
-        "managers"   : { "members": ("lecroy",),                     "guid": None, "addresses": () },
-        "grunts"     : { "members": ("wsanchez", "cdaboo", "dreid"), "guid": None, "addresses": () },
-        "right_coast": { "members": ("cdaboo",),                     "guid": None, "addresses": () },
-        "left_coast" : { "members": ("wsanchez", "dreid", "lecroy"), "guid": None, "addresses": () },
+        "managers"   : { "guid": None, "addresses": (), "members": (("user", "lecroy"),)                                         },
+        "grunts"     : { "guid": None, "addresses": (), "members": (("user", "wsanchez"), ("user", "cdaboo"), ("user", "dreid")) },
+        "right_coast": { "guid": None, "addresses": (), "members": (("user", "cdaboo"),)                                         },
+        "left_coast" : { "guid": None, "addresses": (), "members": (("user", "wsanchez"), ("user", "dreid"), ("user", "lecroy")) },
     }
 
     resources = {

Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_xmlfile.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_xmlfile.py	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_xmlfile.py	2006-12-08 23:29:47 UTC (rev 774)
@@ -42,10 +42,12 @@
     }
 
     groups = {
-        "managers"   : { "password": "managers",    "members": ("lecroy",),                     "guid": None, "addresses": () },
-        "grunts"     : { "password": "grunts",      "members": ("wsanchez", "cdaboo", "dreid"), "guid": None, "addresses": () },
-        "right_coast": { "password": "right_coast", "members": ("cdaboo",),                     "guid": None, "addresses": () },
-        "left_coast" : { "password": "left_coast",  "members": ("wsanchez", "dreid", "lecroy"), "guid": None, "addresses": () },
+        "admin"      : { "password": "admin",       "guid": None, "addresses": (), "members": (("group", "managers"),)                                      },
+        "managers"   : { "password": "managers",    "guid": None, "addresses": (), "members": (("user", "lecroy"),)                                         },
+        "grunts"     : { "password": "grunts",      "guid": None, "addresses": (), "members": (("user", "wsanchez"), ("user", "cdaboo"), ("user", "dreid")) },
+        "right_coast": { "password": "right_coast", "guid": None, "addresses": (), "members": (("user", "cdaboo"),)                                         },
+        "left_coast" : { "password": "left_coast",  "guid": None, "addresses": (), "members": (("user", "wsanchez"), ("user", "dreid"), ("user", "lecroy")) },
+        "both_coasts": { "password": "both_coasts", "guid": None, "addresses": (), "members": (("group", "right_coast"), ("group", "left_coast"))           },
     }
 
     resources = {

Modified: CalendarServer/trunk/twistedcaldav/directory/test/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/util.py	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/twistedcaldav/directory/test/util.py	2006-12-08 23:29:47 UTC (rev 774)
@@ -163,9 +163,11 @@
         service = self.service()
         for group in self.groups:
             groupRecord = service.recordWithShortName("group", group)
+            result = set((m.recordType, m.shortName) for m in groupRecord.members())
+            expected = set(self.groups[group]["members"])
             self.assertEquals(
-                set(m.shortName for m in groupRecord.members()),
-                set(self.groups[group]["members"])
+                result, expected,
+                "Wrong membership for group %r: %s != %s" % (group, result, expected)
             )
 
     def test_groupMemberships(self):
@@ -177,13 +179,19 @@
         if not self.groups:
             raise SkipTest("No groups")
 
-        service = self.service()
-        for user in self.users:
-            userRecord = service.recordWithShortName("user", user)
-            self.assertEquals(
-                set(g.shortName for g in userRecord.groups()),
-                set(g for g in self.groups if user in self.groups[g]["members"])
-            )
+        for recordType, data in (
+            ( "user" , self.users  ),
+            ( "group", self.groups ),
+        ):
+            service = self.service()
+            for shortName in data:
+                record = service.recordWithShortName(recordType, shortName)
+                result = set(g.shortName for g in record.groups())
+                expected = set(g for g in self.groups if (record.recordType, shortName) in self.groups[g]["members"])
+                self.assertEquals(
+                    result, expected,
+                    "Wrong groups for %s %r: %s != %s" % (record.recordType, shortName, result, expected)
+                )
 
     def recordNames(self, recordType):
         return set(r.shortName for r in self.service().listRecords(recordType))

Modified: CalendarServer/trunk/twistedcaldav/directory/xmlaccountsparser.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/xmlaccountsparser.py	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/twistedcaldav/directory/xmlaccountsparser.py	2006-12-08 23:29:47 UTC (rev 774)
@@ -31,20 +31,22 @@
 
 from twistedcaldav.resource import CalDAVResource
 
-ELEMENT_ACCOUNTS    = "accounts"
-ELEMENT_USER        = "user"
-ELEMENT_GROUP       = "group"
-ELEMENT_RESOURCE    = "resource"
+ELEMENT_ACCOUNTS     = "accounts"
+ELEMENT_USER         = "user"
+ELEMENT_GROUP        = "group"
+ELEMENT_RESOURCE     = "resource"
 
-ELEMENT_USERID      = "uid"
-ELEMENT_PASSWORD    = "password"
-ELEMENT_NAME        = "name"
-ELEMENT_MEMBERS     = "members"
-ELEMENT_CUADDR      = "cuaddr"
-ELEMENT_CANPROXY    = "canproxy"
+ELEMENT_USERID       = "uid"
+ELEMENT_PASSWORD     = "password"
+ELEMENT_NAME         = "name"
+ELEMENT_MEMBERS      = "members"
+ELEMENT_MEMBER       = "member"
+ELEMENT_CUADDR       = "cuaddr"
+ELEMENT_CANPROXY     = "canproxy"
 
-ATTRIBUTE_REALM     = "realm"
-ATTRIBUTE_REPEAT    = "repeat"
+ATTRIBUTE_REALM      = "realm"
+ATTRIBUTE_REPEAT     = "repeat"
+ATTRIBUTE_RECORDTYPE = "type"
 
 class XMLAccountsParser(object):
     """
@@ -59,11 +61,11 @@
 
         self.xmlFile = xmlFile
         self.realm = None
-        self.items = {}
+        self.items = {"user": {}, "group": {}, "resource": {}}
 
         # Read in XML
         fd = open(self.xmlFile.path, "r")
-        doc = xml.dom.minidom.parse( fd )
+        doc = xml.dom.minidom.parse(fd)
         fd.close()
 
         # Verify that top-level element is correct
@@ -91,26 +93,28 @@
                 recordType = {
                     ELEMENT_USER:    "user",
                     ELEMENT_GROUP:   "group",
-                    ELEMENT_RESOURCE:"resource",}[child._get_localName()]
+                    ELEMENT_RESOURCE:"resource",
+                }[child._get_localName()]
                 
                 principal = XMLAccountRecord(recordType)
-                principal.parseXML( child )
+                principal.parseXML(child)
                 if repeat > 1:
                     for i in xrange(1, repeat+1):
                         newprincipal = principal.repeat(i)
-                        self.items[newprincipal.uid] = newprincipal
+                        self.items[recordType][newprincipal.uid] = newprincipal
                         if recordType == "group":
                             self._updateMembership(newprincipal)
                 else:
-                    self.items[principal.uid] = principal
+                    self.items[recordType][principal.uid] = principal
                     if recordType == "group":
                         self._updateMembership(principal)
 
     def _updateMembership(self, group):
         # Update group membership
-        for member in group.members:
-            if self.items.has_key(member):
-                self.items[member].groups.add(group.uid)
+        for recordType, shortName in group.members:
+            item = self.items[recordType].get(shortName, None)
+            if item is not None:
+                item.groups.add(group.uid)
         
 class XMLAccountRecord (object):
     """
@@ -118,9 +122,8 @@
     """
     def __init__(self, recordType):
         """
-        @param recordType:    record type for directory entry.
+        @param recordType: record type for directory entry.
         """
-        
         self.recordType = recordType
         self.uid = None
         self.password = None
@@ -136,7 +139,6 @@
         done on them with the numeric value provided.
         @param ctr: an integer to substitute into text.
         """
-        
         if self.uid.find("%") != -1:
             uid = self.uid % ctr
         else:
@@ -165,30 +167,32 @@
         result.canproxy = self.canproxy
         return result
 
-    def parseXML( self, node ):
-
+    def parseXML(self, node):
         for child in node._get_childNodes():
             if child._get_localName() == ELEMENT_USERID:
                 if child.firstChild is not None:
-                   self.uid = child.firstChild.data.encode("utf-8")
+                    self.uid = child.firstChild.data.encode("utf-8")
             elif child._get_localName() == ELEMENT_PASSWORD:
                 if child.firstChild is not None:
                     self.password = child.firstChild.data.encode("utf-8")
             elif child._get_localName() == ELEMENT_NAME:
                 if child.firstChild is not None:
-                   self.name = child.firstChild.data.encode("utf-8")
+                    self.name = child.firstChild.data.encode("utf-8")
             elif child._get_localName() == ELEMENT_MEMBERS:
                 self._parseMembers(child)
             elif child._get_localName() == ELEMENT_CUADDR:
                 if child.firstChild is not None:
-                   self.calendarUserAddresses.add(child.firstChild.data.encode("utf-8"))
+                    self.calendarUserAddresses.add(child.firstChild.data.encode("utf-8"))
             elif child._get_localName() == ELEMENT_CANPROXY:
                 CalDAVResource.proxyUsers.add(self.uid)
                 self.canproxy = True
 
-    def _parseMembers( self, node ):
-
+    def _parseMembers(self, node):
         for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_USERID:
+            if child._get_localName() == ELEMENT_MEMBER:
+                if child.hasAttribute(ATTRIBUTE_RECORDTYPE):
+                    recordType = child.getAttribute(ATTRIBUTE_RECORDTYPE)
+                else:
+                    recordType = "user"
                 if child.firstChild is not None:
-                   self.members.add(child.firstChild.data.encode("utf-8"))
+                    self.members.add((recordType, child.firstChild.data.encode("utf-8")))

Modified: CalendarServer/trunk/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/xmlfile.py	2006-12-08 22:17:31 UTC (rev 773)
+++ CalendarServer/trunk/twistedcaldav/directory/xmlfile.py	2006-12-08 23:29:47 UTC (rev 774)
@@ -82,9 +82,8 @@
         return None
 
     def _entriesForRecordType(self, recordType):
-        for entry in self._accounts().itervalues():
-            if entry.recordType == recordType:
-                 yield entry.uid, entry
+        for entry in self._accounts()[recordType].itervalues():
+             yield entry.uid, entry
 
     def _accounts(self):
         fileInfo = (self.xmlFile.getmtime(), self.xmlFile.getsize())
@@ -114,8 +113,8 @@
         self._groups  = xmlPrincipal.groups
 
     def members(self):
-        for shortName in self._members:
-            yield self.service.recordWithShortName("user", shortName)
+        for recordType, shortName in self._members:
+            yield self.service.recordWithShortName(recordType, shortName)
 
     def groups(self):
         for shortName in self._groups:

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


More information about the calendarserver-changes mailing list