<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[12849] CalendarServer/branches/users/sagen/move2who</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/12849">12849</a></dd>
<dt>Author</dt> <dd>sagen@apple.com</dd>
<dt>Date</dt> <dd>2014-03-07 14:20:50 -0800 (Fri, 07 Mar 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Allow single-process configurations (like Single and Utility) to bypass the client/server/amp business, and just use an augmented directory service directly.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertapcaldavpy">CalendarServer/branches/users/sagen/move2who/calendarserver/tap/caldav.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertaptesttest_utilpy">CalendarServer/branches/users/sagen/move2who/calendarserver/tap/test/test_util.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertaputilpy">CalendarServer/branches/users/sagen/move2who/calendarserver/tap/util.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertoolscalverifypy">CalendarServer/branches/users/sagen/move2who/calendarserver/tools/calverify.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertoolsprincipalspy">CalendarServer/branches/users/sagen/move2who/calendarserver/tools/principals.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertoolstesttest_principalspy">CalendarServer/branches/users/sagen/move2who/calendarserver/tools/test/test_principals.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertoolsutilpy">CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotwistedcaldavtestutilpy">CalendarServer/branches/users/sagen/move2who/twistedcaldav/test/util.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotwistedcaldavupgradepy">CalendarServer/branches/users/sagen/move2who/twistedcaldav/upgrade.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavcaldavdatastoretesttest_attachmentspy">CalendarServer/branches/users/sagen/move2who/txdav/caldav/datastore/test/test_attachments.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavcommondatastoresqlpy">CalendarServer/branches/users/sagen/move2who/txdav/common/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavdpsclientpy">CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavdpsserverpy">CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavwhoaugmentpy">CalendarServer/branches/users/sagen/move2who/txdav/who/augment.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavwhodelegatespy">CalendarServer/branches/users/sagen/move2who/txdav/who/delegates.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavwhogroupspy">CalendarServer/branches/users/sagen/move2who/txdav/who/groups.py</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavwhodirectorypy">CalendarServer/branches/users/sagen/move2who/txdav/who/directory.py</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServerbranchesuserssagenmove2whocalendarservertapcaldavpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tap/caldav.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -86,7 +86,7 @@
</span><span class="cx"> from txdav.common.datastore.work.revision_cleanup import (
</span><span class="cx"> scheduleFirstFindMinRevision
</span><span class="cx"> )
</span><del>-from txdav.dps.server import DirectoryProxyServiceMaker
</del><ins>+from txdav.dps.server import directoryFromConfig
</ins><span class="cx"> from txdav.dps.client import DirectoryService as DirectoryProxyClientService
</span><span class="cx"> from txdav.who.groups import GroupCacher as NewGroupCacher
</span><span class="cx">
</span><span class="lines">@@ -927,10 +927,10 @@
</span><span class="cx"> CalDAV and CardDAV requests.
</span><span class="cx"> """
</span><span class="cx"> pool, txnFactory = getDBPool(config)
</span><del>- store = storeFromConfig(config, txnFactory)
</del><ins>+ directory = DirectoryProxyClientService("FIXME")
+ store = storeFromConfig(config, txnFactory, directory)
</ins><span class="cx"> logObserver = AMPCommonAccessLoggingObserver()
</span><span class="cx"> result = self.requestProcessingService(options, store, logObserver)
</span><del>- directory = store.directoryService()
</del><span class="cx">
</span><span class="cx"> if pool is not None:
</span><span class="cx"> pool.setServiceParent(result)
</span><span class="lines">@@ -1011,7 +1011,7 @@
</span><span class="cx"> namespace=config.GroupCaching.MemcachedPool,
</span><span class="cx"> useExternalProxies=config.GroupCaching.UseExternalProxies,
</span><span class="cx"> )
</span><del>- newGroupCacher = NewGroupCacher(DirectoryProxyClientService(None))
</del><ins>+ newGroupCacher = NewGroupCacher(directory)
</ins><span class="cx"> else:
</span><span class="cx"> groupCacher = None
</span><span class="cx"> newGroupCacher = None
</span><span class="lines">@@ -1312,6 +1312,13 @@
</span><span class="cx"> if store is None:
</span><span class="cx"> raise StoreNotAvailable()
</span><span class="cx">
</span><ins>+ # 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))
+
</ins><span class="cx"> result = self.requestProcessingService(options, store, logObserver)
</span><span class="cx">
</span><span class="cx"> # Optionally set up push notifications
</span><span class="lines">@@ -1357,9 +1364,7 @@
</span><span class="cx"> namespace=config.GroupCaching.MemcachedPool,
</span><span class="cx"> useExternalProxies=config.GroupCaching.UseExternalProxies
</span><span class="cx"> )
</span><del>- newGroupCacher = NewGroupCacher(
- DirectoryProxyClientService(None)
- )
</del><ins>+ newGroupCacher = NewGroupCacher(directory)
</ins><span class="cx"> else:
</span><span class="cx"> groupCacher = None
</span><span class="cx"> newGroupCacher = None
</span><span class="lines">@@ -1393,13 +1398,6 @@
</span><span class="cx"> "manhole_tap could not be imported"
</span><span class="cx"> )
</span><span class="cx">
</span><del>- # Optionally enable Directory Proxy
- if config.DirectoryProxy.Enabled:
- dps = DirectoryProxyServiceMaker().makeService(
- None, store=store
- )
- dps.setServiceParent(result)
-
</del><span class="cx"> def decorateTransaction(txn):
</span><span class="cx"> txn._pushDistributor = pushDistributor
</span><span class="cx"> txn._rootResource = result.rootResource
</span><span class="lines">@@ -1445,7 +1443,7 @@
</span><span class="cx"> Popen(memcachedArgv)
</span><span class="cx">
</span><span class="cx"> return self.storageService(
</span><del>- slaveSvcCreator, logObserver, uid=uid, gid=gid
</del><ins>+ slaveSvcCreator, logObserver, uid=uid, gid=gid, directory=None
</ins><span class="cx"> )
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -1458,10 +1456,17 @@
</span><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> def toolServiceCreator(pool, store, ignored, storageService):
</span><ins>+ # 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))
</ins><span class="cx"> return config.UtilityServiceClass(store)
</span><span class="cx">
</span><span class="cx"> uid, gid = getSystemIDs(config.UserName, config.GroupName)
</span><del>- return self.storageService(toolServiceCreator, None, uid=uid, gid=gid)
</del><ins>+ return self.storageService(toolServiceCreator, None, uid=uid, gid=gid,
+ directory=None)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def makeService_Agent(self, options):
</span><span class="lines">@@ -1509,7 +1514,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def storageService(
</span><del>- self, createMainService, logObserver, uid=None, gid=None
</del><ins>+ self, createMainService, logObserver, uid=None, gid=None, directory=None
</ins><span class="cx"> ):
</span><span class="cx"> """
</span><span class="cx"> If necessary, create a service to be started used for storage; for
</span><span class="lines">@@ -1535,6 +1540,9 @@
</span><span class="cx"> running as root (also the gid to chown Attachments to).
</span><span class="cx"> @type gid: C{int}
</span><span class="cx">
</span><ins>+ @param directory: The directory service to use.
+ @type directory: L{IStoreDirectoryService} or None
+
</ins><span class="cx"> @return: the appropriate a service to start.
</span><span class="cx"> @rtype: L{IService}
</span><span class="cx"> """
</span><span class="lines">@@ -1549,7 +1557,7 @@
</span><span class="cx"> maxConnections=config.MaxDBConnectionsPerPool
</span><span class="cx"> )
</span><span class="cx"> cp.setServiceParent(ms)
</span><del>- store = storeFromConfig(config, cp.connection)
</del><ins>+ store = storeFromConfig(config, cp.connection, directory)
</ins><span class="cx">
</span><span class="cx"> pps = PreProcessingService(
</span><span class="cx"> createMainService, cp, store, logObserver, storageService
</span><span class="lines">@@ -1674,7 +1682,7 @@
</span><span class="cx"> "Unknown database type {}".format(config.DBType)
</span><span class="cx"> )
</span><span class="cx"> else:
</span><del>- store = storeFromConfig(config, None)
</del><ins>+ store = storeFromConfig(config, None, directory)
</ins><span class="cx"> return createMainService(None, store, logObserver, None)
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -1941,7 +1949,7 @@
</span><span class="cx"> namespace=config.GroupCaching.MemcachedPool,
</span><span class="cx"> useExternalProxies=config.GroupCaching.UseExternalProxies
</span><span class="cx"> )
</span><del>- newGroupCacher = NewGroupCacher(DirectoryProxyClientService(None))
</del><ins>+ newGroupCacher = NewGroupCacher(directory)
</ins><span class="cx"> else:
</span><span class="cx"> groupCacher = None
</span><span class="cx"> newGroupCacher = None
</span><span class="lines">@@ -1957,7 +1965,10 @@
</span><span class="cx">
</span><span class="cx"> return multi
</span><span class="cx">
</span><del>- ssvc = self.storageService(spawnerSvcCreator, None, uid, gid)
</del><ins>+ ssvc = self.storageService(
+ spawnerSvcCreator, None, uid, gid,
+ directory=DirectoryProxyClientService("FIXME")
+ )
</ins><span class="cx"> ssvc.setServiceParent(s)
</span><span class="cx"> return s
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whocalendarservertaptesttest_utilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tap/test/test_util.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -14,13 +14,14 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from calendarserver.tap.util import directoryFromConfig, MemoryLimitService, Stepper
</del><ins>+from calendarserver.tap.util import MemoryLimitService, Stepper
</ins><span class="cx"> from twistedcaldav.util import computeProcessCount
</span><span class="cx"> from twistedcaldav.test.util import TestCase
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.directory.augment import AugmentXMLDB
</span><span class="cx"> from twisted.internet.task import Clock
</span><span class="cx"> from twisted.internet.defer import succeed, inlineCallbacks
</span><ins>+from txdav.dps.server import directoryFromConfig
</ins><span class="cx">
</span><span class="cx"> class ProcessCountTestCase(TestCase):
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whocalendarservertaputilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tap/util.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -223,7 +223,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-def storeFromConfig(config, txnFactory, directoryService=None):
</del><ins>+def storeFromConfig(config, txnFactory, directoryService):
</ins><span class="cx"> """
</span><span class="cx"> Produce an L{IDataStore} from the given configuration, transaction factory,
</span><span class="cx"> and notifier factory.
</span><span class="lines">@@ -241,9 +241,6 @@
</span><span class="cx"> if config.EnableResponseCache and config.Memcached.Pools.Default.ClientEnabled:
</span><span class="cx"> notifierFactories["cache"] = CacheStoreNotifierFactory()
</span><span class="cx">
</span><del>- if directoryService is None:
- directoryService = directoryFromConfig(config)
-
</del><span class="cx"> quota = config.UserQuota
</span><span class="cx"> if quota == 0:
</span><span class="cx"> quota = None
</span><span class="lines">@@ -286,14 +283,11 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-def directoryFromConfig(config):
</del><ins>+def REMOVEMEdirectoryFromConfig(config):
</ins><span class="cx"> """
</span><span class="cx"> Create an L{AggregateDirectoryService} from the given configuration.
</span><span class="cx"> """
</span><span class="cx">
</span><del>- # MOVE2WHO
- return DirectoryProxyClientService("XYZZY")
-
</del><span class="cx"> #
</span><span class="cx"> # Setup the Augment Service
</span><span class="cx"> #
</span><span class="lines">@@ -470,7 +464,6 @@
</span><span class="cx"> directory = newStore.directoryService()
</span><span class="cx"> principalCollection = principalResourceClass("/principals/", directory)
</span><span class="cx">
</span><del>-
</del><span class="cx"> #
</span><span class="cx"> # Setup the ProxyDB Service
</span><span class="cx"> #
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whocalendarservertoolscalverifypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tools/calverify.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -431,7 +431,7 @@
</span><span class="cx"> configuration, creating one first if necessary.
</span><span class="cx"> """
</span><span class="cx"> if self._directory is None:
</span><del>- self._directory = getDirectory(self.config) #directoryFromConfig(self.config)
</del><ins>+ self._directory = getDirectory(self.config)
</ins><span class="cx"> return self._directory
</span><span class="cx">
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whocalendarservertoolsprincipalspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tools/principals.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -119,6 +119,7 @@
</span><span class="cx"> if self.function is not None:
</span><span class="cx"> yield self.function(self.store, *self.params)
</span><span class="cx">
</span><ins>+
</ins><span class="cx"> attrMap = {
</span><span class="cx"> 'GeneratedUID': {'attr': 'guid', },
</span><span class="cx"> 'RealName': {'attr': 'fullName', },
</span><span class="lines">@@ -142,7 +143,6 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><del>-@inlineCallbacks
</del><span class="cx"> def main():
</span><span class="cx"> try:
</span><span class="cx"> (optargs, args) = getopt(
</span><span class="lines">@@ -191,6 +191,10 @@
</span><span class="cx"> verbose = False
</span><span class="cx">
</span><span class="cx"> for opt, arg in optargs:
</span><ins>+
+ # Args come in as encoded bytes
+ arg = arg.decode("utf-8")
+
</ins><span class="cx"> if opt in ("-h", "--help"):
</span><span class="cx"> usage()
</span><span class="cx">
</span><span class="lines">@@ -234,20 +238,9 @@
</span><span class="cx"> proxyType = "write"
</span><span class="cx"> else:
</span><span class="cx"> raise AssertionError("Unknown proxy type")
</span><del>-
- try:
- yield recordForPrincipalID(arg, checkOnly=True)
- except ValueError, e:
- abort(e)
-
</del><span class="cx"> principalActions.append((action_addProxy, proxyType, arg))
</span><span class="cx">
</span><span class="cx"> elif opt in ("", "--remove-proxy"):
</span><del>- try:
- yield recordForPrincipalID(arg, checkOnly=True)
- except ValueError, e:
- abort(e)
-
</del><span class="cx"> principalActions.append((action_removeProxy, arg))
</span><span class="cx">
</span><span class="cx"> # elif opt in ("", "--set-auto-schedule"):
</span><span class="lines">@@ -359,21 +352,19 @@
</span><span class="cx"> params = (searchPrincipals,)
</span><span class="cx">
</span><span class="cx"> else:
</span><del>- #
- # Do a quick sanity check that arguments look like principal
- # identifiers.
- #
</del><span class="cx"> if not args:
</span><span class="cx"> usage("No principals specified.")
</span><span class="cx">
</span><del>- for arg in args:
- try:
- yield recordForPrincipalID(arg, checkOnly=True)
- except ValueError, e:
- abort(e)
</del><ins>+ # We don't have a directory yet
+ # for arg in args:
+ # try:
+ # yield recordForPrincipalID(arg, checkOnly=True)
+ # except ValueError, e:
+ # abort(e)
</ins><span class="cx">
</span><ins>+ unicodeArgs = [a.decode("utf-8") for a in args]
</ins><span class="cx"> function = runPrincipalActions
</span><del>- params = (args, principalActions)
</del><ins>+ params = (unicodeArgs, principalActions)
</ins><span class="cx">
</span><span class="cx"> PrincipalService.function = function
</span><span class="cx"> PrincipalService.params = params
</span><span class="lines">@@ -411,9 +402,7 @@
</span><span class="cx"> for principalID in principalIDs:
</span><span class="cx"> # Resolve the given principal IDs to records
</span><span class="cx"> try:
</span><del>- record = yield recordForPrincipalID(
- principalID, directory=directory
- )
</del><ins>+ record = yield recordForPrincipalID(directory, principalID)
</ins><span class="cx"> except ValueError:
</span><span class="cx"> record = None
</span><span class="cx">
</span><span class="lines">@@ -545,7 +534,7 @@
</span><span class="cx"> directory = store.directoryService()
</span><span class="cx"> readWrite = (proxyType == "write")
</span><span class="cx"> for proxyID in proxyIDs:
</span><del>- proxyRecord = yield recordForPrincipalID(proxyID, directory=directory)
</del><ins>+ proxyRecord = yield recordForPrincipalID(directory, proxyID)
</ins><span class="cx"> if proxyRecord is None:
</span><span class="cx"> print("Invalid principal ID: %s" % (proxyID,))
</span><span class="cx"> else:
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whocalendarservertoolstesttest_principalspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tools/test/test_principals.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -17,22 +17,23 @@
</span><span class="cx"> import os
</span><span class="cx"> import sys
</span><span class="cx">
</span><ins>+from calendarserver.tools.principals import (
+ parseCreationArgs, matchStrings,
+ updateRecord, principalForPrincipalID, getProxies, setProxies
+)
</ins><span class="cx"> from twext.python.filepath import CachingFilePath as FilePath
</span><span class="cx"> from twisted.internet import reactor
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, Deferred, returnValue
</span><del>-
</del><span class="cx"> from twistedcaldav.config import config
</span><ins>+from twistedcaldav.directory import calendaruserproxy
</ins><span class="cx"> from twistedcaldav.directory.directory import DirectoryError
</span><del>-from twistedcaldav.directory import calendaruserproxy
</del><ins>+from twistedcaldav.test.util import (
+ TestCase, CapturingProcessProtocol, ErrorOutput
+)
+from txdav.dps.server import directoryFromConfig
</ins><span class="cx">
</span><del>-from twistedcaldav.test.util import TestCase, CapturingProcessProtocol, \
- ErrorOutput
</del><span class="cx">
</span><del>-from calendarserver.tap.util import directoryFromConfig
-from calendarserver.tools.principals import (parseCreationArgs, matchStrings,
- updateRecord, principalForPrincipalID, getProxies, setProxies)
</del><span class="cx">
</span><del>-
</del><span class="cx"> class ManagePrincipalsTestCase(TestCase):
</span><span class="cx">
</span><span class="cx"> def setUp(self):
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whocalendarservertoolsutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -396,14 +396,8 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>-def recordForPrincipalID(principalID, checkOnly=False, directory=None):
</del><ins>+def recordForPrincipalID(directory, principalID, checkOnly=False):
</ins><span class="cx">
</span><del>- # 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
-
</del><span class="cx"> if principalID.startswith("/"):
</span><span class="cx"> segments = principalID.strip("/").split("/")
</span><span class="cx"> if (len(segments) == 3 and
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotwistedcaldavtestutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/twistedcaldav/test/util.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -50,11 +50,12 @@
</span><span class="cx"> from calendarserver.provision.root import RootResource
</span><span class="cx">
</span><span class="cx"> from twext.python.log import Logger
</span><del>-from txdav.caldav.datastore.test.util import buildCalendarStore
-from calendarserver.tap.util import getRootResource, directoryFromConfig
</del><ins>+from calendarserver.tap.util import getRootResource
</ins><span class="cx"> from txweb2.dav.test.util import SimpleRequest
</span><span class="cx"> from twistedcaldav.directory.util import transactionFromRequest
</span><span class="cx"> from twistedcaldav.directory.directory import DirectoryService
</span><ins>+from txdav.caldav.datastore.test.util import buildCalendarStore
+from txdav.dps.server import directoryFromConfig
</ins><span class="cx">
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotwistedcaldavupgradepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/twistedcaldav/upgrade.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx">
</span><span class="cx"> from twisted.protocols.amp import AMP, Command, String, Boolean
</span><span class="cx">
</span><del>-from calendarserver.tap.util import getRootResource, FakeRequest, directoryFromConfig
</del><ins>+from calendarserver.tap.util import getRootResource, FakeRequest
</ins><span class="cx"> from calendarserver.tools.util import getDirectory
</span><span class="cx">
</span><span class="cx"> from txdav.caldav.datastore.scheduling.imip.mailgateway import migrateTokensToStore
</span><span class="lines">@@ -1032,7 +1032,7 @@
</span><span class="cx"> def stepWithResult(self, result):
</span><span class="cx"> if self.doPostImport:
</span><span class="cx">
</span><del>- directory = directoryFromConfig(self.config)
</del><ins>+ directory = self.store.directoryService()
</ins><span class="cx">
</span><span class="cx"> # Load proxy assignments from XML if specified
</span><span class="cx"> if self.config.ProxyLoadFromFile:
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavcaldavdatastoretesttest_attachmentspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/caldav/datastore/test/test_attachments.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><del>-from calendarserver.tap.util import directoryFromConfig
</del><ins>+from txdav.dps.server import directoryFromConfig
</ins><span class="cx">
</span><span class="cx"> from pycalendar.datetime import DateTime
</span><span class="cx"> from pycalendar.value import Value
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavcommondatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/common/datastore/sql.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -211,6 +211,10 @@
</span><span class="cx"> return self._directoryService
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def setDirectoryService(self, directoryService):
+ self._directoryService = directoryService
+
+
</ins><span class="cx"> def callWithNewTransactions(self, callback):
</span><span class="cx"> """
</span><span class="cx"> Registers a method to be called whenever a new transaction is
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavdpsclientpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -38,6 +38,9 @@
</span><span class="cx"> MembersCommand, GroupsCommand, SetMembersCommand,
</span><span class="cx"> VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand
</span><span class="cx"> )
</span><ins>+from txdav.who.directory import (
+ CalendarDirectoryRecordMixin, CalendarDirectoryServiceMixin
+)
</ins><span class="cx"> import txdav.who.delegates
</span><span class="cx"> import txdav.who.idirectory
</span><span class="cx"> from txweb2.auth.digest import DigestedCredentials
</span><span class="lines">@@ -59,7 +62,7 @@
</span><span class="cx"> ## component.normalizeCalendarUserAddresses
</span><span class="cx">
</span><span class="cx"> @implementer(IDirectoryService, IStoreDirectoryService)
</span><del>-class DirectoryService(BaseDirectoryService):
</del><ins>+class DirectoryService(BaseDirectoryService, CalendarDirectoryServiceMixin):
</ins><span class="cx"> """
</span><span class="cx"> Client side of directory proxy
</span><span class="cx"> """
</span><span class="lines">@@ -83,16 +86,7 @@
</span><span class="cx"> def getGroups(self, guids=None):
</span><span class="cx"> return succeed(set())
</span><span class="cx">
</span><del>- # 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.
</del><span class="cx">
</span><del>- @param principalService: the principal service.
- @type principalService: L{DirectoryProvisioningResource}
- """
- self.principalCollection = principalCollection
-
</del><span class="cx"> guid = "1332A615-4D3A-41FE-B636-FBE25BFB982E"
</span><span class="cx">
</span><span class="cx"> # END MOVE2WHO
</span><span class="lines">@@ -293,8 +287,9 @@
</span><span class="cx"> return self.recordType.lookupByName(oldName[:-1])
</span><span class="cx">
</span><span class="cx">
</span><ins>+
</ins><span class="cx"> @implementer(ICalendarStoreDirectoryRecord)
</span><del>-class DirectoryRecord(BaseDirectoryRecord):
</del><ins>+class DirectoryRecord(BaseDirectoryRecord, CalendarDirectoryRecordMixin):
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><span class="lines">@@ -384,132 +379,8 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx">
</span><del>- @property
- def calendarUserAddresses(self):
- if not self.hasCalendars:
- return frozenset()
</del><span class="cx">
</span><del>- try:
- cuas = set(
- ["mailto:%s" % (emailAddress,)
- for emailAddress in self.emailAddresses]
- )
- except AttributeError:
- cuas = set()
</del><span class="cx">
</span><del>- 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
-
-
</del><span class="cx"> # For scheduling/freebusy
</span><span class="cx"> # FIXME: doesn't this need to happen in the DPS?
</span><span class="cx"> @inlineCallbacks
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavdpsserverpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -446,6 +446,89 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><ins>+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
+
+
</ins><span class="cx"> @implementer(IPlugin, service.IServiceMaker)
</span><span class="cx"> class DirectoryProxyServiceMaker(object):
</span><span class="cx">
</span><span class="lines">@@ -454,7 +537,7 @@
</span><span class="cx"> options = DirectoryProxyOptions
</span><span class="cx">
</span><span class="cx">
</span><del>- def makeService(self, options, store=None):
</del><ins>+ def makeService(self, options):
</ins><span class="cx"> """
</span><span class="cx"> Return a service
</span><span class="cx"> """
</span><span class="lines">@@ -465,82 +548,20 @@
</span><span class="cx"> else:
</span><span class="cx"> setproctitle("CalendarServer Directory Proxy Service")
</span><span class="cx">
</span><del>- directoryType = config.DirectoryProxy.DirectoryType
- args = config.DirectoryProxy.Arguments
- kwds = config.DirectoryProxy.Keywords
</del><ins>+ try:
+ print("XZZZY AAA")
+ directory = directoryFromConfig(config)
+ print("XZZZY BBB")
+ except Exception as e:
+ log.error("Failed to create directory service", error=e)
+ raise
</ins><span class="cx">
</span><del>- # FIXME: this needs to talk to its own separate database
- if store is None:
- pool, txnFactory = getDBPool(config)
- store = storeFromConfig(config, txnFactory)
</del><ins>+ log.info("Created directory service")
+ print("XZZZY CCCC")
</ins><span class="cx">
</span><del>- 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
</del><ins>+ return strPortsService(
+ "unix:{path}:mode=660".format(
+ path=config.DirectoryProxy.SocketPath
+ ),
+ DirectoryProxyAMPFactory(directory)
</ins><span class="cx"> )
</span><del>- #
- # 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))
</del></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavwhoaugmentpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/who/augment.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -23,6 +23,9 @@
</span><span class="cx"> from twext.who.directory import DirectoryRecord
</span><span class="cx"> from twext.who.directory import DirectoryService as BaseDirectoryService
</span><span class="cx"> from twext.who.util import ConstantsContainer
</span><ins>+from txdav.who.directory import (
+ CalendarDirectoryRecordMixin, CalendarDirectoryServiceMixin
+)
</ins><span class="cx"> from txdav.who.idirectory import AutoScheduleMode, FieldName
</span><span class="cx"> from txdav.who.idirectory import RecordType as CalRecordType
</span><span class="cx"> from txdav.who.delegates import RecordType as DelegateRecordType
</span><span class="lines">@@ -33,7 +36,7 @@
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span><span class="cx">
</span><del>-class AugmentedDirectoryRecord(DirectoryRecord):
</del><ins>+class AugmentedDirectoryRecord(DirectoryRecord, CalendarDirectoryRecordMixin):
</ins><span class="cx">
</span><span class="cx"> def __init__(self, service, baseRecord, augmentedFields):
</span><span class="cx"> DirectoryRecord.__init__(self, service, augmentedFields)
</span><span class="lines">@@ -64,7 +67,8 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @implementer(IDirectoryService)
</span><del>-class AugmentedDirectoryService(BaseDirectoryService):
</del><ins>+class AugmentedDirectoryService(BaseDirectoryService,
+ CalendarDirectoryServiceMixin):
</ins><span class="cx">
</span><span class="cx"> fieldName = ConstantsContainer((
</span><span class="cx"> BaseDirectoryService.fieldName,
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavwhodelegatespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/who/delegates.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -67,6 +67,7 @@
</span><span class="cx"> this record.
</span><span class="cx"> """
</span><span class="cx"> parentUID, proxyType = self.uid.split("#")
</span><ins>+
</ins><span class="cx"> txn = self.service._store.newTransaction()
</span><span class="cx">
</span><span class="cx"> if self.recordType in (
</span><span class="lines">@@ -103,7 +104,6 @@
</span><span class="cx"> @param memberRecords: The new members of the group
</span><span class="cx"> @type memberRecords: iterable of L{iDirectoryRecord}s
</span><span class="cx"> """
</span><del>-
</del><span class="cx"> if self.recordType not in (
</span><span class="cx"> RecordType.readDelegateGroup, RecordType.writeDelegateGroup
</span><span class="cx"> ):
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavwhodirectorypy"></a>
<div class="addfile"><h4>Added: CalendarServer/branches/users/sagen/move2who/txdav/who/directory.py (0 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,170 @@
</span><ins>+##
+# 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
</ins></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavwhogroupspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/who/groups.py (12848 => 12849)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -131,7 +131,6 @@
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def doWork(self):
</span><del>- print("XYZZY IN GRW doWork", )
</del><span class="cx"> # Delete all other work items for this group
</span><span class="cx"> yield Delete(
</span><span class="cx"> From=self.table, Where=(self.table.GROUP_GUID == self.groupGuid)
</span><span class="lines">@@ -142,7 +141,7 @@
</span><span class="cx">
</span><span class="cx"> try:
</span><span class="cx"> yield newGroupCacher.refreshGroup(
</span><del>- self.transaction, self.groupGuid
</del><ins>+ self.transaction, self.groupGuid.decode("utf-8")
</ins><span class="cx"> )
</span><span class="cx"> except Exception, e:
</span><span class="cx"> log.error(
</span><span class="lines">@@ -471,4 +470,6 @@
</span><span class="cx"> ).on(txn)
</span><span class="cx"> attendeeGroupUIDs = set([row[0] for row in rows])
</span><span class="cx">
</span><ins>+ # FIXME: is this a good place to clear out unreferenced groups?
+
</ins><span class="cx"> returnValue(delegatedUIDs.union(attendeeGroupUIDs))
</span></span></pre>
</div>
</div>
</body>
</html>