[CalendarServer-changes] [12849] CalendarServer/branches/users/sagen/move2who

source_changes at macosforge.org source_changes at macosforge.org
Fri Mar 7 14:20:50 PST 2014


Revision: 12849
          http://trac.calendarserver.org//changeset/12849
Author:   sagen at apple.com
Date:     2014-03-07 14:20:50 -0800 (Fri, 07 Mar 2014)
Log Message:
-----------
Allow single-process configurations (like Single and Utility) to bypass the client/server/amp business, and just use an augmented directory service directly.

Modified Paths:
--------------
    CalendarServer/branches/users/sagen/move2who/calendarserver/tap/caldav.py
    CalendarServer/branches/users/sagen/move2who/calendarserver/tap/test/test_util.py
    CalendarServer/branches/users/sagen/move2who/calendarserver/tap/util.py
    CalendarServer/branches/users/sagen/move2who/calendarserver/tools/calverify.py
    CalendarServer/branches/users/sagen/move2who/calendarserver/tools/principals.py
    CalendarServer/branches/users/sagen/move2who/calendarserver/tools/test/test_principals.py
    CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py
    CalendarServer/branches/users/sagen/move2who/twistedcaldav/test/util.py
    CalendarServer/branches/users/sagen/move2who/twistedcaldav/upgrade.py
    CalendarServer/branches/users/sagen/move2who/txdav/caldav/datastore/test/test_attachments.py
    CalendarServer/branches/users/sagen/move2who/txdav/common/datastore/sql.py
    CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py
    CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py
    CalendarServer/branches/users/sagen/move2who/txdav/who/augment.py
    CalendarServer/branches/users/sagen/move2who/txdav/who/delegates.py
    CalendarServer/branches/users/sagen/move2who/txdav/who/groups.py

Added Paths:
-----------
    CalendarServer/branches/users/sagen/move2who/txdav/who/directory.py

Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/calendarserver/tap/caldav.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tap/caldav.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -86,7 +86,7 @@
 from txdav.common.datastore.work.revision_cleanup import (
     scheduleFirstFindMinRevision
 )
-from txdav.dps.server import DirectoryProxyServiceMaker
+from txdav.dps.server import directoryFromConfig
 from txdav.dps.client import DirectoryService as DirectoryProxyClientService
 from txdav.who.groups import GroupCacher as NewGroupCacher
 
@@ -927,10 +927,10 @@
         CalDAV and CardDAV requests.
         """
         pool, txnFactory = getDBPool(config)
-        store = storeFromConfig(config, txnFactory)
+        directory = DirectoryProxyClientService("FIXME")
+        store = storeFromConfig(config, txnFactory, directory)
         logObserver = AMPCommonAccessLoggingObserver()
         result = self.requestProcessingService(options, store, logObserver)
-        directory = store.directoryService()
 
         if pool is not None:
             pool.setServiceParent(result)
@@ -1011,7 +1011,7 @@
                 namespace=config.GroupCaching.MemcachedPool,
                 useExternalProxies=config.GroupCaching.UseExternalProxies,
             )
-            newGroupCacher = NewGroupCacher(DirectoryProxyClientService(None))
+            newGroupCacher = NewGroupCacher(directory)
         else:
             groupCacher = None
             newGroupCacher = None
@@ -1312,6 +1312,13 @@
             if store is None:
                 raise StoreNotAvailable()
 
+            # Create a Directory Proxy "Server" service and hand it to the
+            # store.
+            # FIXME: right now the store passed *to* the directory is the
+            # calendar/contacts data store, but for a multi-server deployment
+            # it will need its own separate store.
+            store.setDirectoryService(directoryFromConfig(config, store=store))
+
             result = self.requestProcessingService(options, store, logObserver)
 
             # Optionally set up push notifications
@@ -1357,9 +1364,7 @@
                     namespace=config.GroupCaching.MemcachedPool,
                     useExternalProxies=config.GroupCaching.UseExternalProxies
                 )
-                newGroupCacher = NewGroupCacher(
-                    DirectoryProxyClientService(None)
-                )
+                newGroupCacher = NewGroupCacher(directory)
             else:
                 groupCacher = None
                 newGroupCacher = None
@@ -1393,13 +1398,6 @@
                         "manhole_tap could not be imported"
                     )
 
-            # Optionally enable Directory Proxy
-            if config.DirectoryProxy.Enabled:
-                dps = DirectoryProxyServiceMaker().makeService(
-                    None, store=store
-                )
-                dps.setServiceParent(result)
-
             def decorateTransaction(txn):
                 txn._pushDistributor = pushDistributor
                 txn._rootResource = result.rootResource
@@ -1445,7 +1443,7 @@
                 Popen(memcachedArgv)
 
         return self.storageService(
-            slaveSvcCreator, logObserver, uid=uid, gid=gid
+            slaveSvcCreator, logObserver, uid=uid, gid=gid, directory=None
         )
 
 
@@ -1458,10 +1456,17 @@
         """
 
         def toolServiceCreator(pool, store, ignored, storageService):
+            # Create a Directory Proxy "Server" service and hand it to the
+            # store
+            # FIXME: right now the store passed *to* the directory is the
+            # calendar/contacts data store, but for a multi-server deployment
+            # it will need its own separate store.
+            store.setDirectoryService(directoryFromConfig(config, store=store))
             return config.UtilityServiceClass(store)
 
         uid, gid = getSystemIDs(config.UserName, config.GroupName)
-        return self.storageService(toolServiceCreator, None, uid=uid, gid=gid)
+        return self.storageService(toolServiceCreator, None, uid=uid, gid=gid,
+                                   directory=None)
 
 
     def makeService_Agent(self, options):
@@ -1509,7 +1514,7 @@
 
 
     def storageService(
-        self, createMainService, logObserver, uid=None, gid=None
+        self, createMainService, logObserver, uid=None, gid=None, directory=None
     ):
         """
         If necessary, create a service to be started used for storage; for
@@ -1535,6 +1540,9 @@
             running as root (also the gid to chown Attachments to).
         @type gid: C{int}
 
+        @param directory: The directory service to use.
+        @type directory: L{IStoreDirectoryService} or None
+
         @return: the appropriate a service to start.
         @rtype: L{IService}
         """
@@ -1549,7 +1557,7 @@
                     maxConnections=config.MaxDBConnectionsPerPool
                 )
                 cp.setServiceParent(ms)
-                store = storeFromConfig(config, cp.connection)
+                store = storeFromConfig(config, cp.connection, directory)
 
                 pps = PreProcessingService(
                     createMainService, cp, store, logObserver, storageService
@@ -1674,7 +1682,7 @@
                     "Unknown database type {}".format(config.DBType)
                 )
         else:
-            store = storeFromConfig(config, None)
+            store = storeFromConfig(config, None, directory)
             return createMainService(None, store, logObserver, None)
 
 
@@ -1941,7 +1949,7 @@
                     namespace=config.GroupCaching.MemcachedPool,
                     useExternalProxies=config.GroupCaching.UseExternalProxies
                 )
-                newGroupCacher = NewGroupCacher(DirectoryProxyClientService(None))
+                newGroupCacher = NewGroupCacher(directory)
             else:
                 groupCacher = None
                 newGroupCacher = None
@@ -1957,7 +1965,10 @@
 
             return multi
 
-        ssvc = self.storageService(spawnerSvcCreator, None, uid, gid)
+        ssvc = self.storageService(
+            spawnerSvcCreator, None, uid, gid,
+            directory=DirectoryProxyClientService("FIXME")
+        )
         ssvc.setServiceParent(s)
         return s
 

Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tap/test/test_util.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/calendarserver/tap/test/test_util.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tap/test/test_util.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -14,13 +14,14 @@
 # limitations under the License.
 ##
 
-from calendarserver.tap.util import directoryFromConfig, MemoryLimitService, Stepper
+from calendarserver.tap.util import MemoryLimitService, Stepper
 from twistedcaldav.util import computeProcessCount
 from twistedcaldav.test.util import TestCase
 from twistedcaldav.config import config
 from twistedcaldav.directory.augment import AugmentXMLDB
 from twisted.internet.task import Clock
 from twisted.internet.defer import succeed, inlineCallbacks
+from txdav.dps.server import directoryFromConfig
 
 class ProcessCountTestCase(TestCase):
 

Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tap/util.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/calendarserver/tap/util.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tap/util.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -223,7 +223,7 @@
 
 
 
-def storeFromConfig(config, txnFactory, directoryService=None):
+def storeFromConfig(config, txnFactory, directoryService):
     """
     Produce an L{IDataStore} from the given configuration, transaction factory,
     and notifier factory.
@@ -241,9 +241,6 @@
     if config.EnableResponseCache and config.Memcached.Pools.Default.ClientEnabled:
         notifierFactories["cache"] = CacheStoreNotifierFactory()
 
-    if directoryService is None:
-        directoryService = directoryFromConfig(config)
-
     quota = config.UserQuota
     if quota == 0:
         quota = None
@@ -286,14 +283,11 @@
 
 
 
-def directoryFromConfig(config):
+def REMOVEMEdirectoryFromConfig(config):
     """
     Create an L{AggregateDirectoryService} from the given configuration.
     """
 
-    # MOVE2WHO
-    return DirectoryProxyClientService("XYZZY")
-
     #
     # Setup the Augment Service
     #
@@ -470,7 +464,6 @@
     directory = newStore.directoryService()
     principalCollection = principalResourceClass("/principals/", directory)
 
-
     #
     # Setup the ProxyDB Service
     #

Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tools/calverify.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/calendarserver/tools/calverify.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tools/calverify.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -431,7 +431,7 @@
         configuration, creating one first if necessary.
         """
         if self._directory is None:
-            self._directory = getDirectory(self.config) #directoryFromConfig(self.config)
+            self._directory = getDirectory(self.config)
         return self._directory
 
 

Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tools/principals.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/calendarserver/tools/principals.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tools/principals.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -119,6 +119,7 @@
         if self.function is not None:
             yield self.function(self.store, *self.params)
 
+
 attrMap = {
     'GeneratedUID': {'attr': 'guid', },
     'RealName': {'attr': 'fullName', },
@@ -142,7 +143,6 @@
 }
 
 
- at inlineCallbacks
 def main():
     try:
         (optargs, args) = getopt(
@@ -191,6 +191,10 @@
     verbose = False
 
     for opt, arg in optargs:
+
+        # Args come in as encoded bytes
+        arg = arg.decode("utf-8")
+
         if opt in ("-h", "--help"):
             usage()
 
@@ -234,20 +238,9 @@
                 proxyType = "write"
             else:
                 raise AssertionError("Unknown proxy type")
-
-            try:
-                yield recordForPrincipalID(arg, checkOnly=True)
-            except ValueError, e:
-                abort(e)
-
             principalActions.append((action_addProxy, proxyType, arg))
 
         elif opt in ("", "--remove-proxy"):
-            try:
-                yield recordForPrincipalID(arg, checkOnly=True)
-            except ValueError, e:
-                abort(e)
-
             principalActions.append((action_removeProxy, arg))
 
         # elif opt in ("", "--set-auto-schedule"):
@@ -359,21 +352,19 @@
         params = (searchPrincipals,)
 
     else:
-        #
-        # Do a quick sanity check that arguments look like principal
-        # identifiers.
-        #
         if not args:
             usage("No principals specified.")
 
-        for arg in args:
-            try:
-                yield recordForPrincipalID(arg, checkOnly=True)
-            except ValueError, e:
-                abort(e)
+        # We don't have a directory yet
+        # for arg in args:
+        #     try:
+        #         yield recordForPrincipalID(arg, checkOnly=True)
+        #     except ValueError, e:
+        #         abort(e)
 
+        unicodeArgs = [a.decode("utf-8") for a in args]
         function = runPrincipalActions
-        params = (args, principalActions)
+        params = (unicodeArgs, principalActions)
 
     PrincipalService.function = function
     PrincipalService.params = params
@@ -411,9 +402,7 @@
     for principalID in principalIDs:
         # Resolve the given principal IDs to records
         try:
-            record = yield recordForPrincipalID(
-                principalID, directory=directory
-            )
+            record = yield recordForPrincipalID(directory, principalID)
         except ValueError:
             record = None
 
@@ -545,7 +534,7 @@
     directory = store.directoryService()
     readWrite = (proxyType == "write")
     for proxyID in proxyIDs:
-        proxyRecord = yield recordForPrincipalID(proxyID, directory=directory)
+        proxyRecord = yield recordForPrincipalID(directory, proxyID)
         if proxyRecord is None:
             print("Invalid principal ID: %s" % (proxyID,))
         else:

Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tools/test/test_principals.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/calendarserver/tools/test/test_principals.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tools/test/test_principals.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -17,22 +17,23 @@
 import os
 import sys
 
+from calendarserver.tools.principals import (
+    parseCreationArgs, matchStrings,
+    updateRecord, principalForPrincipalID, getProxies, setProxies
+)
 from twext.python.filepath import CachingFilePath as FilePath
 from twisted.internet import reactor
 from twisted.internet.defer import inlineCallbacks, Deferred, returnValue
-
 from twistedcaldav.config import config
+from twistedcaldav.directory import calendaruserproxy
 from twistedcaldav.directory.directory import DirectoryError
-from twistedcaldav.directory import calendaruserproxy
+from twistedcaldav.test.util import (
+    TestCase, CapturingProcessProtocol, ErrorOutput
+)
+from txdav.dps.server import directoryFromConfig
 
-from twistedcaldav.test.util import TestCase, CapturingProcessProtocol, \
-    ErrorOutput
 
-from calendarserver.tap.util import directoryFromConfig
-from calendarserver.tools.principals import (parseCreationArgs, matchStrings,
-    updateRecord, principalForPrincipalID, getProxies, setProxies)
 
-
 class ManagePrincipalsTestCase(TestCase):
 
     def setUp(self):

Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -396,14 +396,8 @@
 
 
 @inlineCallbacks
-def recordForPrincipalID(principalID, checkOnly=False, directory=None):
+def recordForPrincipalID(directory, principalID, checkOnly=False):
 
-    # Allow a directory parameter to be passed in, but default to config.directory
-    # But config.directory isn't set right away, so only use it when we're doing more
-    # than checking.
-    if not checkOnly and not directory:
-        directory = config.directory
-
     if principalID.startswith("/"):
         segments = principalID.strip("/").split("/")
         if (len(segments) == 3 and

Modified: CalendarServer/branches/users/sagen/move2who/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/twistedcaldav/test/util.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/twistedcaldav/test/util.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -50,11 +50,12 @@
 from calendarserver.provision.root import RootResource
 
 from twext.python.log import Logger
-from txdav.caldav.datastore.test.util import buildCalendarStore
-from calendarserver.tap.util import getRootResource, directoryFromConfig
+from calendarserver.tap.util import getRootResource
 from txweb2.dav.test.util import SimpleRequest
 from twistedcaldav.directory.util import transactionFromRequest
 from twistedcaldav.directory.directory import DirectoryService
+from txdav.caldav.datastore.test.util import buildCalendarStore
+from txdav.dps.server import directoryFromConfig
 
 log = Logger()
 

Modified: CalendarServer/branches/users/sagen/move2who/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/twistedcaldav/upgrade.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/twistedcaldav/upgrade.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -60,7 +60,7 @@
 
 from twisted.protocols.amp import AMP, Command, String, Boolean
 
-from calendarserver.tap.util import getRootResource, FakeRequest, directoryFromConfig
+from calendarserver.tap.util import getRootResource, FakeRequest
 from calendarserver.tools.util import getDirectory
 
 from txdav.caldav.datastore.scheduling.imip.mailgateway import migrateTokensToStore
@@ -1032,7 +1032,7 @@
     def stepWithResult(self, result):
         if self.doPostImport:
 
-            directory = directoryFromConfig(self.config)
+            directory = self.store.directoryService()
 
             # Load proxy assignments from XML if specified
             if self.config.ProxyLoadFromFile:

Modified: CalendarServer/branches/users/sagen/move2who/txdav/caldav/datastore/test/test_attachments.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/txdav/caldav/datastore/test/test_attachments.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/txdav/caldav/datastore/test/test_attachments.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -14,7 +14,7 @@
 # limitations under the License.
 ##
 
-from calendarserver.tap.util import directoryFromConfig
+from txdav.dps.server import directoryFromConfig
 
 from pycalendar.datetime import DateTime
 from pycalendar.value import Value

Modified: CalendarServer/branches/users/sagen/move2who/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/txdav/common/datastore/sql.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/txdav/common/datastore/sql.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -211,6 +211,10 @@
         return self._directoryService
 
 
+    def setDirectoryService(self, directoryService):
+        self._directoryService = directoryService
+
+
     def callWithNewTransactions(self, callback):
         """
         Registers a method to be called whenever a new transaction is

Modified: CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -38,6 +38,9 @@
     MembersCommand, GroupsCommand, SetMembersCommand,
     VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand
 )
+from txdav.who.directory import (
+    CalendarDirectoryRecordMixin, CalendarDirectoryServiceMixin
+)
 import txdav.who.delegates
 import txdav.who.idirectory
 from txweb2.auth.digest import DigestedCredentials
@@ -59,7 +62,7 @@
 ##    component.normalizeCalendarUserAddresses
 
 @implementer(IDirectoryService, IStoreDirectoryService)
-class DirectoryService(BaseDirectoryService):
+class DirectoryService(BaseDirectoryService, CalendarDirectoryServiceMixin):
     """
     Client side of directory proxy
     """
@@ -83,16 +86,7 @@
     def getGroups(self, guids=None):
         return succeed(set())
 
-    # Must maintain the hack for a bit longer:
-    def setPrincipalCollection(self, principalCollection):
-        """
-        Set the principal service that the directory relies on for doing proxy tests.
 
-        @param principalService: the principal service.
-        @type principalService: L{DirectoryProvisioningResource}
-        """
-        self.principalCollection = principalCollection
-
     guid = "1332A615-4D3A-41FE-B636-FBE25BFB982E"
 
     # END MOVE2WHO
@@ -293,8 +287,9 @@
         return self.recordType.lookupByName(oldName[:-1])
 
 
+
 @implementer(ICalendarStoreDirectoryRecord)
-class DirectoryRecord(BaseDirectoryRecord):
+class DirectoryRecord(BaseDirectoryRecord, CalendarDirectoryRecordMixin):
 
 
     @inlineCallbacks
@@ -384,132 +379,8 @@
         )
 
 
-    @property
-    def calendarUserAddresses(self):
-        if not self.hasCalendars:
-            return frozenset()
 
-        try:
-            cuas = set(
-                ["mailto:%s" % (emailAddress,)
-                 for emailAddress in self.emailAddresses]
-            )
-        except AttributeError:
-            cuas = set()
 
-        try:
-            if self.guid:
-                if isinstance(self.guid, uuid.UUID):
-                    guid = unicode(self.guid).upper()
-                else:
-                    guid = self.guid
-                cuas.add("urn:uuid:{guid}".format(guid=guid))
-        except AttributeError:
-            # No guid
-            pass
-        cuas.add("/principals/__uids__/{uid}/".format(uid=self.uid))
-        for shortName in self.shortNames:
-            cuas.add("/principals/{rt}/{sn}/".format(
-                rt=self.recordType.name + "s", sn=shortName)
-            )
-        return frozenset(cuas)
-
-
-    def getCUType(self):
-        # Mapping from directory record.recordType to RFC2445 CUTYPE values
-        self._cuTypes = {
-            self.service.recordType.user: 'INDIVIDUAL',
-            self.service.recordType.group: 'GROUP',
-            self.service.recordType.resource: 'RESOURCE',
-            self.service.recordType.location: 'ROOM',
-        }
-
-        return self._cuTypes.get(self.recordType, "UNKNOWN")
-
-
-    @property
-    def displayName(self):
-        return self.fullNames[0]
-
-
-    def cacheToken(self):
-        """
-        Generate a token that can be uniquely used to identify the state of this record for use
-        in a cache.
-        """
-        return hash((
-            self.__class__.__name__,
-            self.service.realmName,
-            self.recordType.name,
-            self.shortNames,
-            self.guid,
-            self.hasCalendars,
-        ))
-
-
-    def canonicalCalendarUserAddress(self):
-        """
-            Return a CUA for this record, preferring in this order:
-            urn:uuid: form
-            mailto: form
-            first in calendarUserAddresses list
-        """
-
-        cua = ""
-        for candidate in self.calendarUserAddresses:
-            # Pick the first one, but urn:uuid: and mailto: can override
-            if not cua:
-                cua = candidate
-            # But always immediately choose the urn:uuid: form
-            if candidate.startswith("urn:uuid:"):
-                cua = candidate
-                break
-            # Prefer mailto: if no urn:uuid:
-            elif candidate.startswith("mailto:"):
-                cua = candidate
-        return cua
-
-
-    def enabledAsOrganizer(self):
-        # MOVE2WHO FIXME TO LOOK AT CONFIG
-        if self.recordType == self.service.recordType.user:
-            return True
-        elif self.recordType == DirectoryService.recordType_groups:
-            return False  # config.Scheduling.Options.AllowGroupAsOrganizer
-        elif self.recordType == DirectoryService.recordType_locations:
-            return False  # config.Scheduling.Options.AllowLocationAsOrganizer
-        elif self.recordType == DirectoryService.recordType_resources:
-            return False  # config.Scheduling.Options.AllowResourceAsOrganizer
-        else:
-            return False
-
-
-    #MOVE2WHO
-    def thisServer(self):
-        return True
-
-
-    def isLoginEnabled(self):
-        return self.loginAllowed
-
-
-    #MOVE2WHO
-    def calendarsEnabled(self):
-        # In the old world, this *also* looked at config:
-        # return config.EnableCalDAV and self.enabledForCalendaring
-        return self.hasCalendars
-
-
-    def getAutoScheduleMode(self, organizer):
-        # MOVE2WHO Fix this to take organizer into account:
-        return self.autoScheduleMode
-
-
-    def canAutoSchedule(self, organizer=None):
-        # MOVE2WHO Fix this:
-        return True
-
-
     # For scheduling/freebusy
     # FIXME: doesn't this need to happen in the DPS?
     @inlineCallbacks

Modified: CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -446,6 +446,89 @@
 
 
 
+def directoryFromConfig(config, store=None):
+    """
+    Return a directory service based on the config
+    """
+    directoryType = config.DirectoryProxy.DirectoryType
+    args = config.DirectoryProxy.Arguments
+    kwds = config.DirectoryProxy.Keywords
+
+    # FIXME: this needs to talk to its own separate database
+    pool, txnFactory = getDBPool(config)
+    if store is None:
+        store = storeFromConfig(config, txnFactory, None)
+
+    if directoryType == "OD":
+        from twext.who.opendirectory import DirectoryService as ODDirectoryService
+        primaryDirectory = ODDirectoryService(*args, **kwds)
+
+    elif directoryType == "LDAP":
+        authDN = kwds.pop("authDN", "")
+        password = kwds.pop("password", "")
+        if authDN and password:
+            creds = UsernamePassword(authDN, password)
+        else:
+            creds = None
+        kwds["credentials"] = creds
+        debug = kwds.pop("debug", "")
+        primaryDirectory = LDAPDirectoryService(
+            *args, _debug=debug, **kwds
+        )
+
+    elif directoryType == "XML":
+        path = kwds.pop("path", "")
+        if not path or not os.path.exists(path):
+            log.error("Path not found for XML directory: {p}", p=path)
+        fp = FilePath(path)
+        primaryDirectory = XMLDirectoryService(fp, *args, **kwds)
+
+    else:
+        log.error("Invalid DirectoryType: {dt}", dt=directoryType)
+
+    #
+    # Setup the Augment Service
+    #
+    if config.AugmentService.type:
+        augmentClass = namedClass(config.AugmentService.type)
+        log.info(
+            "Configuring augment service of type: {augmentClass}",
+            augmentClass=augmentClass
+        )
+        try:
+            augmentService = augmentClass(**config.AugmentService.params)
+        except IOError:
+            log.error("Could not start augment service")
+            raise
+    else:
+        augmentService = None
+
+    delegateDirectory = DelegateDirectoryService(
+        primaryDirectory.realmName,
+        store
+    )
+
+    aggregateDirectory = AggregateDirectoryService(
+        primaryDirectory.realmName,
+        (primaryDirectory, delegateDirectory)
+    )
+    try:
+        augmented = AugmentedDirectoryService(
+            aggregateDirectory, store, augmentService
+        )
+
+        # The delegate directory needs a way to look up user/group records
+        # so hand it a reference to the augmented directory.
+        # FIXME: is there a better pattern to use here?
+        delegateDirectory.setMasterDirectory(augmented)
+
+    except Exception as e:
+        log.error("Could not create directory service", error=e)
+        raise
+
+    return augmented
+
+
 @implementer(IPlugin, service.IServiceMaker)
 class DirectoryProxyServiceMaker(object):
 
@@ -454,7 +537,7 @@
     options = DirectoryProxyOptions
 
 
-    def makeService(self, options, store=None):
+    def makeService(self, options):
         """
         Return a service
         """
@@ -465,82 +548,20 @@
         else:
             setproctitle("CalendarServer Directory Proxy Service")
 
-        directoryType = config.DirectoryProxy.DirectoryType
-        args = config.DirectoryProxy.Arguments
-        kwds = config.DirectoryProxy.Keywords
+        try:
+            print("XZZZY AAA")
+            directory = directoryFromConfig(config)
+            print("XZZZY BBB")
+        except Exception as e:
+            log.error("Failed to create directory service", error=e)
+            raise
 
-        # FIXME: this needs to talk to its own separate database
-        if store is None:
-            pool, txnFactory = getDBPool(config)
-            store = storeFromConfig(config, txnFactory)
+        log.info("Created directory service")
+        print("XZZZY CCCC")
 
-        if directoryType == "OD":
-            from twext.who.opendirectory import DirectoryService as ODDirectoryService
-            primaryDirectory = ODDirectoryService(*args, **kwds)
-
-        elif directoryType == "LDAP":
-            authDN = kwds.pop("authDN", "")
-            password = kwds.pop("password", "")
-            if authDN and password:
-                creds = UsernamePassword(authDN, password)
-            else:
-                creds = None
-            kwds["credentials"] = creds
-            debug = kwds.pop("debug", "")
-            primaryDirectory = LDAPDirectoryService(
-                *args, _debug=debug, **kwds
-            )
-
-        elif directoryType == "XML":
-            path = kwds.pop("path", "")
-            if not path or not os.path.exists(path):
-                log.error("Path not found for XML directory: {p}", p=path)
-            fp = FilePath(path)
-            primaryDirectory = XMLDirectoryService(fp, *args, **kwds)
-
-        else:
-            log.error("Invalid DirectoryType: {dt}", dt=directoryType)
-
-        desc = "unix:{path}:mode=660".format(
-            path=config.DirectoryProxy.SocketPath
+        return strPortsService(
+            "unix:{path}:mode=660".format(
+                path=config.DirectoryProxy.SocketPath
+            ),
+            DirectoryProxyAMPFactory(directory)
         )
-        #
-        # Setup the Augment Service
-        #
-        if config.AugmentService.type:
-            augmentClass = namedClass(config.AugmentService.type)
-            log.info(
-                "Configuring augment service of type: {augmentClass}",
-                augmentClass=augmentClass
-            )
-            try:
-                augmentService = augmentClass(**config.AugmentService.params)
-            except IOError:
-                log.error("Could not start augment service")
-                raise
-        else:
-            augmentService = None
-
-        delegateDirectory = DelegateDirectoryService(
-            primaryDirectory.realmName,
-            store
-        )
-
-        aggregateDirectory = AggregateDirectoryService(
-            primaryDirectory.realmName,
-            (primaryDirectory, delegateDirectory)
-        )
-        try:
-            augmented = AugmentedDirectoryService(
-                aggregateDirectory, store, augmentService
-            )
-
-            # The delegate directory needs a way to look up user/group records
-            # so hand it a reference to the augmented directory.
-            # FIXME: is there a better pattern to use here?
-            delegateDirectory.setMasterDirectory(augmented)
-
-        except Exception as e:
-            log.error("Could not create directory service", error=e)
-            raise
-        return strPortsService(desc, DirectoryProxyAMPFactory(augmented))

Modified: CalendarServer/branches/users/sagen/move2who/txdav/who/augment.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/txdav/who/augment.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/txdav/who/augment.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -23,6 +23,9 @@
 from twext.who.directory import DirectoryRecord
 from twext.who.directory import DirectoryService as BaseDirectoryService
 from twext.who.util import ConstantsContainer
+from txdav.who.directory import (
+    CalendarDirectoryRecordMixin, CalendarDirectoryServiceMixin
+)
 from txdav.who.idirectory import AutoScheduleMode, FieldName
 from txdav.who.idirectory import RecordType as CalRecordType
 from txdav.who.delegates import RecordType as DelegateRecordType
@@ -33,7 +36,7 @@
 log = Logger()
 
 
-class AugmentedDirectoryRecord(DirectoryRecord):
+class AugmentedDirectoryRecord(DirectoryRecord, CalendarDirectoryRecordMixin):
 
     def __init__(self, service, baseRecord, augmentedFields):
         DirectoryRecord.__init__(self, service, augmentedFields)
@@ -64,7 +67,8 @@
 
 
 @implementer(IDirectoryService)
-class AugmentedDirectoryService(BaseDirectoryService):
+class AugmentedDirectoryService(BaseDirectoryService,
+                                CalendarDirectoryServiceMixin):
 
     fieldName = ConstantsContainer((
         BaseDirectoryService.fieldName,

Modified: CalendarServer/branches/users/sagen/move2who/txdav/who/delegates.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/txdav/who/delegates.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/txdav/who/delegates.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -67,6 +67,7 @@
         this record.
         """
         parentUID, proxyType = self.uid.split("#")
+
         txn = self.service._store.newTransaction()
 
         if self.recordType in (
@@ -103,7 +104,6 @@
         @param memberRecords: The new members of the group
         @type memberRecords: iterable of L{iDirectoryRecord}s
         """
-
         if self.recordType not in (
             RecordType.readDelegateGroup, RecordType.writeDelegateGroup
         ):

Added: CalendarServer/branches/users/sagen/move2who/txdav/who/directory.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/txdav/who/directory.py	                        (rev 0)
+++ CalendarServer/branches/users/sagen/move2who/txdav/who/directory.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -0,0 +1,170 @@
+##
+# Copyright (c) 2006-2014 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+"""
+Calendar/Contacts specific methods for DirectoryRecord
+"""
+
+
+import uuid
+
+
+__all__ = [
+    "CalendarDirectoryRecordMixin",
+    "CalendarDirectoryServiceMixin",
+]
+
+
+class CalendarDirectoryServiceMixin(object):
+
+    # Must maintain the hack for a bit longer:
+    def setPrincipalCollection(self, principalCollection):
+        """
+        Set the principal service that the directory relies on for doing proxy tests.
+
+        @param principalService: the principal service.
+        @type principalService: L{DirectoryProvisioningResource}
+        """
+        self.principalCollection = principalCollection
+
+
+class CalendarDirectoryRecordMixin(object):
+
+
+    @property
+    def calendarUserAddresses(self):
+        if not self.hasCalendars:
+            return frozenset()
+
+        try:
+            cuas = set(
+                ["mailto:%s" % (emailAddress,)
+                 for emailAddress in self.emailAddresses]
+            )
+        except AttributeError:
+            cuas = set()
+
+        try:
+            if self.guid:
+                if isinstance(self.guid, uuid.UUID):
+                    guid = unicode(self.guid).upper()
+                else:
+                    guid = self.guid
+                cuas.add("urn:uuid:{guid}".format(guid=guid))
+        except AttributeError:
+            # No guid
+            pass
+        cuas.add("/principals/__uids__/{uid}/".format(uid=self.uid))
+        for shortName in self.shortNames:
+            cuas.add("/principals/{rt}/{sn}/".format(
+                rt=self.recordType.name + "s", sn=shortName)
+            )
+        return frozenset(cuas)
+
+
+    def getCUType(self):
+        # Mapping from directory record.recordType to RFC2445 CUTYPE values
+        self._cuTypes = {
+            self.service.recordType.user: 'INDIVIDUAL',
+            self.service.recordType.group: 'GROUP',
+            self.service.recordType.resource: 'RESOURCE',
+            self.service.recordType.location: 'ROOM',
+        }
+
+        return self._cuTypes.get(self.recordType, "UNKNOWN")
+
+
+    @property
+    def displayName(self):
+        return self.fullNames[0]
+
+
+    def cacheToken(self):
+        """
+        Generate a token that can be uniquely used to identify the state of this record for use
+        in a cache.
+        """
+        return hash((
+            self.__class__.__name__,
+            self.service.realmName,
+            self.recordType.name,
+            self.shortNames,
+            self.guid,
+            self.hasCalendars,
+        ))
+
+
+    def canonicalCalendarUserAddress(self):
+        """
+            Return a CUA for this record, preferring in this order:
+            urn:uuid: form
+            mailto: form
+            first in calendarUserAddresses list
+        """
+
+        cua = ""
+        for candidate in self.calendarUserAddresses:
+            # Pick the first one, but urn:uuid: and mailto: can override
+            if not cua:
+                cua = candidate
+            # But always immediately choose the urn:uuid: form
+            if candidate.startswith("urn:uuid:"):
+                cua = candidate
+                break
+            # Prefer mailto: if no urn:uuid:
+            elif candidate.startswith("mailto:"):
+                cua = candidate
+        return cua
+
+
+    def enabledAsOrganizer(self):
+        # MOVE2WHO FIXME TO LOOK AT CONFIG
+        if self.recordType == self.service.recordType.user:
+            return True
+        elif self.recordType == self.service.recordType.group:
+            return False  # config.Scheduling.Options.AllowGroupAsOrganizer
+        elif self.recordType == self.service.recordType.location:
+            return False  # config.Scheduling.Options.AllowLocationAsOrganizer
+        elif self.recordType == self.service.recordType.resource:
+            return False  # config.Scheduling.Options.AllowResourceAsOrganizer
+        else:
+            return False
+
+
+    #MOVE2WHO
+    def thisServer(self):
+        return True
+
+
+    def isLoginEnabled(self):
+        return self.loginAllowed
+
+
+    #MOVE2WHO
+    def calendarsEnabled(self):
+        # In the old world, this *also* looked at config:
+        # return config.EnableCalDAV and self.enabledForCalendaring
+        return self.hasCalendars
+
+
+    def getAutoScheduleMode(self, organizer):
+        # MOVE2WHO Fix this to take organizer into account:
+        return self.autoScheduleMode
+
+
+    def canAutoSchedule(self, organizer=None):
+        # MOVE2WHO Fix this:
+        return True

Modified: CalendarServer/branches/users/sagen/move2who/txdav/who/groups.py
===================================================================
--- CalendarServer/branches/users/sagen/move2who/txdav/who/groups.py	2014-03-07 21:46:24 UTC (rev 12848)
+++ CalendarServer/branches/users/sagen/move2who/txdav/who/groups.py	2014-03-07 22:20:50 UTC (rev 12849)
@@ -131,7 +131,6 @@
 
     @inlineCallbacks
     def doWork(self):
-        print("XYZZY IN GRW doWork", )
         # Delete all other work items for this group
         yield Delete(
             From=self.table, Where=(self.table.GROUP_GUID == self.groupGuid)
@@ -142,7 +141,7 @@
 
             try:
                 yield newGroupCacher.refreshGroup(
-                    self.transaction, self.groupGuid
+                    self.transaction, self.groupGuid.decode("utf-8")
                 )
             except Exception, e:
                 log.error(
@@ -471,4 +470,6 @@
             ).on(txn)
             attendeeGroupUIDs = set([row[0] for row in rows])
 
+        # FIXME: is this a good place to clear out unreferenced groups?
+
         returnValue(delegatedUIDs.union(attendeeGroupUIDs))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140307/3a2f77d6/attachment-0001.html>


More information about the calendarserver-changes mailing list