[CalendarServer-changes] [12992] CalendarServer/branches/users/sagen/move2who-4

source_changes at macosforge.org source_changes at macosforge.org
Mon Mar 24 12:36:49 PDT 2014


Revision: 12992
          http://trac.calendarserver.org//changeset/12992
Author:   sagen at apple.com
Date:     2014-03-24 12:36:48 -0700 (Mon, 24 Mar 2014)
Log Message:
-----------
Get gateway working

Modified Paths:
--------------
    CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/gateway.py
    CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/test/gateway/caldavd.plist
    CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/test/test_gateway.py
    CalendarServer/branches/users/sagen/move2who-4/requirements/py_develop.txt

Modified: CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/gateway.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/gateway.py	2014-03-22 02:56:09 UTC (rev 12991)
+++ CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/gateway.py	2014-03-24 19:36:48 UTC (rev 12992)
@@ -30,17 +30,19 @@
 )
 from calendarserver.tools.purge import WorkerService, PurgeOldEventsService, DEFAULT_BATCH_SIZE, DEFAULT_RETAIN_DAYS
 from calendarserver.tools.util import (
-    principalForPrincipalID, proxySubprincipal, addProxy, removeProxy,
-    ProxyError, ProxyWarning, autoDisableMemcached
+    recordForPrincipalID, autoDisableMemcached
 )
 from pycalendar.datetime import DateTime
 from twext.who.directory import DirectoryRecord
-from twisted.internet.defer import inlineCallbacks, succeed
+from twisted.internet.defer import inlineCallbacks, succeed, returnValue
 from twistedcaldav.config import config, ConfigDict
-from txdav.xml import element as davxml
 
 from txdav.who.idirectory import RecordType as CalRecordType
 from twext.who.idirectory import FieldName
+from twisted.python.constants import Names, NamedConstant
+from txdav.who.delegates import (
+    addDelegate, removeDelegate, RecordType as DelegateRecordType
+)
 
 
 attrMap = {
@@ -227,23 +229,50 @@
     def command_getLocationList(self, command):
         return self.respondWithRecordsOfTypes(self.dir, command, ["locations"])
 
-
     @inlineCallbacks
-    def command_createLocation(self, command):
+    def _saveRecord(self, typeName, recordType, command, oldFields=None):
+        """
+        Save a record using the values in the command plist, starting with
+        any fields in the optional oldFields.
 
-        fields = {
-            FieldName.recordType: CalRecordType.location
-        }
+        @param typeName: one of "locations", "resources", "addresses"; used
+            to return the appropriate list of records afterwards.
+        @param recordType: the type of record to save
+        @param command: the command containing values
+        @type command: C{dict}
+        @param oldFields: the optional fields to start with, which will be
+            overridden by values from command
+        @type oldFiles: C{dict}
+        """
+
+        if oldFields is None:
+            fields = {
+                FieldName.recordType: recordType
+            }
+            create = True
+        else:
+            fields = oldFields.copy()
+            create = False
+
         for key, info in attrMap.iteritems():
             if key in command:
                 attrName = info['attr']
                 field = self.dir.fieldName.lookupByName(attrName)
                 valueType = self.dir.fieldName.valueType(field)
                 value = command[key]
-                if self.dir.fieldName.isMultiValue(field) and not isinstance(value, list):
+
+                # For backwards compatibility, convert to a list if needed
+                if (
+                    self.dir.fieldName.isMultiValue(field) and
+                    not isinstance(value, list)
+                ):
                     value = [value]
+
                 if valueType == int:
                     value = int(value)
+                elif issubclass(valueType, Names):
+                    if value is not None:
+                        value = valueType.lookupByName(value)
                 else:
                     if isinstance(value, list):
                         newList = []
@@ -259,9 +288,8 @@
                 fields[field] = value
 
         record = DirectoryRecord(self.dir, fields)
-        yield self.dir.updateRecords([record], create=True)
+        yield self.dir.updateRecords([record], create=create)
 
-
         readProxies = command.get("ReadProxies", None)
         if readProxies:
             proxyRecords = []
@@ -282,15 +310,62 @@
 
         yield setProxies(record, readProxies, writeProxies)
 
-        yield self.respondWithRecordsOfTypes(self.dir, command, ["locations"])
+        yield self.respondWithRecordsOfTypes(self.dir, command, [typeName])
 
 
+    def command_createLocation(self, command):
+        return self._saveRecord("locations", CalRecordType.location, command)
+
+
+    def command_createResource(self, command):
+        return self._saveRecord("resources", CalRecordType.resource, command)
+
+
+    def command_createAddress(self, command):
+        return self._saveRecord("addresses", CalRecordType.address, command)
+
+
     @inlineCallbacks
+    def command_setLocationAttributes(self, command):
+        uid = command['GeneratedUID']
+        record = yield self.dir.recordWithUID(uid)
+        yield self._saveRecord(
+            "locations",
+            CalRecordType.location,
+            command,
+            oldFields=record.fields
+        )
+
+    @inlineCallbacks
+    def command_setResourceAttributes(self, command):
+        uid = command['GeneratedUID']
+        record = yield self.dir.recordWithUID(uid)
+        yield self._saveRecord(
+            "resources",
+            CalRecordType.resource,
+            command,
+            oldFields=record.fields
+        )
+
+
+    @inlineCallbacks
+    def command_setAddressAttributes(self, command):
+        uid = command['GeneratedUID']
+        record = yield self.dir.recordWithUID(uid)
+        yield self._saveRecord(
+            "addresses",
+            CalRecordType.address,
+            command,
+            oldFields=record.fields
+        )
+
+
+    @inlineCallbacks
     def command_getLocationAttributes(self, command):
         uid = command['GeneratedUID']
         record = yield self.dir.recordWithUID(uid)
         if record is None:
-            self.respondWithError("Location not found: %s" % (uid,))
+            self.respondWithError("Principal not found: %s" % (uid,))
             return
         recordDict = recordToDict(record)
         # recordDict['AutoSchedule'] = principal.getAutoSchedule()
@@ -305,117 +380,95 @@
         self.respond(command, recordDict)
 
     command_getResourceAttributes = command_getLocationAttributes
+    command_getAddressAttributes = command_getLocationAttributes
 
 
-    @inlineCallbacks
-    def command_setLocationAttributes(self, command):
 
-        # Set autoSchedule prior to the updateRecord so that the right
-        # value ends up in memcached
-        principal = principalForPrincipalID(command['GeneratedUID'],
-            directory=self.dir)
-        (yield principal.setAutoSchedule(command.get('AutoSchedule', False)))
-        (yield principal.setAutoAcceptGroup(command.get('AutoAcceptGroup', "")))
 
-        kwargs = {}
-        for key, info in attrMap.iteritems():
-            if key in command:
-                kwargs[info['attr']] = command[key]
-        try:
-            record = (yield updateRecord(False, self.dir, "locations", **kwargs))
-        except DirectoryError, e:
-            self.respondWithError(str(e))
-            return
 
-        readProxies = command.get("ReadProxies", None)
-        writeProxies = command.get("WriteProxies", None)
-        principal = principalForPrincipalID(record.guid, directory=self.dir)
-        (yield setProxies(self.store, principal, readProxies, writeProxies, directory=self.dir))
+    # @inlineCallbacks
+    # def _setAttributes(self, )
+    #     # Set autoSchedule prior to the updateRecord so that the right
+    #     # value ends up in memcached
+    #     principal = principalForPrincipalID(command['GeneratedUID'],
+    #         directory=self.dir)
+    #     (yield principal.setAutoSchedule(command.get('AutoSchedule', False)))
+    #     (yield principal.setAutoAcceptGroup(command.get('AutoAcceptGroup', "")))
 
-        yield self.command_getLocationAttributes(command)
+    #     kwargs = {}
+    #     for key, info in attrMap.iteritems():
+    #         if key in command:
+    #             kwargs[info['attr']] = command[key]
+    #     try:
+    #         record = (yield updateRecord(False, self.dir, "locations", **kwargs))
+    #     except DirectoryError, e:
+    #         self.respondWithError(str(e))
+    #         return
 
+    #     readProxies = command.get("ReadProxies", None)
+    #     writeProxies = command.get("WriteProxies", None)
+    #     principal = principalForPrincipalID(record.guid, directory=self.dir)
+    #     (yield setProxies(self.store, principal, readProxies, writeProxies, directory=self.dir))
 
-    def command_deleteLocation(self, command):
-        kwargs = {}
-        for key, info in attrMap.iteritems():
-            if key in command:
-                kwargs[info['attr']] = command[key]
-        try:
-            self.dir.destroyRecord("locations", **kwargs)
-        except DirectoryError, e:
-            self.respondWithError(str(e))
-            return
-        self.respondWithRecordsOfTypes(self.dir, command, ["locations"])
+    #     yield self.command_getLocationAttributes(command)
 
 
+
     # Resources
 
     def command_getResourceList(self, command):
         self.respondWithRecordsOfTypes(self.dir, command, ["resources"])
 
 
-    @inlineCallbacks
-    def command_createResource(self, command):
-        kwargs = {}
-        for key, info in attrMap.iteritems():
-            if key in command:
-                kwargs[info['attr']] = command[key]
+    # @inlineCallbacks
+    # def command_createResource(self, command):
+    #     kwargs = {}
+    #     for key, info in attrMap.iteritems():
+    #         if key in command:
+    #             kwargs[info['attr']] = command[key]
 
-        try:
-            record = (yield updateRecord(True, self.dir, "resources", **kwargs))
-        except DirectoryError, e:
-            self.respondWithError(str(e))
-            return
+    #     try:
+    #         record = (yield updateRecord(True, self.dir, "resources", **kwargs))
+    #     except DirectoryError, e:
+    #         self.respondWithError(str(e))
+    #         return
 
-        readProxies = command.get("ReadProxies", None)
-        writeProxies = command.get("WriteProxies", None)
-        principal = principalForPrincipalID(record.guid, directory=self.dir)
-        (yield setProxies(self.store, principal, readProxies, writeProxies, directory=self.dir))
+    #     readProxies = command.get("ReadProxies", None)
+    #     writeProxies = command.get("WriteProxies", None)
+    #     principal = principalForPrincipalID(record.guid, directory=self.dir)
+    #     (yield setProxies(self.store, principal, readProxies, writeProxies, directory=self.dir))
 
-        self.respondWithRecordsOfTypes(self.dir, command, ["resources"])
+    #     self.respondWithRecordsOfTypes(self.dir, command, ["resources"])
 
 
-    @inlineCallbacks
-    def command_setResourceAttributes(self, command):
+    # @inlineCallbacks
+    # def command_setResourceAttributes(self, command):
 
-        # Set autoSchedule prior to the updateRecord so that the right
-        # value ends up in memcached
-        principal = principalForPrincipalID(command['GeneratedUID'],
-            directory=self.dir)
-        (yield principal.setAutoSchedule(command.get('AutoSchedule', False)))
-        (yield principal.setAutoAcceptGroup(command.get('AutoAcceptGroup', "")))
+    #     # Set autoSchedule prior to the updateRecord so that the right
+    #     # value ends up in memcached
+    #     principal = principalForPrincipalID(command['GeneratedUID'],
+    #         directory=self.dir)
+    #     (yield principal.setAutoSchedule(command.get('AutoSchedule', False)))
+    #     (yield principal.setAutoAcceptGroup(command.get('AutoAcceptGroup', "")))
 
-        kwargs = {}
-        for key, info in attrMap.iteritems():
-            if key in command:
-                kwargs[info['attr']] = command[key]
-        try:
-            record = (yield updateRecord(False, self.dir, "resources", **kwargs))
-        except DirectoryError, e:
-            self.respondWithError(str(e))
-            return
+    #     kwargs = {}
+    #     for key, info in attrMap.iteritems():
+    #         if key in command:
+    #             kwargs[info['attr']] = command[key]
+    #     try:
+    #         record = (yield updateRecord(False, self.dir, "resources", **kwargs))
+    #     except DirectoryError, e:
+    #         self.respondWithError(str(e))
+    #         return
 
-        readProxies = command.get("ReadProxies", None)
-        writeProxies = command.get("WriteProxies", None)
-        principal = principalForPrincipalID(record.guid, directory=self.dir)
-        (yield setProxies(self.store, principal, readProxies, writeProxies, directory=self.dir))
+    #     readProxies = command.get("ReadProxies", None)
+    #     writeProxies = command.get("WriteProxies", None)
+    #     principal = principalForPrincipalID(record.guid, directory=self.dir)
+    #     (yield setProxies(self.store, principal, readProxies, writeProxies, directory=self.dir))
 
-        yield self.command_getResourceAttributes(command)
+    #     yield self.command_getResourceAttributes(command)
 
 
-    def command_deleteResource(self, command):
-        kwargs = {}
-        for key, info in attrMap.iteritems():
-            if key in command:
-                kwargs[info['attr']] = command[key]
-        try:
-            self.dir.destroyRecord("resources", **kwargs)
-        except DirectoryError, e:
-            self.respondWithError(str(e))
-            return
-        self.respondWithRecordsOfTypes(self.dir, command, ["resources"])
-
-
     # deferred
     def command_getLocationAndResourceList(self, command):
         return self.respondWithRecordsOfTypes(self.dir, command, ["locations", "resources"])
@@ -424,62 +477,60 @@
     # Addresses
 
     def command_getAddressList(self, command):
-        self.respondWithRecordsOfTypes(self.dir, command, ["addresses"])
+        return self.respondWithRecordsOfTypes(self.dir, command, ["addresses"])
 
 
-    @inlineCallbacks
-    def command_createAddress(self, command):
-        kwargs = {}
-        for key, info in attrMap.iteritems():
-            if key in command:
-                kwargs[info['attr']] = command[key]
+    # @inlineCallbacks
+    # def command_createAddress(self, command):
+    #     kwargs = {}
+    #     for key, info in attrMap.iteritems():
+    #         if key in command:
+    #             kwargs[info['attr']] = command[key]
 
-        try:
-            yield updateRecord(True, self.dir, "addresses", **kwargs)
-        except DirectoryError, e:
-            self.respondWithError(str(e))
-            return
+    #     try:
+    #         yield updateRecord(True, self.dir, "addresses", **kwargs)
+    #     except DirectoryError, e:
+    #         self.respondWithError(str(e))
+    #         return
 
-        self.respondWithRecordsOfTypes(self.dir, command, ["addresses"])
+    #     self.respondWithRecordsOfTypes(self.dir, command, ["addresses"])
 
 
-    def command_getAddressAttributes(self, command):
-        guid = command['GeneratedUID']
-        record = self.dir.recordWithGUID(guid)
-        if record is None:
-            self.respondWithError("Principal not found: %s" % (guid,))
-            return
-        recordDict = recordToDict(record)
-        self.respond(command, recordDict)
-        return succeed(None)
 
 
+    # @inlineCallbacks
+    # def command_setAddressAttributes(self, command):
+    #     kwargs = {}
+    #     for key, info in attrMap.iteritems():
+    #         if key in command:
+    #             kwargs[info['attr']] = command[key]
+    #     try:
+    #         yield updateRecord(False, self.dir, "addresses", **kwargs)
+    #     except DirectoryError, e:
+    #         self.respondWithError(str(e))
+    #         return
+
+    #     yield self.command_getAddressAttributes(command)
+
+
+
     @inlineCallbacks
-    def command_setAddressAttributes(self, command):
-        kwargs = {}
-        for key, info in attrMap.iteritems():
-            if key in command:
-                kwargs[info['attr']] = command[key]
-        try:
-            yield updateRecord(False, self.dir, "addresses", **kwargs)
-        except DirectoryError, e:
-            self.respondWithError(str(e))
-            return
+    def _delete(self, typeName, command):
+        uid = command['GeneratedUID']
+        yield self.dir.removeRecords([uid])
+        self.respondWithRecordsOfTypes(self.dir, command, [typeName])
 
-        yield self.command_getAddressAttributes(command)
 
+    def command_deleteLocation(self, command):
+        return self._delete("locations", command)
 
+
+    def command_deleteResource(self, command):
+        return self._delete("resources", command)
+
+
     def command_deleteAddress(self, command):
-        kwargs = {}
-        for key, info in attrMap.iteritems():
-            if key in command:
-                kwargs[info['attr']] = command[key]
-        try:
-            self.dir.destroyRecord("addresses", **kwargs)
-        except DirectoryError, e:
-            self.respondWithError(str(e))
-            return
-        self.respondWithRecordsOfTypes(self.dir, command, ["addresses"])
+        return self._delete("addresses", command)
 
 
     # Config
@@ -530,106 +581,144 @@
 
     # Proxies
 
-    @inlineCallbacks
     def command_listWriteProxies(self, command):
-        principal = principalForPrincipalID(command['Principal'], directory=self.dir)
-        if principal is None:
-            self.respondWithError("Principal not found: %s" % (command['Principal'],))
-            return
-        (yield self.respondWithProxies(self.dir, command, principal, "write"))
+        return self._listProxies(command, "write")
 
 
+    def command_listReadProxies(self, command):
+        return self._listProxies(command, "read")
+
     @inlineCallbacks
-    def command_addWriteProxy(self, command):
-        principal = principalForPrincipalID(command['Principal'],
-            directory=self.dir)
-        if principal is None:
+    def _listProxies(self, command, proxyType):
+        record = yield recordForPrincipalID(self.dir, command['Principal'])
+        if record is None:
             self.respondWithError("Principal not found: %s" % (command['Principal'],))
-            return
+            returnValue(None)
+        yield self.respondWithProxies(command, record, proxyType)
 
-        proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
-        if proxy is None:
-            self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
-            return
-        try:
-            (yield addProxy(self.root, self.dir, self.store, principal, "write", proxy))
-        except ProxyError, e:
-            self.respondWithError(str(e))
-            return
-        except ProxyWarning, e:
-            pass
-        (yield self.respondWithProxies(self.dir, command, principal, "write"))
 
+    def command_addReadProxy(self, command):
+        return self._addProxy(command, "read")
 
+
+    def command_addWriteProxy(self, command):
+        return self._addProxy(command, "write")
+
+
     @inlineCallbacks
-    def command_removeWriteProxy(self, command):
-        principal = principalForPrincipalID(command['Principal'], directory=self.dir)
-        if principal is None:
+    def _addProxy(self, command, proxyType):
+        record = yield recordForPrincipalID(self.dir, command['Principal'])
+        if record is None:
             self.respondWithError("Principal not found: %s" % (command['Principal'],))
-            return
-        proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
-        if proxy is None:
+            returnValue(None)
+
+        proxyRecord = yield recordForPrincipalID(self.dir, command['Proxy'])
+        if proxyRecord is None:
             self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
-            return
-        try:
-            (yield removeProxy(self.root, self.dir, self.store, principal, proxy, proxyTypes=("write",)))
-        except ProxyError, e:
-            self.respondWithError(str(e))
-            return
-        except ProxyWarning, e:
-            pass
-        (yield self.respondWithProxies(self.dir, command, principal, "write"))
+            returnValue(None)
 
+        txn = self.store.newTransaction()
+        yield addDelegate(txn, record, proxyRecord, (proxyType == "write"))
+        yield txn.commit()
+        yield self.respondWithProxies(command, record, proxyType)
 
-    @inlineCallbacks
-    def command_listReadProxies(self, command):
-        principal = principalForPrincipalID(command['Principal'], directory=self.dir)
-        if principal is None:
-            self.respondWithError("Principal not found: %s" % (command['Principal'],))
-            return
-        (yield self.respondWithProxies(self.dir, command, principal, "read"))
 
+    def command_removeReadProxy(self, command):
+        return self._removeProxy(command, "read")
 
-    @inlineCallbacks
-    def command_addReadProxy(self, command):
-        principal = principalForPrincipalID(command['Principal'], directory=self.dir)
-        if principal is None:
-            self.respondWithError("Principal not found: %s" % (command['Principal'],))
-            return
-        proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
-        if proxy is None:
-            self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
-            return
-        try:
-            (yield addProxy(self.root, self.dir, self.store, principal, "read", proxy))
-        except ProxyError, e:
-            self.respondWithError(str(e))
-            return
-        except ProxyWarning, e:
-            pass
-        (yield self.respondWithProxies(self.dir, command, principal, "read"))
 
+    def command_removeWriteProxy(self, command):
+        return self._removeProxy(command, "write")
 
+
     @inlineCallbacks
-    def command_removeReadProxy(self, command):
-        principal = principalForPrincipalID(command['Principal'], directory=self.dir)
-        if principal is None:
+    def _removeProxy(self, command, proxyType):
+        record = yield recordForPrincipalID(self.dir, command['Principal'])
+        if record is None:
             self.respondWithError("Principal not found: %s" % (command['Principal'],))
-            return
-        proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
-        if proxy is None:
+            returnValue(None)
+
+        proxyRecord = yield recordForPrincipalID(self.dir, command['Proxy'])
+        if proxyRecord is None:
             self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
-            return
-        try:
-            (yield removeProxy(self.root, self.dir, self.store, principal, proxy, proxyTypes=("read",)))
-        except ProxyError, e:
-            self.respondWithError(str(e))
-            return
-        except ProxyWarning, e:
-            pass
-        (yield self.respondWithProxies(self.dir, command, principal, "read"))
+            returnValue(None)
 
+        txn = self.store.newTransaction()
+        yield removeDelegate(txn, record, proxyRecord, (proxyType == "write"))
+        yield txn.commit()
+        yield self.respondWithProxies(command, record, proxyType)
 
+
+
+    # @inlineCallbacks
+    # def command_removeWriteProxy(self, command):
+    #     principal = principalForPrincipalID(command['Principal'], directory=self.dir)
+    #     if principal is None:
+    #         self.respondWithError("Principal not found: %s" % (command['Principal'],))
+    #         return
+    #     proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
+    #     if proxy is None:
+    #         self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
+    #         return
+    #     try:
+    #         (yield removeProxy(self.root, self.dir, self.store, principal, proxy, proxyTypes=("write",)))
+    #     except ProxyError, e:
+    #         self.respondWithError(str(e))
+    #         return
+    #     except ProxyWarning, e:
+    #         pass
+    #     (yield self.respondWithProxies(self.dir, command, principal, "write"))
+
+
+    # @inlineCallbacks
+    # def command_listReadProxies(self, command):
+    #     principal = principalForPrincipalID(command['Principal'], directory=self.dir)
+    #     if principal is None:
+    #         self.respondWithError("Principal not found: %s" % (command['Principal'],))
+    #         return
+    #     (yield self.respondWithProxies(self.dir, command, principal, "read"))
+
+
+    # @inlineCallbacks
+    # def command_addReadProxy(self, command):
+    #     principal = principalForPrincipalID(command['Principal'], directory=self.dir)
+    #     if principal is None:
+    #         self.respondWithError("Principal not found: %s" % (command['Principal'],))
+    #         return
+    #     proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
+    #     if proxy is None:
+    #         self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
+    #         return
+    #     try:
+    #         (yield addProxy(self.root, self.dir, self.store, principal, "read", proxy))
+    #     except ProxyError, e:
+    #         self.respondWithError(str(e))
+    #         return
+    #     except ProxyWarning, e:
+    #         pass
+    #     (yield self.respondWithProxies(self.dir, command, principal, "read"))
+
+
+    # @inlineCallbacks
+    # def command_removeReadProxy(self, command):
+    #     principal = principalForPrincipalID(command['Principal'], directory=self.dir)
+    #     if principal is None:
+    #         self.respondWithError("Principal not found: %s" % (command['Principal'],))
+    #         return
+    #     proxy = principalForPrincipalID(command['Proxy'], directory=self.dir)
+    #     if proxy is None:
+    #         self.respondWithError("Proxy not found: %s" % (command['Proxy'],))
+    #         return
+    #     try:
+    #         (yield removeProxy(self.root, self.dir, self.store, principal, proxy, proxyTypes=("read",)))
+    #     except ProxyError, e:
+    #         self.respondWithError(str(e))
+    #         return
+    #     except ProxyWarning, e:
+    #         pass
+    #     (yield self.respondWithProxies(self.dir, command, principal, "read"))
+
+
     @inlineCallbacks
     def command_purgeOldEvents(self, command):
         """
@@ -644,22 +733,22 @@
         cutoff.setDateOnly(False)
         cutoff.offsetDay(-retainDays)
         eventCount = (yield PurgeOldEventsService.purgeOldEvents(self.store, cutoff, DEFAULT_BATCH_SIZE))
-        self.respond(command, {'EventsRemoved' : eventCount, "RetainDays" : retainDays})
+        self.respond(command, {'EventsRemoved': eventCount, "RetainDays": retainDays})
 
 
     @inlineCallbacks
-    def respondWithProxies(self, directory, command, principal, proxyType):
+    def respondWithProxies(self, command, record, proxyType):
         proxies = []
-        subPrincipal = proxySubprincipal(principal, proxyType)
-        if subPrincipal is not None:
-            membersProperty = (yield subPrincipal.readProperty(davxml.GroupMemberSet, None))
-            if membersProperty.children:
-                for member in membersProperty.children:
-                    proxyPrincipal = principalForPrincipalID(str(member), directory=directory)
-                    proxies.append(proxyPrincipal.record.guid)
+        recordType = {
+            "read": DelegateRecordType.readDelegateGroup,
+            "write": DelegateRecordType.writeDelegateGroup,
+        }[proxyType]
+        proxyGroup = yield self.dir.recordWithShortName(recordType, record.uid)
+        for member in (yield proxyGroup.members()):
+            proxies.append(member.uid)
 
         self.respond(command, {
-            'Principal' : principal.record.guid, 'Proxies' : proxies
+            'Principal': record.uid, 'Proxies': proxies
         })
 
 
@@ -675,11 +764,11 @@
 
 
     def respond(self, command, result):
-        self.output.write(writePlistToString({'command' : command['command'], 'result' : result}))
+        self.output.write(writePlistToString({'command': command['command'], 'result': result}))
 
 
     def respondWithError(self, msg, status=1):
-        self.output.write(writePlistToString({'error' : msg, }))
+        self.output.write(writePlistToString({'error': msg, }))
 
 
 
@@ -690,8 +779,14 @@
             value = record.fields[record.service.fieldName.lookupByName(info['attr'])]
             if value is None:
                 continue
-            elif isinstance(value, str):
+            # For backwards compatibility, present fullName/RealName as single
+            # value even though twext.who now has it as multiValue
+            if key == "RealName":
+                value = value[0]
+            if isinstance(value, str):
                 value = value.decode("utf-8")
+            elif isinstance(value, NamedConstant):
+                value = value.name
             recordDict[key] = value
         except KeyError:
             pass
@@ -700,7 +795,7 @@
 
 
 def respondWithError(msg, status=1):
-    sys.stdout.write(writePlistToString({'error' : msg, }))
+    sys.stdout.write(writePlistToString({'error': msg, }))
 
 
 

Modified: CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/test/gateway/caldavd.plist
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/test/gateway/caldavd.plist	2014-03-22 02:56:09 UTC (rev 12991)
+++ CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/test/gateway/caldavd.plist	2014-03-24 19:36:48 UTC (rev 12992)
@@ -34,6 +34,14 @@
     <key>ServerHostName</key>
     <string></string> <!-- The hostname clients use when connecting -->
 
+    <!-- Enable Calendars -->
+    <key>EnableCalDAV</key>
+    <true/>
+
+    <!-- Enable AddressBooks -->
+    <key>EnableCardDAV</key>
+    <true/>
+
     <!-- HTTP port [0 = disable HTTP] -->
     <key>HTTPPort</key>
     <integer>8008</integer>
@@ -482,6 +490,31 @@
 
       <key>Services</key>
       <dict>
+
+        <key>APNS</key>
+        <dict>
+          <key>Enabled</key>
+          <false/>
+          <key>EnableStaggering</key>
+          <true/>
+          <key>StaggerSeconds</key>
+          <integer>5</integer>
+          <key>CalDAV</key>
+          <dict>
+            <key>CertificatePath</key>
+            <string>/example/calendar.cer</string>
+            <key>PrivateKeyPath</key>
+            <string>/example/calendar.pem</string>
+          </dict>
+          <key>CardDAV</key>
+          <dict>
+            <key>CertificatePath</key>
+            <string>/example/contacts.cer</string>
+            <key>PrivateKeyPath</key>
+            <string>/example/contacts.pem</string>
+          </dict>
+        </dict>
+
         <key>SimpleLineNotifier</key>
         <dict>
           <!-- Simple line notification service (for testing) -->
@@ -756,5 +789,12 @@
     </dict>
 
 
+    <key>Includes</key>
+    <array>
+        <string>%(WritablePlist)s</string>
+    </array>
+    <key>WritableConfigFile</key>
+    <string>%(WritablePlist)s</string>
+
   </dict>
 </plist>

Modified: CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/test/test_gateway.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/test/test_gateway.py	2014-03-22 02:56:09 UTC (rev 12991)
+++ CalendarServer/branches/users/sagen/move2who-4/calendarserver/tools/test/test_gateway.py	2014-03-24 19:36:48 UTC (rev 12992)
@@ -29,6 +29,7 @@
 import plistlib
 from twistedcaldav.memcacheclient import ClientFactory
 from twistedcaldav import memcacher
+from txdav.who.idirectory import AutoScheduleMode
 
 
 class RunCommandTestCase(StoreTestCase):
@@ -183,6 +184,12 @@
 
 class GatewayTestCase(RunCommandTestCase):
 
+    def _flush(self):
+        # Flush both XML directories
+        self.directory._directory.services[0].flush()
+        self.directory._directory.services[1].flush()
+
+
     @inlineCallbacks
     def test_getLocationAndResourceList(self):
         results = yield self.runCommand(command_getLocationAndResourceList)
@@ -198,14 +205,18 @@
     @inlineCallbacks
     def test_getLocationAttributes(self):
         yield self.runCommand(command_createLocation)
+
+        # Tell the resources services to flush its cache and re-read XML
+        self._flush()
+
         results = yield self.runCommand(command_getLocationAttributes)
-        self.assertEquals(results["result"]["Capacity"], "40")
-        self.assertEquals(results["result"]["Description"], "Test Description")
+        # self.assertEquals(results["result"]["Capacity"], "40")
+        # self.assertEquals(results["result"]["Description"], "Test Description")
         self.assertEquals(results["result"]["RecordName"], ["createdlocation01"])
         self.assertEquals(results["result"]["RealName"],
             "Created Location 01 %s %s" % (unichr(208), u"\ud83d\udca3"))
-        self.assertEquals(results["result"]["Comment"], "Test Comment")
-        self.assertEquals(results["result"]["AutoSchedule"], True)
+        # self.assertEquals(results["result"]["Comment"], "Test Comment")
+        self.assertEquals(results["result"]["AutoScheduleMode"], u"acceptIfFree")
         self.assertEquals(results["result"]["AutoAcceptGroup"], "E5A6142C-4189-4E9E-90B0-9CD0268B314B")
         self.assertEquals(set(results["result"]["ReadProxies"]), set(['user03', 'user04']))
         self.assertEquals(set(results["result"]["WriteProxies"]), set(['user05', 'user06']))
@@ -220,9 +231,13 @@
     @inlineCallbacks
     def test_getResourceAttributes(self):
         yield self.runCommand(command_createResource)
+
+        # Tell the resources services to flush its cache and re-read XML
+        self._flush()
+
         results = yield self.runCommand(command_getResourceAttributes)
-        self.assertEquals(results["result"]["Comment"], "Test Comment")
-        self.assertEquals(results["result"]["Type"], "Computer")
+        # self.assertEquals(results["result"]["Comment"], "Test Comment")
+        # self.assertEquals(results["result"]["Type"], "Computer")
         self.assertEquals(set(results["result"]["ReadProxies"]), set(['user03', 'user04']))
         self.assertEquals(set(results["result"]["WriteProxies"]), set(['user05', 'user06']))
 
@@ -234,17 +249,19 @@
         self.assertEquals(record, None)
         yield self.runCommand(command_createAddress)
 
-        # directory.flushCaches()
+        # Tell the resources services to flush its cache and re-read XML
+        self._flush()
 
         record = yield self.directory.recordWithUID("C701069D-9CA1-4925-A1A9-5CD94767B74B")
-        self.assertEquals(record.fullName.decode("utf-8"),
-            "Created Address 01 %s %s" % (unichr(208), u"\ud83d\udca3"))
+        self.assertEquals(
+            record.displayName,
+            "Created Address 01 %s %s" % (unichr(208), u"\ud83d\udca3")
+        )
 
-        self.assertNotEquals(record, None)
 
-        self.assertEquals(record.extras["abbreviatedName"], "Addr1")
-        self.assertEquals(record.extras["streetAddress"], "1 Infinite Loop\nCupertino, 95014\nCA")
-        self.assertEquals(record.extras["geo"], "geo:37.331,-122.030")
+        self.assertEquals(record.abbreviatedName, "Addr1")
+        self.assertEquals(record.streetAddress, "1 Infinite Loop\nCupertino, 95014\nCA")
+        self.assertEquals(record.geographicLocation, "geo:37.331,-122.030")
 
         results = yield self.runCommand(command_getAddressList)
         self.assertEquals(len(results["result"]), 1)
@@ -257,7 +274,7 @@
         results = yield self.runCommand(command_getAddressAttributes)
         self.assertEquals(results["result"]["RealName"], u'Updated Address')
         self.assertEquals(results["result"]["StreetAddress"], u'Updated Street Address')
-        self.assertEquals(results["result"]["Geo"], u'Updated Geo')
+        self.assertEquals(results["result"]["GeographicLocation"], u'Updated Geo')
 
         results = yield self.runCommand(command_deleteAddress)
 
@@ -272,13 +289,9 @@
         self.assertEquals(record, None)
         yield self.runCommand(command_createLocation)
 
-        # directory.flushCaches()
+        # Tell the resources services to flush its cache and re-read XML
+        self._flush()
 
-        # This appears to be necessary in order for record.autoSchedule to
-        # reflect the change prior to the directory record expiration
-        # augmentService = directory.serviceForRecordType(directory.recordType_locations).augmentService
-        # augmentService.refresh()
-
         record = yield self.directory.recordWithUID("836B1B66-2E9A-4F46-8B1C-3DD6772C20B2")
         self.assertEquals(record.fullNames[0],
             u"Created Location 01 %s %s" % (unichr(208), u"\ud83d\udca3"))
@@ -296,28 +309,24 @@
 
     @inlineCallbacks
     def test_setLocationAttributes(self):
-        directory = getDirectory()
 
         yield self.runCommand(command_createLocation)
         yield self.runCommand(command_setLocationAttributes)
-        directory.flushCaches()
 
-        # This appears to be necessary in order for record.autoSchedule to
-        # reflect the change
-        augmentService = directory.serviceForRecordType(directory.recordType_locations).augmentService
-        augmentService.refresh()
+        # Tell the resources services to flush its cache and re-read XML
+        self._flush()
 
-        record = directory.recordWithUID("836B1B66-2E9A-4F46-8B1C-3DD6772C20B2")
+        record = yield self.directory.recordWithUID("836B1B66-2E9A-4F46-8B1C-3DD6772C20B2")
 
-        self.assertEquals(record.extras["comment"], "Updated Test Comment")
-        self.assertEquals(record.extras["floor"], "Second")
-        self.assertEquals(record.extras["capacity"], "41")
-        self.assertEquals(record.extras["streetAddress"], "2 Infinite Loop\nCupertino, 95014\nCA")
-        self.assertEquals(record.autoSchedule, True)
+        # self.assertEquals(record.extras["comment"], "Updated Test Comment")
+        self.assertEquals(record.floor, "Second")
+        # self.assertEquals(record.extras["capacity"], "41")
+        self.assertEquals(record.streetAddress, "2 Infinite Loop\nCupertino, 95014\nCA")
+        self.assertEquals(record.autoScheduleMode, AutoScheduleMode.acceptIfFree)
         self.assertEquals(record.autoAcceptGroup, "F5A6142C-4189-4E9E-90B0-9CD0268B314B")
 
         results = yield self.runCommand(command_getLocationAttributes)
-        self.assertEquals(results["result"]["AutoSchedule"], True)
+        self.assertEquals(results["result"]["AutoScheduleMode"], "acceptIfFree")
         self.assertEquals(results["result"]["AutoAcceptGroup"], "F5A6142C-4189-4E9E-90B0-9CD0268B314B")
         self.assertEquals(set(results["result"]["ReadProxies"]), set(['user03']))
         self.assertEquals(set(results["result"]["WriteProxies"]), set(['user05', 'user06', 'user07']))
@@ -325,59 +334,62 @@
 
     @inlineCallbacks
     def test_destroyLocation(self):
-        directory = getDirectory()
 
-        record = directory.recordWithUID("location01")
+        record = yield self.directory.recordWithUID("location01")
         self.assertNotEquals(record, None)
 
         yield self.runCommand(command_deleteLocation)
 
-        directory.flushCaches()
-        record = directory.recordWithUID("location01")
+        # Tell the resources services to flush its cache and re-read XML
+        self._flush()
+
+        record = yield self.directory.recordWithUID("location01")
         self.assertEquals(record, None)
 
 
     @inlineCallbacks
     def test_createResource(self):
-        directory = getDirectory()
 
-        record = directory.recordWithUID("AF575A61-CFA6-49E1-A0F6-B5662C9D9801")
+        record = yield self.directory.recordWithUID("AF575A61-CFA6-49E1-A0F6-B5662C9D9801")
         self.assertEquals(record, None)
 
         yield self.runCommand(command_createResource)
 
-        directory.flushCaches()
-        record = directory.recordWithUID("AF575A61-CFA6-49E1-A0F6-B5662C9D9801")
+        # Tell the resources services to flush its cache and re-read XML
+        self._flush()
+
+        record = yield self.directory.recordWithUID("AF575A61-CFA6-49E1-A0F6-B5662C9D9801")
         self.assertNotEquals(record, None)
 
 
     @inlineCallbacks
     def test_setResourceAttributes(self):
-        directory = getDirectory()
 
         yield self.runCommand(command_createResource)
-        directory.flushCaches()
-        record = directory.recordWithUID("AF575A61-CFA6-49E1-A0F6-B5662C9D9801")
-        self.assertEquals(record.fullName, "Laptop 1")
+        record = yield self.directory.recordWithUID("AF575A61-CFA6-49E1-A0F6-B5662C9D9801")
+        self.assertEquals(record.displayName, "Laptop 1")
 
         yield self.runCommand(command_setResourceAttributes)
 
-        directory.flushCaches()
-        record = directory.recordWithUID("AF575A61-CFA6-49E1-A0F6-B5662C9D9801")
-        self.assertEquals(record.fullName, "Updated Laptop 1")
+        # Tell the resources services to flush its cache and re-read XML
+        self._flush()
 
+        record = yield self.directory.recordWithUID("AF575A61-CFA6-49E1-A0F6-B5662C9D9801")
+        self.assertEquals(record.displayName, "Updated Laptop 1")
 
+
     @inlineCallbacks
     def test_destroyResource(self):
-        directory = getDirectory()
 
-        record = directory.recordWithUID("resource01")
+        record = yield self.directory.recordWithUID("resource01")
         self.assertNotEquals(record, None)
 
         yield self.runCommand(command_deleteResource)
 
-        directory.flushCaches()
-        record = directory.recordWithUID("resource01")
+        # Tell the resources services to flush its cache and re-read XML
+        self._flush()
+
+        record = yield self.directory.recordWithUID("resource01")
         self.assertEquals(record, None)
 
 
@@ -408,9 +420,10 @@
         """
         Verify readConfig returns with only the writable keys
         """
-        results = yield self.runCommand(command_readConfig,
-            script="calendarserver_config")
-
+        results = yield self.runCommand(
+            command_readConfig,
+            script="calendarserver_config"
+        )
         self.assertEquals(results["result"]["RedirectHTTPToHTTPS"], False)
         self.assertEquals(results["result"]["EnableSearchAddressBook"], False)
         self.assertEquals(results["result"]["EnableCalDAV"], True)
@@ -430,8 +443,10 @@
         """
         Verify writeConfig updates the writable plist file only
         """
-        results = yield self.runCommand(command_writeConfig,
-            script="calendarserver_config")
+        results = yield self.runCommand(
+            command_writeConfig,
+            script="calendarserver_config"
+        )
 
         self.assertEquals(results["result"]["EnableCalDAV"], False)
         self.assertEquals(results["result"]["EnableCardDAV"], False)
@@ -453,9 +468,9 @@
         <key>command</key>
         <string>addReadProxy</string>
         <key>Principal</key>
-        <string>locations:location01</string>
+        <string>location01</string>
         <key>Proxy</key>
-        <string>users:user03</string>
+        <string>user03</string>
 </dict>
 </plist>
 """
@@ -467,9 +482,9 @@
         <key>command</key>
         <string>addWriteProxy</string>
         <key>Principal</key>
-        <string>locations:location01</string>
+        <string>location01</string>
         <key>Proxy</key>
-        <string>users:user01</string>
+        <string>user01</string>
 </dict>
 </plist>
 """
@@ -492,7 +507,7 @@
         </array>
         <key>StreetAddress</key>
         <string>1 Infinite Loop\nCupertino, 95014\nCA</string>
-        <key>Geo</key>
+        <key>GeographicLocation</key>
         <string>geo:37.331,-122.030</string>
 </dict>
 </plist>
@@ -505,10 +520,8 @@
 <dict>
         <key>command</key>
         <string>createLocation</string>
-        <!--
         <key>AutoScheduleMode</key>
-        <string></string>
-        -->
+        <string>acceptIfFree</string>
         <key>AutoAcceptGroup</key>
         <string>E5A6142C-4189-4E9E-90B0-9CD0268B314B</string>
         <key>GeneratedUID</key>
@@ -552,31 +565,33 @@
 <dict>
         <key>command</key>
         <string>createResource</string>
-        <key>AutoSchedule</key>
-        <true/>
+        <key>AutoScheduleMode</key>
+        <string>declineIfBusy</string>
         <key>GeneratedUID</key>
         <string>AF575A61-CFA6-49E1-A0F6-B5662C9D9801</string>
         <key>RealName</key>
         <string>Laptop 1</string>
+        <!--
         <key>Comment</key>
         <string>Test Comment</string>
         <key>Description</key>
         <string>Test Description</string>
         <key>Type</key>
         <string>Computer</string>
+        -->
         <key>RecordName</key>
         <array>
                 <string>laptop1</string>
         </array>
         <key>ReadProxies</key>
         <array>
-            <string>users:user03</string>
-            <string>users:user04</string>
+            <string>user03</string>
+            <string>user04</string>
         </array>
         <key>WriteProxies</key>
         <array>
-            <string>users:user05</string>
-            <string>users:user06</string>
+            <string>user05</string>
+            <string>user06</string>
         </array>
 </dict>
 </plist>
@@ -691,9 +706,9 @@
         <key>command</key>
         <string>removeReadProxy</string>
         <key>Principal</key>
-        <string>locations:location01</string>
+        <string>location01</string>
         <key>Proxy</key>
-        <string>users:user03</string>
+        <string>user03</string>
 </dict>
 </plist>
 """
@@ -705,9 +720,9 @@
         <key>command</key>
         <string>removeWriteProxy</string>
         <key>Principal</key>
-        <string>locations:location01</string>
+        <string>location01</string>
         <key>Proxy</key>
-        <string>users:user01</string>
+        <string>user01</string>
 </dict>
 </plist>
 """
@@ -736,19 +751,21 @@
         <string>Updated Test Description</string>
         <key>Floor</key>
         <string>Second</string>
+        <!--
         <key>Capacity</key>
         <string>41</string>
+        -->
         <key>StreetAddress</key>
         <string>2 Infinite Loop\nCupertino, 95014\nCA</string>
         <key>ReadProxies</key>
         <array>
-            <string>users:user03</string>
+            <string>user03</string>
         </array>
         <key>WriteProxies</key>
         <array>
-            <string>users:user05</string>
-            <string>users:user06</string>
-            <string>users:user07</string>
+            <string>user05</string>
+            <string>user06</string>
+            <string>user07</string>
         </array>
 </dict>
 </plist>
@@ -790,7 +807,7 @@
         <string>Updated Address</string>
         <key>StreetAddress</key>
         <string>Updated Street Address</string>
-        <key>Geo</key>
+        <key>GeographicLocation</key>
         <string>Updated Geo</string>
 
 </dict>
@@ -804,8 +821,8 @@
 <dict>
         <key>command</key>
         <string>setResourceAttributes</string>
-        <key>AutoSchedule</key>
-        <false/>
+        <key>AutoScheduleMode</key>
+        <string>acceptIfFree</string>
         <key>GeneratedUID</key>
         <string>AF575A61-CFA6-49E1-A0F6-B5662C9D9801</string>
         <key>RealName</key>

Modified: CalendarServer/branches/users/sagen/move2who-4/requirements/py_develop.txt
===================================================================
--- CalendarServer/branches/users/sagen/move2who-4/requirements/py_develop.txt	2014-03-22 02:56:09 UTC (rev 12991)
+++ CalendarServer/branches/users/sagen/move2who-4/requirements/py_develop.txt	2014-03-24 19:36:48 UTC (rev 12992)
@@ -5,6 +5,7 @@
 pyflakes
 docutils>=0.11
 mockldap>=0.1.4
+q
 
 -e svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVClientLibrary/trunk#egg=CalDAVClientLibrary
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140324/d9f76878/attachment-0001.html>


More information about the calendarserver-changes mailing list