[CalendarServer-changes] [5480] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Apr 15 12:05:34 PDT 2010


Revision: 5480
          http://trac.macosforge.org/projects/calendarserver/changeset/5480
Author:   sagen at apple.com
Date:     2010-04-15 12:05:29 -0700 (Thu, 15 Apr 2010)
Log Message:
-----------
calendarserver_manage_principals can now add/remove locations and resources

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tools/principals.py
    CalendarServer/trunk/calendarserver/tools/test/test_principals.py
    CalendarServer/trunk/doc/calendarserver_manage_principals.8
    CalendarServer/trunk/twistedcaldav/directory/xmlfile.py

Modified: CalendarServer/trunk/calendarserver/tools/principals.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/principals.py	2010-04-14 18:00:45 UTC (rev 5479)
+++ CalendarServer/trunk/calendarserver/tools/principals.py	2010-04-15 19:05:29 UTC (rev 5480)
@@ -77,6 +77,8 @@
     print "  --remove-proxy=principal: remove a proxy"
     print "  --set-auto-schedule={true|false}: set auto-accept state"
     print "  --get-auto-schedule: read auto-schedule state"
+    print "  --add {locations|resources} 'full name' [record name] [GUID]: add a principal"
+    print "  --remove: remove a principal"
 
     if e:
         sys.exit(64)
@@ -86,9 +88,11 @@
 def main():
     try:
         (optargs, args) = getopt(
-            sys.argv[1:], "hf:P:", [
+            sys.argv[1:], "a:hf:P:", [
                 "help",
                 "config=",
+                "add=",
+                "remove",
                 "search=",
                 "list-principal-types",
                 "list-principals=",
@@ -110,6 +114,7 @@
     # Get configuration
     #
     configFileName = None
+    addType = None
     listPrincipalTypes = False
     listPrincipals = None
     searchPrincipals = None
@@ -122,6 +127,12 @@
         elif opt in ("-f", "--config"):
             configFileName = arg
 
+        elif opt in ("-a", "--add"):
+            addType = arg
+
+        elif opt in ("-r", "--remove"):
+            principalActions.append((action_removePrincipal,))
+
         elif opt in ("", "--list-principal-types"):
             listPrincipalTypes = True
 
@@ -227,15 +238,55 @@
 
         return
 
+    elif addType:
+
+        try:
+            addType = matchStrings(addType, ["locations", "resources"])
+        except ValueError, e:
+            print e
+            return
+
+        try:
+            fullName, shortName, guid = parseCreationArgs(args)
+        except ValueError, e:
+            print e
+            return
+
+        try:
+            record = config.directory.createRecord(addType, guid=guid,
+                shortNames=[shortName], fullName=fullName)
+        except DirectoryError, e:
+            print e
+            return
+
+        print "Added '%s' (%s) %s %s" % (record.fullName, addType,
+            record.shortNames[0], record.guid)
+        return
+
+
     elif listPrincipals:
+        try:
+            listPrincipals = matchStrings(listPrincipals, ["users", "groups",
+                "locations", "resources"])
+        except ValueError, e:
+            print e
+            return
+
         if args:
             usage("Too many arguments")
 
         try:
-            results = [(record.fullName, record.guid) for record in config.directory.listRecords(listPrincipals)]
-            results.sort()
-            for name, guid in results:
-                print '%s %s' % (name, guid)
+            results = [(record.fullName, record.shortNames[0], record.guid)
+                for record in config.directory.listRecords(listPrincipals)]
+            if results:
+                results.sort()
+                format = "%-15s %-15s %s"
+                print format % ("Full name", "Record name", "UUID")
+                print format % ("---------", "-----------", "----")
+                for fullName, shortName, guid in results:
+                    print format % ("'%s'" % (fullName,), shortName, guid)
+            else:
+                print "No records of type %s" % (listPrincipals,)
         except UnknownRecordTypeError, e:
             usage(e)
 
@@ -394,6 +445,16 @@
 def proxySubprincipal(principal, proxyType):
     return principal.getChild("calendar-proxy-" + proxyType)
 
+def action_removePrincipal(principal):
+    record = principal.record
+    fullName = record.fullName
+    shortName = record.shortNames[0]
+    guid = record.guid
+
+    config.directory.destroyRecord(record.recordType, guid=guid)
+    print "Removed '%s' %s %s" % (fullName, shortName, guid)
+
+
 @inlineCallbacks
 def action_readProperty(resource, qname):
     property = (yield resource.readProperty(qname, None))
@@ -576,5 +637,47 @@
     duplicate or remove a non-existent assignment.
     """
 
+def parseCreationArgs(args):
+    """
+    Look at the command line arguments for --add, and figure out which
+    one is the shortName and which one is the guid by attempting to make a
+    UUID object out of them.
+    """
+
+    fullName = args[0]
+    shortName = None
+    guid = None
+    for arg in args[1:]:
+        if isUUID(arg):
+            if guid is not None:
+                # Both the 2nd and 3rd args are UUIDs.  The first one
+                # should be used for shortName.
+                shortName = guid
+            guid = arg
+        else:
+            shortName = arg
+
+    if len(args) == 3 and guid is None:
+        # both shortName and guid were specified but neither was a UUID
+        raise ValueError("Invalid value for guid")
+
+    return fullName, shortName, guid
+
+
+def isUUID(value):
+    try:
+        UUID(value)
+        return True
+    except:
+        return False
+
+def matchStrings(value, validValues):
+    for validValue in validValues:
+        if validValue.startswith(value):
+            return validValue
+
+    raise ValueError("'%s' is not a recognized value" % (value,))
+
+
 if __name__ == "__main__":
     main()

Modified: CalendarServer/trunk/calendarserver/tools/test/test_principals.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_principals.py	2010-04-14 18:00:45 UTC (rev 5479)
+++ CalendarServer/trunk/calendarserver/tools/test/test_principals.py	2010-04-15 19:05:29 UTC (rev 5480)
@@ -23,7 +23,9 @@
 from twistedcaldav.config import config
 from twistedcaldav.test.util import TestCase, CapturingProcessProtocol
 
+from calendarserver.tools.principals import parseCreationArgs, matchStrings
 
+
 class MangePrincipalsTestCase(TestCase):
 
     def setUp(self):
@@ -113,6 +115,61 @@
             self.assertTrue("user%02d" % (i,) in results)
 
     @inlineCallbacks
+    def test_addRemove(self):
+        results = yield self.runCommand("--add", "resources", "New Resource",
+            "newresource", "edaa6ae6-011b-4d89-ace3-6b688cdd91d9")
+        self.assertTrue("Added 'New Resource'" in results)
+
+        results = yield self.runCommand("--list-principals=resources")
+        self.assertTrue("newresource" in results)
+
+        results = yield self.runCommand("--add", "resources", "New Resource",
+            "newresource1", "edaa6ae6-011b-4d89-ace3-6b688cdd91d9")
+        self.assertTrue("Duplicate guid" in results)
+
+        results = yield self.runCommand("--add", "resources", "New Resource",
+            "newresource", "fdaa6ae6-011b-4d89-ace3-6b688cdd91d9")
+        self.assertTrue("Duplicate shortName" in results)
+
+        results = yield self.runCommand("--remove", "resources:newresource")
+        self.assertTrue("Removed 'New Resource'" in results)
+
+        results = yield self.runCommand("--list-principals=resources")
+        self.assertFalse("newresource" in results)
+
+    def test_parseCreationArgs(self):
+
+        self.assertEquals(("full name", None, None),
+            parseCreationArgs(("full name",)))
+
+        self.assertEquals(("full name", "short name", None),
+            parseCreationArgs(("full name", "short name")))
+
+        guid = "02C3DE93-E655-4856-47B76B8BB1A7BDCE"
+
+        self.assertEquals(("full name", "short name", guid),
+            parseCreationArgs(("full name", "short name", guid)))
+
+        self.assertEquals(("full name", "short name", guid),
+            parseCreationArgs(("full name", guid, "short name")))
+
+        self.assertEquals(("full name", None, guid),
+            parseCreationArgs(("full name", guid)))
+
+        self.assertRaises(
+            ValueError,
+            parseCreationArgs, ("full name", "non guid", "non guid")
+        )
+
+    def test_matchStrings(self):
+        self.assertEquals("abc", matchStrings("a", ("abc", "def")))
+        self.assertEquals("def", matchStrings("de", ("abc", "def")))
+        self.assertRaises(
+            ValueError,
+            matchStrings, "foo", ("abc", "def")
+        )
+
+    @inlineCallbacks
     def test_modifyWriteProxies(self):
         results = yield self.runCommand("--add-write-proxy=users:user01",
             "locations:location01")

Modified: CalendarServer/trunk/doc/calendarserver_manage_principals.8
===================================================================
--- CalendarServer/trunk/doc/calendarserver_manage_principals.8	2010-04-14 18:00:45 UTC (rev 5479)
+++ CalendarServer/trunk/doc/calendarserver_manage_principals.8	2010-04-15 19:05:29 UTC (rev 5480)
@@ -35,6 +35,8 @@
 .Op Fl -remove-proxy Ar principal
 .Op Fl -set-auto-schedule Ar true|false
 .Op Fl -get-auto-schedule
+.Op Fl -add Ar locations|resources full-name [record-name] [GUID]
+.Op Fl -remove
 .Ar principal
 .Op principal ...
 .Sh DESCRIPTION
@@ -114,6 +116,8 @@
 Enable or disable automatic scheduling.
 .It Fl -get-auto-schedule
 Get the automatic scheduling state.
+.It Fl -add Ar locations|resources full-name [record-name] [GUID]
+Add a new location or resource. Record name and GUID are optional.  If GUID is not specified, one will be generated.  If record name is not specified, the record name will be set to the GUID.
 .El
 .Sh EXAMPLES
 Add Alice and Bob as read proxies for Joe and display the list of Joe's proxies:
@@ -132,6 +136,22 @@
 .Pp
 .Dl "calendarserver_manage_principals --search joe"
 .Pp
+Add a location:
+.Pp
+.Dl "calendarserver_manage_principals --add locations 'Example Office' office1"
+.Pp
+Add a resource:
+.Pp
+.Dl "calendarserver_manage_principals --add resources 'Example Projector' proj1"
+.Pp
+List all resource:
+.Pp
+.Dl "calendarserver_manage_principals --list-principals resources"
+.Pp
+Remove a resource:
+.Pp
+.Dl "calendarserver_manage_principals --remove resources:proj1"
+.Pp
 .Sh FILES
 .Bl -tag -width flag
 .It /etc/caldavd/caldavd.plist

Modified: CalendarServer/trunk/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/xmlfile.py	2010-04-14 18:00:45 UTC (rev 5479)
+++ CalendarServer/trunk/twistedcaldav/directory/xmlfile.py	2010-04-15 19:05:29 UTC (rev 5480)
@@ -339,6 +339,10 @@
             for xmlPrincipal in accounts[recType].itervalues():
                 if xmlPrincipal.guid == guid:
                     raise DirectoryError("Duplicate guid: %s" % (guid,))
+                for shortName in shortNames:
+                    if shortName in xmlPrincipal.shortNames:
+                        raise DirectoryError("Duplicate shortName: %s" %
+                            (shortName,))
                 self._addElement(accountsElement, xmlPrincipal)
 
         xmlPrincipal = XMLAccountRecord(recordType)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100415/7e427f3f/attachment-0001.html>


More information about the calendarserver-changes mailing list