<!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>[12835] 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/12835">12835</a></dd>
<dt>Author</dt> <dd>sagen@apple.com</dd>
<dt>Date</dt> <dd>2014-03-06 17:22:21 -0800 (Thu, 06 Mar 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Halfway through rewrite of calendarserver_manage_principals. Added recordsMatchingTokens()</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertapcaldavpy">CalendarServer/branches/users/sagen/move2who/calendarserver/tap/caldav.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertoolsprincipalspy">CalendarServer/branches/users/sagen/move2who/calendarserver/tools/principals.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whocalendarservertoolsutilpy">CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavdpsclientpy">CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavdpscommandspy">CalendarServer/branches/users/sagen/move2who/txdav/dps/commands.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavdpsserverpy">CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2whotxdavdpstesttest_clientpy">CalendarServer/branches/users/sagen/move2who/txdav/dps/test/test_client.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 (12834 => 12835)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who/calendarserver/tap/caldav.py        2014-03-06 23:06:36 UTC (rev 12834)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tap/caldav.py        2014-03-07 01:22:21 UTC (rev 12835)
</span><span class="lines">@@ -549,8 +549,8 @@
</span><span class="cx"> self.monitor.addProcessObject(process, PARENT_ENVIRONMENT)
</span><span class="cx">
</span><span class="cx"> if (
</span><del>- config.DirectoryProxy.Enabled and
- config.DirectoryProxy.SocketPath != ""
</del><ins>+ config.DirectoryProxy.Enabled and
+ config.DirectoryProxy.SocketPath != ""
</ins><span class="cx"> ):
</span><span class="cx"> log.info("Adding directory proxy service")
</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 (12834 => 12835)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who/calendarserver/tools/principals.py        2014-03-06 23:06:36 UTC (rev 12834)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tools/principals.py        2014-03-07 01:22:21 UTC (rev 12835)
</span><span class="lines">@@ -26,17 +26,16 @@
</span><span class="cx"> from twisted.internet import reactor
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, returnValue, succeed
</span><span class="cx"> from txdav.xml import element as davxml
</span><ins>+from txdav.who.delegates import addDelegate, removeDelegate
</ins><span class="cx">
</span><del>-from txdav.xml.base import decodeXMLName, encodeXMLName
</del><span class="cx">
</span><span class="cx"> from twistedcaldav.config import config
</span><del>-from twistedcaldav.directory.directory import UnknownRecordTypeError, DirectoryError
</del><ins>+from twistedcaldav.directory.directory import UnknownRecordTypeError
</ins><span class="cx"> from txdav.who.groups import schedulePolledGroupCachingUpdate
</span><span class="cx">
</span><span class="cx"> from calendarserver.tools.util import (
</span><del>- booleanArgument, proxySubprincipal, action_addProxyPrincipal,
- principalForPrincipalID, prettyPrincipal, ProxyError,
- action_removeProxyPrincipal
</del><ins>+ booleanArgument, proxySubprincipal,
+ recordForPrincipalID, prettyPrincipal, prettyRecord, ProxyError
</ins><span class="cx"> )
</span><span class="cx"> from twistedcaldav.directory.augment import allowedAutoScheduleModes
</span><span class="cx">
</span><span class="lines">@@ -74,10 +73,10 @@
</span><span class="cx"> print(" --search <search-string>: search for matching principals")
</span><span class="cx"> print(" --list-principal-types: list all of the known principal types")
</span><span class="cx"> print(" --list-principals type: list all principals of the given type")
</span><del>- print(" --read-property=property: read DAV property (eg.: {DAV:}group-member-set)")
</del><span class="cx"> print(" --list-read-proxies: list proxies with read-only access")
</span><span class="cx"> print(" --list-write-proxies: list proxies with read-write access")
</span><span class="cx"> print(" --list-proxies: list all proxies")
</span><ins>+ print(" --list-proxy-for: principals this principal is a proxy for")
</ins><span class="cx"> print(" --add-read-proxy=principal: add a read-only proxy")
</span><span class="cx"> print(" --add-write-proxy=principal: add a read-write proxy")
</span><span class="cx"> print(" --remove-proxy=principal: remove a proxy")
</span><span class="lines">@@ -118,33 +117,32 @@
</span><span class="cx"> resource, directory, store, and whatever has been assigned to "params".
</span><span class="cx"> """
</span><span class="cx"> if self.function is not None:
</span><del>- rootResource = self.rootResource()
- directory = rootResource.getDirectory()
- yield self.function(rootResource, directory, self.store, *self.params)
</del><ins>+ yield self.function(self.store, *self.params)
</ins><span class="cx">
</span><span class="cx"> attrMap = {
</span><del>- 'GeneratedUID' : { 'attr' : 'guid', },
- 'RealName' : { 'attr' : 'fullName', },
- 'RecordName' : { 'attr' : 'shortNames', },
- 'AutoSchedule' : { 'attr' : 'autoSchedule', },
- 'AutoAcceptGroup' : { 'attr' : 'autoAcceptGroup', },
</del><ins>+ 'GeneratedUID': {'attr': 'guid', },
+ 'RealName': {'attr': 'fullName', },
+ 'RecordName': {'attr': 'shortNames', },
+ 'AutoSchedule': {'attr': 'autoSchedule', },
+ 'AutoAcceptGroup': {'attr': 'autoAcceptGroup', },
</ins><span class="cx">
</span><del>- 'Comment' : { 'extras' : True, 'attr' : 'comment', },
- 'Description' : { 'extras' : True, 'attr' : 'description', },
- 'Type' : { 'extras' : True, 'attr' : 'type', },
</del><ins>+ 'Comment': {'extras': True, 'attr': 'comment', },
+ 'Description': {'extras': True, 'attr': 'description', },
+ 'Type': {'extras': True, 'attr': 'type', },
</ins><span class="cx">
</span><span class="cx"> # For "Locations", i.e. scheduled spaces
</span><del>- 'Capacity' : { 'extras' : True, 'attr' : 'capacity', },
- 'Floor' : { 'extras' : True, 'attr' : 'floor', },
- 'AssociatedAddress' : { 'extras' : True, 'attr' : 'associatedAddress', },
</del><ins>+ 'Capacity': {'extras': True, 'attr': 'capacity', },
+ 'Floor': {'extras': True, 'attr': 'floor', },
+ 'AssociatedAddress': {'extras': True, 'attr': 'associatedAddress', },
</ins><span class="cx">
</span><span class="cx"> # For "Addresses", i.e. nonscheduled areas containing Locations
</span><del>- 'AbbreviatedName' : { 'extras' : True, 'attr' : 'abbreviatedName', },
- 'StreetAddress' : { 'extras' : True, 'attr' : 'streetAddress', },
- 'Geo' : { 'extras' : True, 'attr' : 'geo', },
</del><ins>+ 'AbbreviatedName': {'extras': True, 'attr': 'abbreviatedName', },
+ 'StreetAddress': {'extras': True, 'attr': 'streetAddress', },
+ 'Geo': {'extras': True, 'attr': 'geo', },
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><ins>+@inlineCallbacks
</ins><span class="cx"> def main():
</span><span class="cx"> try:
</span><span class="cx"> (optargs, args) = getopt(
</span><span class="lines">@@ -156,10 +154,10 @@
</span><span class="cx"> "search=",
</span><span class="cx"> "list-principal-types",
</span><span class="cx"> "list-principals=",
</span><del>- "read-property=",
</del><span class="cx"> "list-read-proxies",
</span><span class="cx"> "list-write-proxies",
</span><span class="cx"> "list-proxies",
</span><ins>+ "list-proxy-for",
</ins><span class="cx"> "add-read-proxy=",
</span><span class="cx"> "add-write-proxy=",
</span><span class="cx"> "remove-proxy=",
</span><span class="lines">@@ -185,7 +183,7 @@
</span><span class="cx"> # Get configuration
</span><span class="cx"> #
</span><span class="cx"> configFileName = None
</span><del>- addType = None
</del><ins>+ # addType = None
</ins><span class="cx"> listPrincipalTypes = False
</span><span class="cx"> listPrincipals = None
</span><span class="cx"> searchPrincipals = None
</span><span class="lines">@@ -202,11 +200,11 @@
</span><span class="cx"> elif opt in ("-f", "--config"):
</span><span class="cx"> configFileName = arg
</span><span class="cx">
</span><del>- elif opt in ("-a", "--add"):
- addType = arg
</del><ins>+ # elif opt in ("-a", "--add"):
+ # addType = arg
</ins><span class="cx">
</span><del>- elif opt in ("-r", "--remove"):
- principalActions.append((action_removePrincipal,))
</del><ins>+ # elif opt in ("-r", "--remove"):
+ # principalActions.append((action_removePrincipal,))
</ins><span class="cx">
</span><span class="cx"> elif opt in ("", "--list-principal-types"):
</span><span class="cx"> listPrincipalTypes = True
</span><span class="lines">@@ -217,13 +215,6 @@
</span><span class="cx"> elif opt in ("", "--search"):
</span><span class="cx"> searchPrincipals = arg
</span><span class="cx">
</span><del>- elif opt in ("", "--read-property"):
- try:
- qname = decodeXMLName(arg)
- except ValueError, e:
- abort(e)
- principalActions.append((action_readProperty, qname))
-
</del><span class="cx"> elif opt in ("", "--list-read-proxies"):
</span><span class="cx"> principalActions.append((action_listProxies, "read"))
</span><span class="cx">
</span><span class="lines">@@ -233,6 +224,9 @@
</span><span class="cx"> elif opt in ("-L", "--list-proxies"):
</span><span class="cx"> principalActions.append((action_listProxies, "read", "write"))
</span><span class="cx">
</span><ins>+ elif opt in ("--list-proxy-for"):
+ principalActions.append((action_listProxyFor, "read", "write"))
+
</ins><span class="cx"> elif opt in ("--add-read-proxy", "--add-write-proxy"):
</span><span class="cx"> if "read" in opt:
</span><span class="cx"> proxyType = "read"
</span><span class="lines">@@ -242,7 +236,7 @@
</span><span class="cx"> raise AssertionError("Unknown proxy type")
</span><span class="cx">
</span><span class="cx"> try:
</span><del>- principalForPrincipalID(arg, checkOnly=True)
</del><ins>+ yield recordForPrincipalID(arg, checkOnly=True)
</ins><span class="cx"> except ValueError, e:
</span><span class="cx"> abort(e)
</span><span class="cx">
</span><span class="lines">@@ -250,64 +244,64 @@
</span><span class="cx">
</span><span class="cx"> elif opt in ("", "--remove-proxy"):
</span><span class="cx"> try:
</span><del>- principalForPrincipalID(arg, checkOnly=True)
</del><ins>+ yield recordForPrincipalID(arg, checkOnly=True)
</ins><span class="cx"> except ValueError, e:
</span><span class="cx"> abort(e)
</span><span class="cx">
</span><span class="cx"> principalActions.append((action_removeProxy, arg))
</span><span class="cx">
</span><del>- elif opt in ("", "--set-auto-schedule"):
- try:
- autoSchedule = booleanArgument(arg)
- except ValueError, e:
- abort(e)
</del><ins>+ # elif opt in ("", "--set-auto-schedule"):
+ # try:
+ # autoSchedule = booleanArgument(arg)
+ # except ValueError, e:
+ # abort(e)
</ins><span class="cx">
</span><del>- principalActions.append((action_setAutoSchedule, autoSchedule))
</del><ins>+ # principalActions.append((action_setAutoSchedule, autoSchedule))
</ins><span class="cx">
</span><del>- elif opt in ("", "--get-auto-schedule"):
- principalActions.append((action_getAutoSchedule,))
</del><ins>+ # elif opt in ("", "--get-auto-schedule"):
+ # principalActions.append((action_getAutoSchedule,))
</ins><span class="cx">
</span><del>- elif opt in ("", "--set-auto-schedule-mode"):
- try:
- if arg not in allowedAutoScheduleModes:
- raise ValueError("Unknown auto-schedule mode: %s" % (arg,))
- autoScheduleMode = arg
- except ValueError, e:
- abort(e)
</del><ins>+ # elif opt in ("", "--set-auto-schedule-mode"):
+ # try:
+ # if arg not in allowedAutoScheduleModes:
+ # raise ValueError("Unknown auto-schedule mode: %s" % (arg,))
+ # autoScheduleMode = arg
+ # except ValueError, e:
+ # abort(e)
</ins><span class="cx">
</span><del>- principalActions.append((action_setAutoScheduleMode, autoScheduleMode))
</del><ins>+ # principalActions.append((action_setAutoScheduleMode, autoScheduleMode))
</ins><span class="cx">
</span><del>- elif opt in ("", "--get-auto-schedule-mode"):
- principalActions.append((action_getAutoScheduleMode,))
</del><ins>+ # elif opt in ("", "--get-auto-schedule-mode"):
+ # principalActions.append((action_getAutoScheduleMode,))
</ins><span class="cx">
</span><del>- elif opt in ("", "--set-auto-accept-group"):
- try:
- principalForPrincipalID(arg, checkOnly=True)
- except ValueError, e:
- abort(e)
</del><ins>+ # elif opt in ("", "--set-auto-accept-group"):
+ # try:
+ # yield recordForPrincipalID(arg, checkOnly=True)
+ # except ValueError, e:
+ # abort(e)
</ins><span class="cx">
</span><del>- principalActions.append((action_setAutoAcceptGroup, arg))
</del><ins>+ # principalActions.append((action_setAutoAcceptGroup, arg))
</ins><span class="cx">
</span><del>- elif opt in ("", "--get-auto-accept-group"):
- principalActions.append((action_getAutoAcceptGroup,))
</del><ins>+ # elif opt in ("", "--get-auto-accept-group"):
+ # principalActions.append((action_getAutoAcceptGroup,))
</ins><span class="cx">
</span><del>- elif opt in ("", "--set-geo"):
- principalActions.append((action_setValue, "Geo", arg))
</del><ins>+ # elif opt in ("", "--set-geo"):
+ # principalActions.append((action_setValue, "Geo", arg))
</ins><span class="cx">
</span><del>- elif opt in ("", "--get-geo"):
- principalActions.append((action_getValue, "Geo"))
</del><ins>+ # elif opt in ("", "--get-geo"):
+ # principalActions.append((action_getValue, "Geo"))
</ins><span class="cx">
</span><del>- elif opt in ("", "--set-street-address"):
- principalActions.append((action_setValue, "StreetAddress", arg))
</del><ins>+ # elif opt in ("", "--set-street-address"):
+ # principalActions.append((action_setValue, "StreetAddress", arg))
</ins><span class="cx">
</span><del>- elif opt in ("", "--get-street-address"):
- principalActions.append((action_getValue, "StreetAddress"))
</del><ins>+ # elif opt in ("", "--get-street-address"):
+ # principalActions.append((action_getValue, "StreetAddress"))
</ins><span class="cx">
</span><del>- elif opt in ("", "--set-address"):
- principalActions.append((action_setValue, "AssociatedAddress", arg))
</del><ins>+ # elif opt in ("", "--set-address"):
+ # principalActions.append((action_setValue, "AssociatedAddress", arg))
</ins><span class="cx">
</span><del>- elif opt in ("", "--get-address"):
- principalActions.append((action_getValue, "AssociatedAddress"))
</del><ins>+ # elif opt in ("", "--get-address"):
+ # principalActions.append((action_getValue, "AssociatedAddress"))
</ins><span class="cx">
</span><span class="cx"> else:
</span><span class="cx"> raise NotImplementedError(opt)
</span><span class="lines">@@ -322,32 +316,34 @@
</span><span class="cx"> function = runListPrincipalTypes
</span><span class="cx"> params = ()
</span><span class="cx">
</span><del>- elif addType:
</del><ins>+ # elif addType:
</ins><span class="cx">
</span><del>- try:
- addType = matchStrings(addType, ["locations", "resources", "addresses"])
- except ValueError, e:
- print(e)
- return
</del><ins>+ # try:
+ # addType = matchStrings(addType, ["locations", "resources", "addresses"])
+ # except ValueError, e:
+ # print(e)
+ # return
</ins><span class="cx">
</span><del>- try:
- fullName, shortName, guid = parseCreationArgs(args)
- except ValueError, e:
- print(e)
- return
</del><ins>+ # try:
+ # fullName, shortName, guid = parseCreationArgs(args)
+ # except ValueError, e:
+ # print(e)
+ # return
</ins><span class="cx">
</span><del>- if shortName is not None:
- shortNames = [shortName]
- else:
- shortNames = ()
</del><ins>+ # if shortName is not None:
+ # shortNames = [shortName]
+ # else:
+ # shortNames = ()
</ins><span class="cx">
</span><del>- function = runAddPrincipal
- params = (addType, guid, shortNames, fullName)
</del><ins>+ # function = runAddPrincipal
+ # params = (addType, guid, shortNames, fullName)
</ins><span class="cx">
</span><span class="cx"> elif listPrincipals:
</span><span class="cx"> try:
</span><del>- listPrincipals = matchStrings(listPrincipals, ["users", "groups",
- "locations", "resources", "addresses"])
</del><ins>+ listPrincipals = matchStrings(
+ listPrincipals,
+ ["users", "groups", "locations", "resources", "addresses"]
+ )
</ins><span class="cx"> except ValueError, e:
</span><span class="cx"> print(e)
</span><span class="cx"> return
</span><span class="lines">@@ -372,7 +368,7 @@
</span><span class="cx">
</span><span class="cx"> for arg in args:
</span><span class="cx"> try:
</span><del>- principalForPrincipalID(arg, checkOnly=True)
</del><ins>+ yield recordForPrincipalID(arg, checkOnly=True)
</ins><span class="cx"> except ValueError, e:
</span><span class="cx"> abort(e)
</span><span class="cx">
</span><span class="lines">@@ -385,17 +381,20 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-def runListPrincipalTypes(service, rootResource, directory, store):
</del><ins>+def runListPrincipalTypes(service, store):
+ directory = store.directoryService()
</ins><span class="cx"> for recordType in directory.recordTypes():
</span><del>- print(recordType)
</del><ins>+ print(directory.recordTypeToOldString(recordType))
</ins><span class="cx"> return succeed(None)
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>-def runListPrincipals(service, rootResource, directory, store, listPrincipals):
</del><ins>+def runListPrincipals(service, store, listPrincipals):
+ directory = store.directoryService()
+ recordType = directory.oldNameToRecordType(listPrincipals)
</ins><span class="cx"> try:
</span><del>- records = list((yield directory.listRecords(listPrincipals)))
</del><ins>+ records = list((yield directory.recordsWithRecordType(recordType)))
</ins><span class="cx"> if records:
</span><span class="cx"> printRecordList(records)
</span><span class="cx"> else:
</span><span class="lines">@@ -407,51 +406,48 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>-def runPrincipalActions(service, rootResource, directory, store, principalIDs,
- actions):
</del><ins>+def runPrincipalActions(service, store, principalIDs, actions):
+ directory = store.directoryService()
</ins><span class="cx"> for principalID in principalIDs:
</span><del>- # Resolve the given principal IDs to principals
</del><ins>+ # Resolve the given principal IDs to records
</ins><span class="cx"> try:
</span><del>- principal = yield principalForPrincipalID(principalID, directory=directory)
</del><ins>+ record = yield recordForPrincipalID(
+ principalID, directory=directory
+ )
</ins><span class="cx"> except ValueError:
</span><del>- principal = None
</del><ins>+ record = None
</ins><span class="cx">
</span><del>- if principal is None:
</del><ins>+ if record is None:
</ins><span class="cx"> sys.stderr.write("Invalid principal ID: %s\n" % (principalID,))
</span><span class="cx"> continue
</span><span class="cx">
</span><span class="cx"> # Performs requested actions
</span><span class="cx"> for action in actions:
</span><del>- (yield action[0](rootResource, directory, store, principal,
- *action[1:]))
</del><ins>+ (yield action[0](store, record, *action[1:]))
</ins><span class="cx"> print("")
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>-def runSearch(service, rootResource, directory, store, searchTerm):
-
</del><ins>+def runSearch(service, store, searchTerm):
+ directory = store.directoryService()
</ins><span class="cx"> fields = []
</span><del>- for fieldName in ("fullName", "firstName", "lastName", "emailAddresses"):
</del><ins>+ for fieldName in ("fullNames", "emailAddresses"):
</ins><span class="cx"> fields.append((fieldName, searchTerm, True, "contains"))
</span><span class="cx">
</span><span class="cx"> records = list((yield directory.recordsMatchingTokens(searchTerm.strip().split())))
</span><span class="cx"> if records:
</span><del>- records.sort(key=operator.attrgetter('fullName'))
</del><ins>+ records.sort(key=operator.attrgetter('fullNames'))
</ins><span class="cx"> print("%d matches found:" % (len(records),))
</span><span class="cx"> for record in records:
</span><del>- print("\n%s (%s)" % (record.fullName,
- {"users" : "User",
- "groups" : "Group",
- "locations" : "Place",
- "resources" : "Resource",
- "addresses" : "Address",
- }.get(record.recordType),
- ))
- print(" GUID: %s" % (record.guid,))
</del><ins>+ print(
+ "\n{d} {rt}".format(
+ d=record.displayName,
+ rt=record.recordType.name
+ )
+ )
+ print(" UID: %s" % (record.uid,))
</ins><span class="cx"> print(" Record name(s): %s" % (", ".join(record.shortNames),))
</span><del>- if record.authIDs:
- print(" Auth ID(s): %s" % (", ".join(record.authIDs),))
</del><span class="cx"> if record.emailAddresses:
</span><span class="cx"> print(" Email(s): %s" % (", ".join(record.emailAddresses),))
</span><span class="cx"> else:
</span><span class="lines">@@ -461,292 +457,318 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-@inlineCallbacks
-def runAddPrincipal(service, rootResource, directory, store, addType, guid,
- shortNames, fullName):
- try:
- yield updateRecord(True, directory, addType, guid=guid,
- shortNames=shortNames, fullName=fullName)
- print("Added '%s'" % (fullName,))
- except DirectoryError, e:
- print(e)
</del><ins>+# @inlineCallbacks
+# def runAddPrincipal(service, store, addType, guid, shortNames, fullName):
+# directory = store.directoryService()
+# try:
+# # FIXME STOP USING GUID
+# yield updateRecord(
+# True, directory, addType, guid=guid,
+# shortNames=shortNames, fullName=fullName
+# )
+# print("Added '%s'" % (fullName,))
+# except DirectoryError, e:
+# print(e)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-def action_removePrincipal(rootResource, directory, store, principal):
- record = principal.record
- fullName = record.fullName
- shortName = record.shortNames[0]
- guid = record.guid
</del><ins>+# def action_removePrincipal(store, record):
+# directory = store.directoryService()
+# fullName = record.displayName
+# shortName = record.shortNames[0]
</ins><span class="cx">
</span><del>- directory.destroyRecord(record.recordType, guid=guid)
- print("Removed '%s' %s %s" % (fullName, shortName, guid))
</del><ins>+# yield directory.destroyRecord(record.recordType, uid=record.uid)
+# print("Removed '%s' %s %s" % (fullName, shortName, record.uid))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><ins>+
</ins><span class="cx"> @inlineCallbacks
</span><del>-def action_readProperty(rootResource, directory, store, resource, qname):
- property = (yield resource.readProperty(qname, None))
- print("%r on %s:" % (encodeXMLName(*qname), resource))
- print("")
- print(property.toxml())
</del><ins>+def action_listProxies(store, record, *proxyTypes):
+ directory = store.directoryService()
+ for proxyType in proxyTypes:
</ins><span class="cx">
</span><ins>+ groupRecordType = {
+ "read": directory.recordType.readDelegateGroup,
+ "write": directory.recordType.writeDelegateGroup,
+ }.get(proxyType)
</ins><span class="cx">
</span><ins>+ pseudoGroup = yield directory.recordWithShortName(
+ groupRecordType,
+ record.uid
+ )
+ proxies = yield pseudoGroup.members()
+ if proxies:
+ print("%s proxies for %s:" % (
+ {"read": "Read-only", "write": "Read/write"}[proxyType],
+ prettyRecord(record)
+ ))
+ printRecordList(proxies)
+ print("")
+ else:
+ print("No %s proxies for %s" % (proxyType, prettyRecord(record)))
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> @inlineCallbacks
</span><del>-def action_listProxies(rootResource, directory, store, principal, *proxyTypes):
</del><ins>+def action_listProxyFor(store, record, *proxyTypes):
+ directory = store.directoryService()
</ins><span class="cx"> for proxyType in proxyTypes:
</span><del>- subPrincipal = proxySubprincipal(principal, proxyType)
- if subPrincipal is None:
- print("No %s proxies for %s" % (proxyType,
- prettyPrincipal(principal)))
- continue
</del><span class="cx">
</span><del>- membersProperty = (yield subPrincipal.readProperty(davxml.GroupMemberSet, None))
</del><ins>+ groupRecordType = {
+ "read": directory.recordType.readDelegatorGroup,
+ "write": directory.recordType.writeDelegatorGroup,
+ }.get(proxyType)
</ins><span class="cx">
</span><del>- if membersProperty.children:
- print("%s proxies for %s:" % (
- {"read": "Read-only", "write": "Read/write"}[proxyType],
- prettyPrincipal(principal)
</del><ins>+ pseudoGroup = yield directory.recordWithShortName(
+ groupRecordType,
+ record.uid
+ )
+ proxies = yield pseudoGroup.members()
+ if proxies:
+ print("%s is a %s proxy for:" % (
+ prettyRecord(record),
+ {"read": "Read-only", "write": "Read/write"}[proxyType]
</ins><span class="cx"> ))
</span><del>- records = []
- for member in membersProperty.children:
- proxyPrincipal = principalForPrincipalID(str(member),
- directory=directory)
- records.append(proxyPrincipal.record)
-
- printRecordList(records)
- print
</del><ins>+ printRecordList(proxies)
+ print("")
</ins><span class="cx"> else:
</span><del>- print("No %s proxies for %s" % (proxyType,
- prettyPrincipal(principal)))
</del><ins>+ print(
+ "{r} is not a {t} proxy for anyone".format(
+ r=prettyRecord(record),
+ t={"read": "Read-only", "write": "Read/write"}[proxyType]
+ )
+ )
</ins><span class="cx">
</span><span class="cx">
</span><del>-
</del><span class="cx"> @inlineCallbacks
</span><del>-def action_addProxy(rootResource, directory, store, principal, proxyType, *proxyIDs):
</del><ins>+def _addRemoveProxy(fn, store, record, proxyType, *proxyIDs):
+ directory = store.directoryService()
+ readWrite = (proxyType == "write")
</ins><span class="cx"> for proxyID in proxyIDs:
</span><del>- proxyPrincipal = yield principalForPrincipalID(proxyID, directory=directory)
- if proxyPrincipal is None:
</del><ins>+ proxyRecord = yield recordForPrincipalID(proxyID, directory=directory)
+ if proxyRecord is None:
</ins><span class="cx"> print("Invalid principal ID: %s" % (proxyID,))
</span><span class="cx"> else:
</span><del>- (yield action_addProxyPrincipal(rootResource, directory, store,
- principal, proxyType, proxyPrincipal))
</del><ins>+ txn = store.newTransaction()
+ yield fn(txn, record, proxyRecord, readWrite)
+ yield txn.commit()
</ins><span class="cx">
</span><span class="cx">
</span><ins>+def action_addProxy(store, record, proxyType, *proxyIDs):
+ return _addRemoveProxy(addDelegate, store, record, proxyType, *proxyIDs)
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> @inlineCallbacks
</span><del>-def setProxies(store, principal, readProxyPrincipals, writeProxyPrincipals, directory=None):
- """
- Set read/write proxies en masse for a principal
- @param principal: DirectoryPrincipalResource
- @param readProxyPrincipals: a list of principal IDs (see principalForPrincipalID)
- @param writeProxyPrincipals: a list of principal IDs (see principalForPrincipalID)
- """
</del><ins>+def action_removeProxy(store, record, *proxyIDs):
+ # Write
+ yield _addRemoveProxy(removeDelegate, store, record, "write", *proxyIDs)
+ # Read
+ yield _addRemoveProxy(removeDelegate, store, record, "read", *proxyIDs)
</ins><span class="cx">
</span><del>- proxyTypes = [
- ("read", readProxyPrincipals),
- ("write", writeProxyPrincipals),
- ]
- for proxyType, proxyIDs in proxyTypes:
- if proxyIDs is None:
- continue
- subPrincipal = proxySubprincipal(principal, proxyType)
- if subPrincipal is None:
- raise ProxyError("Unable to edit %s proxies for %s\n" % (proxyType,
- prettyPrincipal(principal)))
- memberURLs = []
- for proxyID in proxyIDs:
- proxyPrincipal = yield principalForPrincipalID(proxyID, directory=directory)
- proxyURL = proxyPrincipal.url()
- memberURLs.append(davxml.HRef(proxyURL))
- membersProperty = davxml.GroupMemberSet(*memberURLs)
- yield subPrincipal.writeProperty(membersProperty, None)
- if store is not None:
- # Schedule work the PeerConnectionPool will pick up as overdue
- yield schedulePolledGroupCachingUpdate(store)
</del><span class="cx">
</span><span class="cx">
</span><ins>+# @inlineCallbacks
+# def setProxies(store, principal, readProxyPrincipals, writeProxyPrincipals, directory=None):
+# """
+# Set read/write proxies en masse for a principal
+# @param principal: DirectoryPrincipalResource
+# @param readProxyPrincipals: a list of principal IDs (see principalForPrincipalID)
+# @param writeProxyPrincipals: a list of principal IDs (see principalForPrincipalID)
+# """
</ins><span class="cx">
</span><del>-@inlineCallbacks
-def getProxies(principal, directory=None):
- """
- Returns a tuple containing the GUIDs for read proxies and write proxies
- of the given principal
- """
</del><ins>+# proxyTypes = [
+# ("read", readProxyPrincipals),
+# ("write", writeProxyPrincipals),
+# ]
+# for proxyType, proxyIDs in proxyTypes:
+# if proxyIDs is None:
+# continue
+# subPrincipal = proxySubprincipal(principal, proxyType)
+# if subPrincipal is None:
+# raise ProxyError("Unable to edit %s proxies for %s\n" % (proxyType,
+# prettyPrincipal(principal)))
+# memberURLs = []
+# for proxyID in proxyIDs:
+# proxyPrincipal = yield principalForPrincipalID(proxyID, directory=directory)
+# proxyURL = proxyPrincipal.url()
+# memberURLs.append(davxml.HRef(proxyURL))
+# membersProperty = davxml.GroupMemberSet(*memberURLs)
+# yield subPrincipal.writeProperty(membersProperty, None)
+# if store is not None:
+# # Schedule work the PeerConnectionPool will pick up as overdue
+# yield schedulePolledGroupCachingUpdate(store)
</ins><span class="cx">
</span><del>- proxies = {
- "read" : [],
- "write" : [],
- }
- for proxyType in proxies.iterkeys():
- subPrincipal = proxySubprincipal(principal, proxyType)
- if subPrincipal is not None:
- membersProperty = (yield subPrincipal.readProperty(davxml.GroupMemberSet, None))
- if membersProperty.children:
- for member in membersProperty.children:
- proxyPrincipal = yield principalForPrincipalID(str(member), directory=directory)
- proxies[proxyType].append(proxyPrincipal.record.guid)
</del><span class="cx">
</span><del>- returnValue((proxies['read'], proxies['write']))
</del><span class="cx">
</span><ins>+# @inlineCallbacks
+# def getProxies(principal, directory=None):
+# """
+# Returns a tuple containing the GUIDs for read proxies and write proxies
+# of the given principal
+# """
</ins><span class="cx">
</span><ins>+# proxies = {
+# "read": [],
+# "write": [],
+# }
+# for proxyType in proxies.iterkeys():
+# subPrincipal = proxySubprincipal(principal, proxyType)
+# if subPrincipal is not None:
+# membersProperty = (yield subPrincipal.readProperty(davxml.GroupMemberSet, None))
+# if membersProperty.children:
+# for member in membersProperty.children:
+# proxyPrincipal = yield principalForPrincipalID(str(member), directory=directory)
+# proxies[proxyType].append(proxyPrincipal.record.guid)
</ins><span class="cx">
</span><del>-@inlineCallbacks
-def action_removeProxy(rootResource, directory, store, principal, *proxyIDs, **kwargs):
- for proxyID in proxyIDs:
- proxyPrincipal = yield principalForPrincipalID(proxyID, directory=directory)
- if proxyPrincipal is None:
- print("Invalid principal ID: %s" % (proxyID,))
- else:
- (yield action_removeProxyPrincipal(rootResource, directory, store,
- principal, proxyPrincipal, **kwargs))
</del><ins>+# returnValue((proxies['read'], proxies['write']))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-@inlineCallbacks
-def action_setAutoSchedule(rootResource, directory, store, principal, autoSchedule):
- if principal.record.recordType == "groups":
- print("Enabling auto-schedule for %s is not allowed." % (principal,))
</del><span class="cx">
</span><del>- elif principal.record.recordType == "users" and not config.Scheduling.Options.AutoSchedule.AllowUsers:
- print("Enabling auto-schedule for %s is not allowed." % (principal,))
</del><span class="cx">
</span><del>- else:
- print("Setting auto-schedule to %s for %s" % (
- {True: "true", False: "false"}[autoSchedule],
- prettyPrincipal(principal),
- ))
</del><ins>+# @inlineCallbacks
+# def action_setAutoSchedule(rootResource, directory, store, principal, autoSchedule):
+# if principal.record.recordType == "groups":
+# print("Enabling auto-schedule for %s is not allowed." % (principal,))
</ins><span class="cx">
</span><del>- (yield updateRecord(False, directory,
- principal.record.recordType,
- guid=principal.record.guid,
- shortNames=principal.record.shortNames,
- fullName=principal.record.fullName,
- autoSchedule=autoSchedule,
- **principal.record.extras
- ))
</del><ins>+# elif principal.record.recordType == "users" and not config.Scheduling.Options.AutoSchedule.AllowUsers:
+# print("Enabling auto-schedule for %s is not allowed." % (principal,))
</ins><span class="cx">
</span><ins>+# else:
+# print("Setting auto-schedule to %s for %s" % (
+# {True: "true", False: "false"}[autoSchedule],
+# prettyPrincipal(principal),
+# ))
</ins><span class="cx">
</span><ins>+# (yield updateRecord(False, directory,
+# principal.record.recordType,
+# guid=principal.record.guid,
+# shortNames=principal.record.shortNames,
+# fullName=principal.record.fullName,
+# autoSchedule=autoSchedule,
+# **principal.record.extras
+# ))
</ins><span class="cx">
</span><del>-def action_getAutoSchedule(rootResource, directory, store, principal):
- autoSchedule = principal.getAutoSchedule()
- print("Auto-schedule for %s is %s" % (
- prettyPrincipal(principal),
- {True: "true", False: "false"}[autoSchedule],
- ))
</del><span class="cx">
</span><span class="cx">
</span><ins>+# def action_getAutoSchedule(rootResource, directory, store, principal):
+# autoSchedule = principal.getAutoSchedule()
+# print("Auto-schedule for %s is %s" % (
+# prettyPrincipal(principal),
+# {True: "true", False: "false"}[autoSchedule],
+# ))
</ins><span class="cx">
</span><del>-@inlineCallbacks
-def action_setAutoScheduleMode(rootResource, directory, store, principal, autoScheduleMode):
- if principal.record.recordType == "groups":
- print("Setting auto-schedule mode for %s is not allowed." % (principal,))
</del><span class="cx">
</span><del>- elif principal.record.recordType == "users" and not config.Scheduling.Options.AutoSchedule.AllowUsers:
- print("Setting auto-schedule mode for %s is not allowed." % (principal,))
</del><span class="cx">
</span><del>- else:
- print("Setting auto-schedule mode to %s for %s" % (
- autoScheduleMode,
- prettyPrincipal(principal),
- ))
</del><ins>+# @inlineCallbacks
+# def action_setAutoScheduleMode(rootResource, directory, store, principal, autoScheduleMode):
+# if principal.record.recordType == "groups":
+# print("Setting auto-schedule mode for %s is not allowed." % (principal,))
</ins><span class="cx">
</span><del>- (yield updateRecord(False, directory,
- principal.record.recordType,
- guid=principal.record.guid,
- shortNames=principal.record.shortNames,
- fullName=principal.record.fullName,
- autoScheduleMode=autoScheduleMode,
- **principal.record.extras
- ))
</del><ins>+# elif principal.record.recordType == "users" and not config.Scheduling.Options.AutoSchedule.AllowUsers:
+# print("Setting auto-schedule mode for %s is not allowed." % (principal,))
</ins><span class="cx">
</span><ins>+# else:
+# print("Setting auto-schedule mode to %s for %s" % (
+# autoScheduleMode,
+# prettyPrincipal(principal),
+# ))
</ins><span class="cx">
</span><ins>+# (yield updateRecord(False, directory,
+# principal.record.recordType,
+# guid=principal.record.guid,
+# shortNames=principal.record.shortNames,
+# fullName=principal.record.fullName,
+# autoScheduleMode=autoScheduleMode,
+# **principal.record.extras
+# ))
</ins><span class="cx">
</span><del>-def action_getAutoScheduleMode(rootResource, directory, store, principal):
- autoScheduleMode = principal.getAutoScheduleMode()
- if not autoScheduleMode:
- autoScheduleMode = "automatic"
- print("Auto-schedule mode for %s is %s" % (
- prettyPrincipal(principal),
- autoScheduleMode,
- ))
</del><span class="cx">
</span><span class="cx">
</span><ins>+# def action_getAutoScheduleMode(rootResource, directory, store, principal):
+# autoScheduleMode = principal.getAutoScheduleMode()
+# if not autoScheduleMode:
+# autoScheduleMode = "automatic"
+# print("Auto-schedule mode for %s is %s" % (
+# prettyPrincipal(principal),
+# autoScheduleMode,
+# ))
</ins><span class="cx">
</span><del>-@inlineCallbacks
-def action_setAutoAcceptGroup(rootResource, directory, store, principal, autoAcceptGroup):
- if principal.record.recordType == "groups":
- print("Setting auto-accept-group for %s is not allowed." % (principal,))
</del><span class="cx">
</span><del>- elif principal.record.recordType == "users" and not config.Scheduling.Options.AutoSchedule.AllowUsers:
- print("Setting auto-accept-group for %s is not allowed." % (principal,))
</del><span class="cx">
</span><del>- else:
- groupPrincipal = yield principalForPrincipalID(autoAcceptGroup, directory=directory)
- if groupPrincipal is None or groupPrincipal.record.recordType != "groups":
- print("Invalid principal ID: %s" % (autoAcceptGroup,))
- else:
- print("Setting auto-accept-group to %s for %s" % (
- prettyPrincipal(groupPrincipal),
- prettyPrincipal(principal),
- ))
</del><ins>+# @inlineCallbacks
+# def action_setAutoAcceptGroup(rootResource, directory, store, principal, autoAcceptGroup):
+# if principal.record.recordType == "groups":
+# print("Setting auto-accept-group for %s is not allowed." % (principal,))
</ins><span class="cx">
</span><del>- (yield updateRecord(False, directory,
- principal.record.recordType,
- guid=principal.record.guid,
- shortNames=principal.record.shortNames,
- fullName=principal.record.fullName,
- autoAcceptGroup=groupPrincipal.record.guid,
- **principal.record.extras
- ))
</del><ins>+# elif principal.record.recordType == "users" and not config.Scheduling.Options.AutoSchedule.AllowUsers:
+# print("Setting auto-accept-group for %s is not allowed." % (principal,))
</ins><span class="cx">
</span><ins>+# else:
+# groupPrincipal = yield principalForPrincipalID(autoAcceptGroup, directory=directory)
+# if groupPrincipal is None or groupPrincipal.record.recordType != "groups":
+# print("Invalid principal ID: %s" % (autoAcceptGroup,))
+# else:
+# print("Setting auto-accept-group to %s for %s" % (
+# prettyPrincipal(groupPrincipal),
+# prettyPrincipal(principal),
+# ))
</ins><span class="cx">
</span><ins>+# (yield updateRecord(False, directory,
+# principal.record.recordType,
+# guid=principal.record.guid,
+# shortNames=principal.record.shortNames,
+# fullName=principal.record.fullName,
+# autoAcceptGroup=groupPrincipal.record.guid,
+# **principal.record.extras
+# ))
</ins><span class="cx">
</span><del>-def action_getAutoAcceptGroup(rootResource, directory, store, principal):
- autoAcceptGroup = principal.getAutoAcceptGroup()
- if autoAcceptGroup:
- record = yield directory.recordWithGUID(autoAcceptGroup)
- if record is not None:
- groupPrincipal = yield directory.principalCollection.principalForUID(record.uid)
- if groupPrincipal is not None:
- print("Auto-accept-group for %s is %s" % (
- prettyPrincipal(principal),
- prettyPrincipal(groupPrincipal),
- ))
- return
- print("Invalid auto-accept-group assigned: %s" % (autoAcceptGroup,))
- else:
- print("No auto-accept-group assigned to %s" % (prettyPrincipal(principal),))
</del><span class="cx">
</span><span class="cx">
</span><ins>+# def action_getAutoAcceptGroup(rootResource, directory, store, principal):
+# autoAcceptGroup = principal.getAutoAcceptGroup()
+# if autoAcceptGroup:
+# record = yield directory.recordWithGUID(autoAcceptGroup)
+# if record is not None:
+# groupPrincipal = yield directory.principalCollection.principalForUID(record.uid)
+# if groupPrincipal is not None:
+# print("Auto-accept-group for %s is %s" % (
+# prettyPrincipal(principal),
+# prettyPrincipal(groupPrincipal),
+# ))
+# return
+# print("Invalid auto-accept-group assigned: %s" % (autoAcceptGroup,))
+# else:
+# print("No auto-accept-group assigned to %s" % (prettyPrincipal(principal),))
</ins><span class="cx">
</span><del>-@inlineCallbacks
-def action_setValue(rootResource, directory, store, principal, name, value):
- print("Setting %s to %s for %s" % (
- name, value, prettyPrincipal(principal),
- ))
</del><span class="cx">
</span><del>- principal.record.extras[attrMap[name]["attr"]] = value
- (yield updateRecord(False, directory,
- principal.record.recordType,
- guid=principal.record.guid,
- shortNames=principal.record.shortNames,
- fullName=principal.record.fullName,
- **principal.record.extras
- ))
</del><span class="cx">
</span><ins>+# @inlineCallbacks
+# def action_setValue(rootResource, directory, store, principal, name, value):
+# print("Setting %s to %s for %s" % (
+# name, value, prettyPrincipal(principal),
+# ))
</ins><span class="cx">
</span><ins>+# principal.record.extras[attrMap[name]["attr"]] = value
+# (yield updateRecord(False, directory,
+# principal.record.recordType,
+# guid=principal.record.guid,
+# shortNames=principal.record.shortNames,
+# fullName=principal.record.fullName,
+# **principal.record.extras
+# ))
</ins><span class="cx">
</span><del>-def action_getValue(rootResource, directory, store, principal, name):
- print("%s for %s is %s" % (
- name,
- prettyPrincipal(principal),
- principal.record.extras[attrMap[name]["attr"]]
- ))
</del><span class="cx">
</span><span class="cx">
</span><ins>+# def action_getValue(rootResource, directory, store, principal, name):
+# print("%s for %s is %s" % (
+# name,
+# prettyPrincipal(principal),
+# principal.record.extras[attrMap[name]["attr"]]
+# ))
</ins><span class="cx">
</span><ins>+
+
</ins><span class="cx"> def abort(msg, status=1):
</span><span class="cx"> sys.stdout.write("%s\n" % (msg,))
</span><span class="cx"> try:
</span><span class="lines">@@ -804,14 +826,16 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def printRecordList(records):
</span><del>- results = [(record.fullName, record.shortNames[0], record.guid)
- for record in records]
</del><ins>+ results = [
+ (record.displayName, record.recordType.name, record.uid, record.shortNames)
+ for record in records
+ ]
</ins><span class="cx"> results.sort()
</span><del>- format = "%-22s %-17s %s"
- print(format % ("Full name", "Record name", "UUID"))
- print(format % ("---------", "-----------", "----"))
- for fullName, shortName, guid in results:
- print(format % (fullName, shortName, guid))
</del><ins>+ format = "%-22s %-10s %-20s %s"
+ print(format % ("Full name", "Type", "UID", "Short names"))
+ print(format % ("---------", "----", "---", "-----------"))
+ for fullName, recordType, uid, shortNames in results:
+ print(format % (fullName, recordType, uid, u", ".join(shortNames)))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whocalendarservertoolsutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py (12834 => 12835)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py        2014-03-06 23:06:36 UTC (rev 12834)
+++ CalendarServer/branches/users/sagen/move2who/calendarserver/tools/util.py        2014-03-07 01:22:21 UTC (rev 12835)
</span><span class="lines">@@ -334,6 +334,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><ins>+@inlineCallbacks
</ins><span class="cx"> def principalForPrincipalID(principalID, checkOnly=False, directory=None):
</span><span class="cx">
</span><span class="cx"> # Allow a directory parameter to be passed in, but default to config.directory
</span><span class="lines">@@ -351,16 +352,16 @@
</span><span class="cx"> raise ValueError("Can't resolve all paths yet")
</span><span class="cx">
</span><span class="cx"> if checkOnly:
</span><del>- return None
</del><ins>+ returnValue(None)
</ins><span class="cx">
</span><del>- return directory.principalCollection.principalForUID(uid)
</del><ins>+ returnValue((yield directory.principalCollection.principalForUID(uid)))
</ins><span class="cx">
</span><span class="cx"> if principalID.startswith("("):
</span><span class="cx"> try:
</span><span class="cx"> i = principalID.index(")")
</span><span class="cx">
</span><span class="cx"> if checkOnly:
</span><del>- return None
</del><ins>+ returnValue(None)
</ins><span class="cx">
</span><span class="cx"> recordType = principalID[1:i]
</span><span class="cx"> shortName = principalID[i + 1:]
</span><span class="lines">@@ -368,34 +369,93 @@
</span><span class="cx"> if not recordType or not shortName or "(" in recordType:
</span><span class="cx"> raise ValueError()
</span><span class="cx">
</span><del>- return directory.principalCollection.principalForShortName(recordType, shortName)
</del><ins>+ returnValue((yield directory.principalCollection.principalForShortName(recordType, shortName)))
</ins><span class="cx">
</span><span class="cx"> except ValueError:
</span><span class="cx"> pass
</span><span class="cx">
</span><span class="cx"> if ":" in principalID:
</span><span class="cx"> if checkOnly:
</span><del>- return None
</del><ins>+ returnValue(None)
</ins><span class="cx">
</span><span class="cx"> recordType, shortName = principalID.split(":", 1)
</span><span class="cx">
</span><del>- return directory.principalCollection.principalForShortName(recordType, shortName)
</del><ins>+ returnValue((yield directory.principalCollection.principalForShortName(recordType, shortName)))
</ins><span class="cx">
</span><span class="cx"> try:
</span><span class="cx"> UUID(principalID)
</span><span class="cx">
</span><span class="cx"> if checkOnly:
</span><del>- return None
</del><ins>+ returnValue(None)
</ins><span class="cx">
</span><del>- x = directory.principalCollection.principalForUID(principalID)
- return x
</del><ins>+ returnValue((yield directory.principalCollection.principalForUID(principalID)))
</ins><span class="cx"> except ValueError:
</span><span class="cx"> pass
</span><span class="cx">
</span><span class="cx"> raise ValueError("Invalid principal identifier: %s" % (principalID,))
</span><span class="cx">
</span><span class="cx">
</span><ins>+@inlineCallbacks
+def recordForPrincipalID(principalID, checkOnly=False, directory=None):
</ins><span class="cx">
</span><ins>+ # 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
+ segments[0] == "principals" and segments[1] == "__uids__"):
+ uid = segments[2]
+ else:
+ raise ValueError("Can't resolve all paths yet")
+
+ if checkOnly:
+ returnValue(None)
+
+ returnValue((yield directory.recordWithUID(uid)))
+
+ if principalID.startswith("("):
+ try:
+ i = principalID.index(")")
+
+ if checkOnly:
+ returnValue(None)
+
+ recordType = directory.oldNameToRecordType(principalID[1:i])
+ shortName = principalID[i + 1:]
+
+ if not recordType or not shortName or "(" in recordType:
+ raise ValueError()
+
+ returnValue((yield directory.recordWithShortName(recordType, shortName)))
+
+ except ValueError:
+ pass
+
+ if ":" in principalID:
+ if checkOnly:
+ returnValue(None)
+
+ recordType, shortName = principalID.split(":", 1)
+ recordType = directory.oldNameToRecordType(recordType)
+
+ returnValue((yield directory.recordWithShortName(recordType, shortName)))
+
+ try:
+ if checkOnly:
+ returnValue(None)
+
+ returnValue((yield directory.recordWithUID(principalID)))
+ except ValueError:
+ pass
+
+ raise ValueError("Invalid principal identifier: %s" % (principalID,))
+
+
+
</ins><span class="cx"> def proxySubprincipal(principal, proxyType):
</span><span class="cx"> return principal.getChild("calendar-proxy-" + proxyType)
</span><span class="cx">
</span><span class="lines">@@ -501,12 +561,19 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def prettyPrincipal(principal):
</span><del>- record = principal.record
- return "\"%s\" (%s:%s)" % (record.fullName, record.recordType,
- record.shortNames[0])
</del><ins>+ prettyRecord(principal.record)
</ins><span class="cx">
</span><span class="cx">
</span><ins>+def prettyRecord(record):
+ return "\"{d}\" {uid} ({rt}) {sn}".format(
+ d=record.displayName,
+ rt=record.recordType.name,
+ uid=record.uid,
+ sn=(", ".join(record.shortNames))
+ )
</ins><span class="cx">
</span><ins>+
+
</ins><span class="cx"> class ProxyError(Exception):
</span><span class="cx"> """
</span><span class="cx"> Raised when proxy assignments cannot be performed
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavdpsclientpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py (12834 => 12835)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py        2014-03-06 23:06:36 UTC (rev 12834)
+++ CalendarServer/branches/users/sagen/move2who/txdav/dps/client.py        2014-03-07 01:22:21 UTC (rev 12835)
</span><span class="lines">@@ -29,12 +29,12 @@
</span><span class="cx"> from twisted.internet.protocol import ClientCreator
</span><span class="cx"> from twisted.protocols import amp
</span><span class="cx"> from twisted.python.constants import Names, NamedConstant
</span><del>-from txdav.caldav.datastore.scheduling.cuaddress import normalizeCUAddr
</del><span class="cx"> from txdav.caldav.icalendardirectoryservice import ICalendarStoreDirectoryRecord
</span><span class="cx"> from txdav.common.idirectoryservice import IStoreDirectoryService
</span><span class="cx"> from txdav.dps.commands import (
</span><span class="cx"> RecordWithShortNameCommand, RecordWithUIDCommand, RecordWithGUIDCommand,
</span><span class="cx"> RecordsWithRecordTypeCommand, RecordsWithEmailAddressCommand,
</span><ins>+ RecordsMatchingTokensCommand,
</ins><span class="cx"> MembersCommand, GroupsCommand, SetMembersCommand,
</span><span class="cx"> VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand
</span><span class="cx"> )
</span><span class="lines">@@ -239,13 +239,15 @@
</span><span class="cx"> )
</span><span class="cx">
</span><span class="cx">
</span><del>- def listRecords(self, recordType):
- # MOVE2WHO
- return []
</del><ins>+ # def listRecords(self, recordType):
+ # # MOVE2WHO
+ # return []
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def recordWithCalendarUserAddress(self, address):
</span><ins>+ # FIXME: Circular
+ from txdav.caldav.datastore.scheduling.cuaddress import normalizeCUAddr
</ins><span class="cx"> address = normalizeCUAddr(address)
</span><span class="cx"> record = None
</span><span class="cx"> if address.startswith("urn:uuid:"):
</span><span class="lines">@@ -270,18 +272,27 @@
</span><span class="cx"> returnValue(record if record and record.hasCalendars else None)
</span><span class="cx">
</span><span class="cx">
</span><del>- @inlineCallbacks
</del><span class="cx"> def recordsMatchingTokens(self, tokens, context=None, limitResults=50,
</span><span class="cx"> timeoutSeconds=10):
</span><del>- rec = yield self.recordWithShortName(
- twext.who.idirectory.RecordType.user,
- u"wsanchez"
</del><ins>+ return self._call(
+ RecordsMatchingTokensCommand,
+ self._processMultipleRecords,
+ tokens=[t.encode("utf-8") for t in tokens],
+ context=context
</ins><span class="cx"> )
</span><del>- returnValue([rec])
</del><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><ins>+ # FIXME: Existing code assumes record type names are plural. Is there any
+ # reason to maintain backwards compatibility? I suppose there could be
+ # scripts referring to record type of "users", "locations"
+ def recordTypeToOldName(self, recordType):
+ return recordType.name + u"s"
</ins><span class="cx">
</span><ins>+ def oldNameToRecordType(self, oldName):
+ return self.recordType.lookupByName(oldName[:-1])
+
+
</ins><span class="cx"> @implementer(ICalendarStoreDirectoryRecord)
</span><span class="cx"> class DirectoryRecord(BaseDirectoryRecord):
</span><span class="cx">
</span><span class="lines">@@ -290,7 +301,7 @@
</span><span class="cx"> def verifyCredentials(self, credentials):
</span><span class="cx">
</span><span class="cx"> # XYZZY REMOVE THIS, it bypasses all authentication!:
</span><del>- # returnValue(True)
</del><ins>+ returnValue(True)
</ins><span class="cx">
</span><span class="cx"> if isinstance(credentials, UsernamePassword):
</span><span class="cx"> log.debug("UsernamePassword")
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavdpscommandspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/dps/commands.py (12834 => 12835)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who/txdav/dps/commands.py        2014-03-06 23:06:36 UTC (rev 12834)
+++ CalendarServer/branches/users/sagen/move2who/txdav/dps/commands.py        2014-03-07 01:22:21 UTC (rev 12835)
</span><span class="lines">@@ -67,7 +67,16 @@
</span><span class="cx"> ]
</span><span class="cx">
</span><span class="cx">
</span><ins>+class RecordsMatchingTokensCommand(amp.Command):
+ arguments = [
+ ('tokens', amp.ListOf(amp.String())),
+ ('context', amp.String(optional=True)),
+ ]
+ response = [
+ ('fieldsList', amp.String()),
+ ]
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> class UpdateRecordsCommand(amp.Command):
</span><span class="cx"> arguments = [
</span><span class="cx"> ('fieldsList', amp.String()),
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavdpsserverpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py (12834 => 12835)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py        2014-03-06 23:06:36 UTC (rev 12834)
+++ CalendarServer/branches/users/sagen/move2who/txdav/dps/server.py        2014-03-07 01:22:21 UTC (rev 12835)
</span><span class="lines">@@ -21,6 +21,9 @@
</span><span class="cx"> from calendarserver.tap.util import getDBPool, storeFromConfig
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> from twext.who.aggregate import DirectoryService as AggregateDirectoryService
</span><ins>+from twext.who.expression import (
+ MatchType, Operand, MatchExpression, CompoundExpression, MatchFlags
+)
</ins><span class="cx"> from twext.who.idirectory import RecordType
</span><span class="cx"> from twext.who.ldap import DirectoryService as LDAPDirectoryService
</span><span class="cx"> from twisted.application import service
</span><span class="lines">@@ -39,6 +42,7 @@
</span><span class="cx"> from txdav.dps.commands import (
</span><span class="cx"> RecordWithShortNameCommand, RecordWithUIDCommand, RecordWithGUIDCommand,
</span><span class="cx"> RecordsWithRecordTypeCommand, RecordsWithEmailAddressCommand,
</span><ins>+ RecordsMatchingTokensCommand,
</ins><span class="cx"> MembersCommand, GroupsCommand, SetMembersCommand,
</span><span class="cx"> VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand,
</span><span class="cx"> # UpdateRecordsCommand, RemoveRecordsCommand
</span><span class="lines">@@ -171,7 +175,48 @@
</span><span class="cx"> returnValue(response)
</span><span class="cx">
</span><span class="cx">
</span><ins>+ @RecordsMatchingTokensCommand.responder
+ @inlineCallbacks
+ def recordsMatchingTokens(self, tokens, context=None):
+ tokens = [t.decode("utf-8") for t in tokens]
</ins><span class="cx">
</span><ins>+ log.debug("RecordsMatchingTokens: {t}", t=(", ".join(tokens)))
+
+ fields = [
+ ("fullNames", MatchType.contains),
+ ("emailAddresses", MatchType.startsWith),
+ ]
+ outer = []
+ for token in tokens:
+ inner = []
+ for name, matchType in fields:
+ inner.append(
+ MatchExpression(
+ self._directory.fieldName.lookupByName(name),
+ token,
+ matchType,
+ MatchFlags.caseInsensitive
+ )
+ )
+ outer.append(
+ CompoundExpression(
+ inner,
+ Operand.OR
+ )
+ )
+ expression = CompoundExpression(outer, Operand.AND)
+ records = yield self._directory.recordsFromExpression(expression)
+
+ fieldsList = []
+ for record in records:
+ fieldsList.append(self.recordToDict(record))
+ response = {
+ "fieldsList": pickle.dumps(fieldsList),
+ }
+ log.debug("Responding with: {response}", response=response)
+ returnValue(response)
+
+
</ins><span class="cx"> @MembersCommand.responder
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def members(self, uid):
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2whotxdavdpstesttest_clientpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who/txdav/dps/test/test_client.py (12834 => 12835)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who/txdav/dps/test/test_client.py        2014-03-06 23:06:36 UTC (rev 12834)
+++ CalendarServer/branches/users/sagen/move2who/txdav/dps/test/test_client.py        2014-03-07 01:22:21 UTC (rev 12835)
</span><span class="lines">@@ -112,6 +112,18 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><ins>+ def test_recordsMatchingTokens(self):
+ records = (yield self.directory.recordsMatchingTokens(
+ [u"anche"]
+ ))
+ self.assertEquals(len(records), 2)
+ self.assertEquals(
+ set([u"__dre__", u"__wsanchez__"]),
+ set([r.uid for r in records])
+ )
+
+
+ @inlineCallbacks
</ins><span class="cx"> def test_verifyPlaintextPassword(self):
</span><span class="cx"> if testMode == "xml":
</span><span class="cx"> expectations = (
</span></span></pre>
</div>
</div>
</body>
</html>