<!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>[13015] CalendarServer/branches/users/sagen/move2who-4</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/13015">13015</a></dd>
<dt>Author</dt> <dd>sagen@apple.com</dd>
<dt>Date</dt> <dd>2014-03-27 19:06:05 -0700 (Thu, 27 Mar 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Port wiki and sharing to twext.who</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServerbranchesuserssagenmove2who4calendarserverplatformdarwinwikipy">CalendarServer/branches/users/sagen/move2who-4/calendarserver/platform/darwin/wiki.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4calendarserverprovisionrootpy">CalendarServer/branches/users/sagen/move2who-4/calendarserver/provision/root.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4calendarservertaputilpy">CalendarServer/branches/users/sagen/move2who-4/calendarserver/tap/util.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4twistedcaldavdirectoryaugmentpy">CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/augment.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4twistedcaldavdirectorycalendarpy">CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/calendar.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4twistedcaldavdirectoryprincipalpy">CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/principal.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4twistedcaldavdirectorywikipy">CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/wiki.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4twistedcaldavsharingpy">CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/sharing.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4twistedcaldavstdconfigpy">CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/stdconfig.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4twistedcaldavstorebridgepy">CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/storebridge.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4twistedcaldavtesttest_sharingpy">CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/test/test_sharing.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4txdavwhoaugmentpy">CalendarServer/branches/users/sagen/move2who-4/txdav/who/augment.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4txdavwhodirectorypy">CalendarServer/branches/users/sagen/move2who-4/txdav/who/directory.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4txdavwhoutilpy">CalendarServer/branches/users/sagen/move2who-4/txdav/who/util.py</a></li>
<li><a href="#CalendarServerbranchesuserssagenmove2who4txdavwhowikipy">CalendarServer/branches/users/sagen/move2who-4/txdav/who/wiki.py</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServerbranchesuserssagenmove2who4calendarserverplatformdarwinwikipy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/calendarserver/platform/darwin/wiki.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/calendarserver/platform/darwin/wiki.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/calendarserver/platform/darwin/wiki.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -27,16 +27,17 @@
</span><span class="cx">
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span><ins>+
</ins><span class="cx"> @inlineCallbacks
</span><del>-def guidForAuthToken(token, host="localhost", port=80):
</del><ins>+def uidForAuthToken(token, host="localhost", port=80):
</ins><span class="cx"> """
</span><span class="cx"> Send a GET request to the web auth service to retrieve the user record
</span><del>- guid associated with the provided auth token.
</del><ins>+ uid associated with the provided auth token.
</ins><span class="cx">
</span><span class="cx"> @param token: An auth token, usually passed in via cookie when webcal
</span><span class="cx"> makes a request.
</span><span class="cx"> @type token: C{str}
</span><del>- @return: deferred returning a guid (C{str}) if successful, or
</del><ins>+ @return: deferred returning a uid (C{str}) if successful, or
</ins><span class="cx"> will raise WebAuthError otherwise.
</span><span class="cx"> """
</span><span class="cx"> url = "http://%s:%d/auth/verify?auth_token=%s" % (host, port, token,)
</span><span class="lines">@@ -44,8 +45,10 @@
</span><span class="cx"> try:
</span><span class="cx"> response = json.loads(jsonResponse)
</span><span class="cx"> except Exception, e:
</span><del>- log.error("Error parsing JSON response from webauth: %s (%s)" %
- (jsonResponse, str(e)))
</del><ins>+ log.error(
+ "Error parsing JSON response from webauth: {resp} {error}",
+ resp=jsonResponse, error=str(e)
+ )
</ins><span class="cx"> raise WebAuthError("Could not look up token: %s" % (token,))
</span><span class="cx"> if response["succeeded"]:
</span><span class="cx"> returnValue(response["generated_uid"])
</span><span class="lines">@@ -57,10 +60,10 @@
</span><span class="cx"> def accessForUserToWiki(user, wiki, host="localhost", port=4444):
</span><span class="cx"> """
</span><span class="cx"> Send a GET request to the wiki collabd service to retrieve the access level
</span><del>- the given user (in GUID form) has to the given wiki (in wiki short-name
</del><ins>+ the given user (uid) has to the given wiki (in wiki short-name
</ins><span class="cx"> form).
</span><span class="cx">
</span><del>- @param user: The GUID of the user
</del><ins>+ @param user: The UID of the user
</ins><span class="cx"> @type user: C{str}
</span><span class="cx"> @param wiki: The short name of the wiki
</span><span class="cx"> @type wiki: C{str}
</span><span class="lines">@@ -69,8 +72,9 @@
</span><span class="cx"> status FORBIDDEN will errBack; an unknown wiki will have a status
</span><span class="cx"> of NOT_FOUND
</span><span class="cx"> """
</span><del>- url = "http://%s:%s/cal/accessLevelForUserWikiCalendar/%s/%s" % (host, port,
- user, wiki)
</del><ins>+ url = "http://%s:%s/cal/accessLevelForUserWikiCalendar/%s/%s" % (
+ host, port, user, wiki
+ )
</ins><span class="cx"> return _getPage(url, host, port)
</span><span class="cx">
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4calendarserverprovisionrootpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/calendarserver/provision/root.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/calendarserver/provision/root.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/calendarserver/provision/root.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -19,29 +19,29 @@
</span><span class="cx"> "RootResource",
</span><span class="cx"> ]
</span><span class="cx">
</span><ins>+from calendarserver.platform.darwin.wiki import uidForAuthToken
</ins><span class="cx"> from twext.python.log import Logger
</span><del>-from txweb2 import responsecode
-from txweb2.auth.wrapper import UnauthorizedResponse
-from txdav.xml import element as davxml
-from txweb2.dav.xattrprops import xattrPropertyStore
-from txweb2.http import HTTPError, StatusResponse, RedirectResponse
-
</del><ins>+from twext.who.idirectory import RecordType
</ins><span class="cx"> from twisted.cred.error import LoginFailed, UnauthorizedLogin
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, returnValue, succeed
</span><span class="cx"> from twisted.python.reflect import namedClass
</span><ins>+from twisted.web.error import Error as WebError
</ins><span class="cx"> from twisted.web.xmlrpc import Proxy
</span><del>-from twisted.web.error import Error as WebError
-
</del><ins>+from twistedcaldav.cache import DisabledCache
+from twistedcaldav.cache import MemcacheResponseCache, MemcacheChangeNotifier
</ins><span class="cx"> from twistedcaldav.cache import _CachedResponseResource
</span><del>-from twistedcaldav.cache import MemcacheResponseCache, MemcacheChangeNotifier
-from twistedcaldav.cache import DisabledCache
</del><span class="cx"> from twistedcaldav.config import config
</span><ins>+from twistedcaldav.directory.principal import DirectoryPrincipalResource
</ins><span class="cx"> from twistedcaldav.extensions import DAVFile, CachingPropertyStore
</span><span class="cx"> from twistedcaldav.extensions import DirectoryPrincipalPropertySearchMixIn
</span><span class="cx"> from twistedcaldav.extensions import ReadOnlyResourceMixIn
</span><span class="cx"> from twistedcaldav.resource import CalDAVComplianceMixIn
</span><del>-from twistedcaldav.directory.principal import DirectoryPrincipalResource
-from calendarserver.platform.darwin.wiki import guidForAuthToken
</del><ins>+from txdav.who.wiki import DirectoryService as WikiDirectoryService
+from txdav.xml import element as davxml
+from txweb2 import responsecode
+from txweb2.auth.wrapper import UnauthorizedResponse
+from txweb2.dav.xattrprops import xattrPropertyStore
+from txweb2.http import HTTPError, StatusResponse, RedirectResponse
</ins><span class="cx">
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span><span class="lines">@@ -234,20 +234,20 @@
</span><span class="cx"> record = None
</span><span class="cx"> try:
</span><span class="cx"> if wikiConfig.LionCompatibility:
</span><del>- guid = None
</del><ins>+ uid = None
</ins><span class="cx"> proxy = Proxy(wikiConfig["URL"])
</span><span class="cx"> username = (yield proxy.callRemote(wikiConfig["UserMethod"], token))
</span><span class="cx"> directory = request.site.resource.getDirectory()
</span><del>- record = directory.recordWithShortName("users", username)
</del><ins>+ record = yield directory.recordWithShortName(RecordType.user, username)
</ins><span class="cx"> if record is not None:
</span><del>- guid = record.guid
</del><ins>+ uid = record.uid
</ins><span class="cx"> else:
</span><del>- guid = (yield guidForAuthToken(token))
- if guid == "unauthenticated":
- guid = None
</del><ins>+ uid = (yield uidForAuthToken(token))
+ if uid == "unauthenticated":
+ uid = None
</ins><span class="cx">
</span><span class="cx"> except WebError, w:
</span><del>- guid = None
</del><ins>+ uid = None
</ins><span class="cx"> # FORBIDDEN status means it's an unknown token
</span><span class="cx"> if int(w.status) == responsecode.NOT_FOUND:
</span><span class="cx"> log.debug("Unknown wiki token: %s" % (token,))
</span><span class="lines">@@ -257,18 +257,18 @@
</span><span class="cx">
</span><span class="cx"> except Exception, e:
</span><span class="cx"> log.error("Failed to look up wiki token (%s)" % (e,))
</span><del>- guid = None
</del><ins>+ uid = None
</ins><span class="cx">
</span><del>- if guid is not None:
- log.debug("Wiki lookup returned guid: %s" % (guid,))
</del><ins>+ if uid is not None:
+ log.debug("Wiki lookup returned uid: %s" % (uid,))
</ins><span class="cx"> principal = None
</span><span class="cx"> directory = request.site.resource.getDirectory()
</span><del>- record = directory.recordWithGUID(guid)
</del><ins>+ record = yield directory.recordWithUID(uid)
</ins><span class="cx"> if record is not None:
</span><span class="cx"> username = record.shortNames[0]
</span><span class="cx"> log.debug("Wiki user record for user %s : %s" % (username, record))
</span><span class="cx"> for collection in self.principalCollections():
</span><del>- principal = collection.principalForRecord(record)
</del><ins>+ principal = yield collection.principalForRecord(record)
</ins><span class="cx"> if principal is not None:
</span><span class="cx"> break
</span><span class="cx">
</span><span class="lines">@@ -317,7 +317,7 @@
</span><span class="cx"> elif (len(segments) > 2 and segments[0] in ("calendars", "principals") and
</span><span class="cx"> (
</span><span class="cx"> segments[1] == "wikis" or
</span><del>- (segments[1] == "__uids__" and segments[2].startswith("wiki-"))
</del><ins>+ (segments[1] == "__uids__" and segments[2].startswith(WikiDirectoryService.uidPrefix))
</ins><span class="cx"> )
</span><span class="cx"> ):
</span><span class="cx"> # This is a wiki-related calendar resource. SACLs are not checked.
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4calendarservertaputilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/calendarserver/tap/util.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/calendarserver/tap/util.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/calendarserver/tap/util.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -28,7 +28,6 @@
</span><span class="cx">
</span><span class="cx"> import errno
</span><span class="cx"> import os
</span><del>-from time import sleep
</del><span class="cx"> from socket import fromfd, AF_UNIX, SOCK_STREAM, socketpair
</span><span class="cx"> import psutil
</span><span class="cx">
</span><span class="lines">@@ -46,17 +45,13 @@
</span><span class="cx"> from twisted.internet import reactor as _reactor
</span><span class="cx"> from twisted.internet.reactor import addSystemEventTrigger
</span><span class="cx"> from twisted.internet.tcp import Connection
</span><del>-from twisted.python.reflect import namedClass
-# from twisted.python.failure import Failure
</del><span class="cx">
</span><span class="cx"> from twistedcaldav.bind import doBind
</span><span class="cx"> from twistedcaldav.cache import CacheStoreNotifierFactory
</span><del>-from twistedcaldav.directory import calendaruserproxy
</del><span class="cx"> from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeProvisioningResource
</span><span class="cx"> from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
</span><span class="cx"> from twistedcaldav.directory.digest import QopDigestCredentialFactory
</span><span class="cx"> from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
</span><del>-from twistedcaldav.directory.wiki import WikiDirectoryService
</del><span class="cx"> from calendarserver.push.notifier import NotifierFactory
</span><span class="cx"> from calendarserver.push.applepush import APNSubscriptionResource
</span><span class="cx"> from twistedcaldav.directorybackedaddressbook import DirectoryBackedAddressBookResource
</span><span class="lines">@@ -98,8 +93,6 @@
</span><span class="cx"> from urllib import quote
</span><span class="cx"> from twisted.python.usage import UsageError
</span><span class="cx">
</span><del>-from txdav.dps.client import DirectoryService as DirectoryProxyClientService
-
</del><span class="cx"> from twext.who.checker import UsernamePasswordCredentialChecker
</span><span class="cx"> from twext.who.checker import HTTPDigestCredentialChecker
</span><span class="cx"> from twisted.cred.error import UnauthorizedLogin
</span><span class="lines">@@ -281,96 +274,6 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-def REMOVEMEdirectoryFromConfig(config):
- """
- Create an L{AggregateDirectoryService} from the given configuration.
- """
-
- #
- # 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
-
- #
- # Setup the group membership cacher
- #
- if config.GroupCaching.Enabled:
- groupMembershipCache = GroupMembershipCache(
- config.GroupCaching.MemcachedPool,
- expireSeconds=config.GroupCaching.ExpireSeconds)
- else:
- groupMembershipCache = None
-
- #
- # Setup the Directory
- #
- directories = []
-
- directoryClass = namedClass(config.DirectoryService.type)
- principalResourceClass = DirectoryPrincipalProvisioningResource
-
- log.info("Configuring directory service of type: {directoryType}",
- directoryType=config.DirectoryService.type)
-
- config.DirectoryService.params.augmentService = augmentService
- config.DirectoryService.params.groupMembershipCache = groupMembershipCache
- baseDirectory = directoryClass(config.DirectoryService.params)
-
- # Wait for the directory to become available
- while not baseDirectory.isAvailable():
- sleep(5)
-
- directories.append(baseDirectory)
-
- #
- # Setup the Locations and Resources Service
- #
- if config.ResourceService.Enabled:
- resourceClass = namedClass(config.ResourceService.type)
-
- log.info("Configuring resource service of type: {resourceClass}",
- resourceClass=resourceClass)
-
- config.ResourceService.params.augmentService = augmentService
- config.ResourceService.params.groupMembershipCache = groupMembershipCache
- resourceDirectory = resourceClass(config.ResourceService.params)
- resourceDirectory.realmName = baseDirectory.realmName
- directories.append(resourceDirectory)
-
- #
- # Add wiki directory service
- #
- if config.Authentication.Wiki.Enabled:
- wikiDirectory = WikiDirectoryService()
- wikiDirectory.realmName = baseDirectory.realmName
- directories.append(wikiDirectory)
-
- directory = AggregateDirectoryService(directories, groupMembershipCache)
-
- #
- # Use system-wide realm on OSX
- #
- try:
- import ServerFoundation
- realmName = ServerFoundation.XSAuthenticator.defaultRealm().encode("utf-8")
- directory.setRealm(realmName)
- except ImportError:
- pass
- log.info("Setting up principal collection: {cls}", cls=principalResourceClass)
- principalResourceClass("/principals/", directory)
- return directory
-
-
</del><span class="cx"> # MOVE2WHO -- should we move this class somewhere else?
</span><span class="cx"> class PrincipalCredentialChecker(object):
</span><span class="cx"> credentialInterfaces = (IPrincipalCredentials,)
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4twistedcaldavdirectoryaugmentpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/augment.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/augment.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/augment.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -81,6 +81,7 @@
</span><span class="cx"> "locations": "Location",
</span><span class="cx"> "resources": "Resource",
</span><span class="cx"> "addresses": "Address",
</span><ins>+ "wikis": "Wiki",
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4twistedcaldavdirectorycalendarpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/calendar.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/calendar.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/calendar.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -38,7 +38,7 @@
</span><span class="cx"> from twistedcaldav.directory.common import uidsResourceName, \
</span><span class="cx"> CommonUIDProvisioningResource, CommonHomeTypeProvisioningResource
</span><span class="cx">
</span><del>-from twistedcaldav.directory.wiki import getWikiACL
</del><ins>+from txdav.who.wiki import getWikiACL
</ins><span class="cx"> from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource, \
</span><span class="cx"> DAVResourceWithChildrenMixin
</span><span class="cx"> from twistedcaldav.resource import CalendarHomeResource
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4twistedcaldavdirectoryprincipalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/principal.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/principal.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/principal.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx"> from twistedcaldav.directory.util import (
</span><span class="cx"> formatLink, formatLinks, formatPrincipals, formatList
</span><span class="cx"> )
</span><del>-from twistedcaldav.directory.wiki import getWikiACL
</del><ins>+from txdav.who.wiki import getWikiACL
</ins><span class="cx"> from twistedcaldav.extensions import (
</span><span class="cx"> ReadOnlyResourceMixIn, DAVPrincipalResource, DAVResourceWithChildrenMixin
</span><span class="cx"> )
</span><span class="lines">@@ -1308,6 +1308,7 @@
</span><span class="cx"> Return a CUA for this principal, preferring in this order:
</span><span class="cx"> urn:uuid: form
</span><span class="cx"> mailto: form
</span><ins>+ /principal/__uids__/ form
</ins><span class="cx"> first in calendarUserAddresses( ) list
</span><span class="cx"> """
</span><span class="cx"> return self.record.canonicalCalendarUserAddress()
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4twistedcaldavdirectorywikipy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/wiki.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/wiki.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/directory/wiki.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -250,8 +250,8 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-def getWikiACL(resource, request):
- return succeed(None)
</del><ins>+# def getWikiACL(resource, request):
+# return succeed(None)
</ins><span class="cx"> # @inlineCallbacks
</span><span class="cx"> # def getWikiACL(resource, request):
</span><span class="cx"> # """
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4twistedcaldavsharingpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/sharing.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/sharing.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/sharing.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx"> from twistedcaldav import customxml, caldavxml
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.customxml import calendarserver_namespace
</span><del>-from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
</del><ins>+from txdav.who.wiki import RecordType as WikiRecordType, WikiAccessLevel
</ins><span class="cx"> from twistedcaldav.linkresource import LinkFollowerMixIn
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -269,15 +269,13 @@
</span><span class="cx"> if self._newStoreObject.direct():
</span><span class="cx"> owner = yield self.principalForUID(self._newStoreObject.ownerHome().uid())
</span><span class="cx"> sharee = yield self.principalForUID(self._newStoreObject.viewerHome().uid())
</span><del>- if owner.record.recordType == WikiDirectoryService.recordType_wikis:
</del><ins>+ if owner.record.recordType == WikiRecordType.macOSXServerWiki:
</ins><span class="cx"> # Access level comes from what the wiki has granted to the
</span><span class="cx"> # sharee
</span><del>- userID = sharee.record.guid
- wikiID = owner.record.shortNames[0]
- access = (yield getWikiAccess(userID, wikiID))
- if access == "read":
</del><ins>+ access = (yield owner.record.accessForRecord(sharee.record))
+ if access == WikiAccessLevel.read:
</ins><span class="cx"> returnValue("read-only")
</span><del>- elif access in ("write", "admin"):
</del><ins>+ elif access == WikiAccessLevel.write:
</ins><span class="cx"> returnValue("read-write")
</span><span class="cx"> else:
</span><span class="cx"> returnValue(None)
</span><span class="lines">@@ -502,7 +500,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def inviteSingleUserToShare(self, userid, cn, ace, summary, request): #@UnusedVariable
</del><ins>+ def inviteSingleUserToShare(self, userid, cn, ace, summary, request): #@UnusedVariable
</ins><span class="cx">
</span><span class="cx"> # We currently only handle local users
</span><span class="cx"> sharee = yield self.principalForCalendarUserAddress(userid)
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4twistedcaldavstdconfigpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/stdconfig.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/stdconfig.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/stdconfig.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -1257,7 +1257,13 @@
</span><span class="cx">
</span><span class="cx"> # Default DirectoryRealmName from ServerHostName
</span><span class="cx"> if not configDict.DirectoryRealmName:
</span><del>- configDict.DirectoryRealmName = configDict.ServerHostName
</del><ins>+ # Use system-wide realm on OSX
+ try:
+ import ServerFoundation
+ realmName = ServerFoundation.XSAuthenticator.defaultRealm()
+ configDict.DirectoryRealmName = realmName
+ except ImportError:
+ configDict.DirectoryRealmName = configDict.ServerHostName
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4twistedcaldavstorebridgepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/storebridge.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/storebridge.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/storebridge.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -15,77 +15,89 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx">
</span><ins>+import collections
+import hashlib
+import time
+from urlparse import urlsplit, urljoin
+import uuid
+
</ins><span class="cx"> from pycalendar.datetime import DateTime
</span><del>-
</del><span class="cx"> from twext.enterprise.locking import LockTimeout
</span><span class="cx"> from twext.python.log import Logger
</span><del>-from txweb2 import responsecode, http_headers, http
-from txweb2.dav.http import ErrorResponse, ResponseQueue, MultiStatusResponse
-from txweb2.dav.noneprops import NonePropertyStore
-from txweb2.dav.resource import TwistedACLInheritable, AccessDeniedError, \
- davPrivilegeSet
-from txweb2.dav.util import parentForURL, allDataFromStream, joinURL, davXMLFromStream
-from txweb2.filter.location import addLocation
-from txweb2.http import HTTPError, StatusResponse, Response
-from txweb2.http_headers import ETag, MimeType, MimeDisposition
-from txweb2.iweb import IResponse
-from txweb2.responsecode import \
- FORBIDDEN, NO_CONTENT, NOT_FOUND, CREATED, CONFLICT, PRECONDITION_FAILED, \
- BAD_REQUEST, OK, INSUFFICIENT_STORAGE_SPACE, SERVICE_UNAVAILABLE
-from txweb2.stream import ProducerStream, readStream, MemoryStream
-
</del><span class="cx"> from twisted.internet.defer import succeed, inlineCallbacks, returnValue, maybeDeferred
</span><span class="cx"> from twisted.internet.protocol import Protocol
</span><span class="cx"> from twisted.python.hashlib import md5
</span><span class="cx"> from twisted.python.util import FancyEqMixin
</span><del>-
</del><span class="cx"> from twistedcaldav import customxml, carddavxml, caldavxml, ical
</span><del>-from twistedcaldav.caldavxml import caldav_namespace, MaxAttendeesPerInstance, \
- MaxInstances, NoUIDConflict
</del><ins>+from twistedcaldav.caldavxml import (
+ caldav_namespace, MaxAttendeesPerInstance, MaxInstances, NoUIDConflict
+)
</ins><span class="cx"> from twistedcaldav.carddavxml import carddav_namespace, NoUIDConflict as NovCardUIDConflict
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.customxml import calendarserver_namespace
</span><del>-from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
-from twistedcaldav.ical import Component as VCalendar, Property as VProperty, \
- InvalidICalendarDataError, iCalendarProductID, Component
-from twistedcaldav.instance import InvalidOverriddenInstanceError, \
- TooManyInstancesError
</del><ins>+from twistedcaldav.ical import (
+ Component as VCalendar, Property as VProperty, InvalidICalendarDataError,
+ iCalendarProductID, Component
+)
+from twistedcaldav.instance import (
+ InvalidOverriddenInstanceError, TooManyInstancesError
+)
</ins><span class="cx"> from twistedcaldav.memcachelock import MemcacheLockTimeoutError
</span><span class="cx"> from twistedcaldav.notifications import NotificationCollectionResource, NotificationResource
</span><span class="cx"> from twistedcaldav.resource import CalDAVResource, DefaultAlarmPropertyMixin
</span><span class="cx"> from twistedcaldav.scheduling_store.caldav.resource import ScheduleInboxResource
</span><del>-from twistedcaldav.sharing import invitationBindStatusToXMLMap, \
- invitationBindModeToXMLMap
</del><ins>+from twistedcaldav.sharing import (
+ invitationBindStatusToXMLMap, invitationBindModeToXMLMap
+)
</ins><span class="cx"> from twistedcaldav.util import bestAcceptType
</span><span class="cx"> from twistedcaldav.vcard import Component as VCard, InvalidVCardDataError
</span><del>-
</del><span class="cx"> from txdav.base.propertystore.base import PropertyName
</span><del>-from txdav.caldav.icalendarstore import QuotaExceeded, AttachmentStoreFailed, \
- AttachmentStoreValidManagedID, AttachmentRemoveFailed, \
- AttachmentDropboxNotAllowed, InvalidComponentTypeError, \
- TooManyAttendeesError, InvalidCalendarAccessError, ValidOrganizerError, \
- InvalidPerUserDataMerge, \
- AttendeeAllowedError, ResourceDeletedError, InvalidAttachmentOperation, \
</del><ins>+from txdav.caldav.icalendarstore import (
+ QuotaExceeded, AttachmentStoreFailed,
+ AttachmentStoreValidManagedID, AttachmentRemoveFailed,
+ AttachmentDropboxNotAllowed, InvalidComponentTypeError,
+ TooManyAttendeesError, InvalidCalendarAccessError, ValidOrganizerError,
+ InvalidPerUserDataMerge,
+ AttendeeAllowedError, ResourceDeletedError, InvalidAttachmentOperation,
</ins><span class="cx"> ShareeAllowedError, DuplicatePrivateCommentsError, InvalidSplit
</span><del>-from txdav.carddav.iaddressbookstore import KindChangeNotAllowedError, \
- GroupWithUnsharedAddressNotAllowedError
-from txdav.common.datastore.sql_tables import _BIND_MODE_READ, _BIND_MODE_WRITE, \
</del><ins>+)
+from txdav.carddav.iaddressbookstore import (
+ KindChangeNotAllowedError, GroupWithUnsharedAddressNotAllowedError
+)
+from txdav.common.datastore.sql_tables import (
+ _BIND_MODE_READ, _BIND_MODE_WRITE,
</ins><span class="cx"> _BIND_MODE_DIRECT, _BIND_STATUS_ACCEPTED
</span><del>-from txdav.common.icommondatastore import NoSuchObjectResourceError, \
- TooManyObjectResourcesError, ObjectResourceTooBigError, \
- InvalidObjectResourceError, ObjectResourceNameNotAllowedError, \
- ObjectResourceNameAlreadyExistsError, UIDExistsError, \
- UIDExistsElsewhereError, InvalidUIDError, InvalidResourceMove, \
</del><ins>+)
+from txdav.common.icommondatastore import (
+ NoSuchObjectResourceError,
+ TooManyObjectResourcesError, ObjectResourceTooBigError,
+ InvalidObjectResourceError, ObjectResourceNameNotAllowedError,
+ ObjectResourceNameAlreadyExistsError, UIDExistsError,
+ UIDExistsElsewhereError, InvalidUIDError, InvalidResourceMove,
</ins><span class="cx"> InvalidComponentForStoreError
</span><ins>+)
</ins><span class="cx"> from txdav.idav import PropertyChangeNotAllowedError
</span><ins>+from txdav.who.wiki import RecordType as WikiRecordType
</ins><span class="cx"> from txdav.xml import element as davxml, element
</span><span class="cx"> from txdav.xml.base import dav_namespace, WebDAVUnknownElement, encodeXMLName
</span><ins>+from txweb2 import responsecode, http_headers, http
+from txweb2.dav.http import ErrorResponse, ResponseQueue, MultiStatusResponse
+from txweb2.dav.noneprops import NonePropertyStore
+from txweb2.dav.resource import (
+ TwistedACLInheritable, AccessDeniedError, davPrivilegeSet
+)
+from txweb2.dav.util import parentForURL, allDataFromStream, joinURL, davXMLFromStream
+from txweb2.filter.location import addLocation
+from txweb2.http import HTTPError, StatusResponse, Response
+from txweb2.http_headers import ETag, MimeType, MimeDisposition
+from txweb2.iweb import IResponse
+from txweb2.responsecode import (
+ FORBIDDEN, NO_CONTENT, NOT_FOUND, CREATED, CONFLICT, PRECONDITION_FAILED,
+ BAD_REQUEST, OK, INSUFFICIENT_STORAGE_SPACE, SERVICE_UNAVAILABLE
+)
+from txweb2.stream import ProducerStream, readStream, MemoryStream
</ins><span class="cx">
</span><del>-from urlparse import urlsplit, urljoin
-import collections
-import hashlib
-import time
-import uuid
</del><ins>+
</ins><span class="cx"> """
</span><span class="cx"> Wrappers to translate between the APIs in L{txdav.caldav.icalendarstore} and
</span><span class="cx"> L{txdav.carddav.iaddressbookstore} and those in L{twistedcaldav}.
</span><span class="lines">@@ -93,6 +105,7 @@
</span><span class="cx">
</span><span class="cx"> log = Logger()
</span><span class="cx">
</span><ins>+
</ins><span class="cx"> class _NewStorePropertiesWrapper(object):
</span><span class="cx"> """
</span><span class="cx"> Wrap a new-style property store (a L{txdav.idav.IPropertyStore}) in the old-
</span><span class="lines">@@ -1983,15 +1996,13 @@
</span><span class="cx"> """
</span><span class="cx"> if invite.mode in (_BIND_MODE_DIRECT,):
</span><span class="cx"> ownerUID = invite.ownerUID
</span><del>- owner = self.principalForUID(ownerUID)
</del><ins>+ owner = yield self.principalForUID(ownerUID)
</ins><span class="cx"> shareeUID = invite.shareeUID
</span><del>- if owner.record.recordType == WikiDirectoryService.recordType_wikis:
</del><ins>+ if owner.record.recordType == WikiRecordType.macOSXServerWiki:
</ins><span class="cx"> # Access level comes from what the wiki has granted to the
</span><span class="cx"> # sharee
</span><del>- sharee = self.principalForUID(shareeUID)
- userID = sharee.record.uid
- wikiID = owner.record.shortNames[0]
- access = (yield getWikiAccess(userID, wikiID))
</del><ins>+ sharee = yield self.principalForUID(shareeUID)
+ access = (yield owner.record.accessForRecord(sharee.record))
</ins><span class="cx"> if access == "read":
</span><span class="cx"> returnValue("read-only")
</span><span class="cx"> elif access in ("write", "admin"):
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4twistedcaldavtesttest_sharingpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/test/test_sharing.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/test/test_sharing.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/twistedcaldav/test/test_sharing.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -19,30 +19,31 @@
</span><span class="cx"> from txweb2.http_headers import MimeType
</span><span class="cx"> from txweb2.iweb import IResponse
</span><span class="cx">
</span><del>-from twisted.internet.defer import inlineCallbacks, returnValue
</del><ins>+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
</ins><span class="cx">
</span><span class="cx"> from twistedcaldav import customxml
</span><del>-from twistedcaldav import sharing
</del><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.directory.principal import DirectoryCalendarPrincipalResource
</span><del>-from twistedcaldav.resource import CalDAVResource
-from twistedcaldav.sharing import WikiDirectoryService
</del><span class="cx"> from twistedcaldav.test.test_cache import StubResponseCacheResource
</span><span class="cx"> from twistedcaldav.test.util import norequest, StoreTestCase, SimpleStoreRequest
</span><span class="cx">
</span><del>-from txdav.caldav.datastore.test.util import buildDirectory
</del><span class="cx"> from txdav.common.datastore.sql_tables import _BIND_MODE_DIRECT
</span><span class="cx"> from txdav.xml import element as davxml
</span><span class="cx"> from txdav.xml.parser import WebDAVDocument
</span><span class="cx">
</span><span class="cx"> from xml.etree.cElementTree import XML
</span><ins>+from txdav.who.wiki import (
+ DirectoryRecord as WikiDirectoryRecord,
+ DirectoryService as WikiDirectoryService,
+ RecordType as WikiRecordType,
+ WikiAccessLevel
+)
</ins><span class="cx">
</span><ins>+sharedOwnerType = davxml.ResourceType.sharedownercalendar # @UndefinedVariable
+regularCalendarType = davxml.ResourceType.calendar # @UndefinedVariable
</ins><span class="cx">
</span><del>-sharedOwnerType = davxml.ResourceType.sharedownercalendar #@UndefinedVariable
-regularCalendarType = davxml.ResourceType.calendar #@UndefinedVariable
</del><span class="cx">
</span><span class="cx">
</span><del>-
</del><span class="cx"> def normalize(x):
</span><span class="cx"> """
</span><span class="cx"> Normalize some XML by parsing it, collapsing whitespace, and
</span><span class="lines">@@ -63,8 +64,8 @@
</span><span class="cx"> self.fullName = name
</span><span class="cx"> self.guid = name
</span><span class="cx"> self.calendarUserAddresses = set((cuaddr,))
</span><del>- if name.startswith("wiki-"):
- recordType = WikiDirectoryService.recordType_wikis
</del><ins>+ if name.startswith(WikiDirectoryService.uidPrefix):
+ recordType = WikiRecordType.macOSXServerWiki
</ins><span class="cx"> else:
</span><span class="cx"> recordType = None
</span><span class="cx"> self.recordType = recordType
</span><span class="lines">@@ -131,42 +132,45 @@
</span><span class="cx"> super(SharingTests, self).configure()
</span><span class="cx"> self.patch(config.Sharing, "Enabled", True)
</span><span class="cx"> self.patch(config.Sharing.Calendars, "Enabled", True)
</span><ins>+ self.patch(config.Authentication.Wiki, "Enabled", True)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def setUp(self):
</span><span class="cx"> yield super(SharingTests, self).setUp()
</span><span class="cx">
</span><del>- def patched(c):
- """
- The decorated method is patched on L{CalDAVResource} for the
- duration of the test.
- """
- self.patch(CalDAVResource, c.__name__, c)
- return c
</del><ins>+ # FIXME: not sure what these were for:
</ins><span class="cx">
</span><del>- @patched
- def principalForCalendarUserAddress(resourceSelf, cuaddr):
- if "bogus" in cuaddr:
- return None
- else:
- return FakePrincipal(cuaddr, self)
</del><ins>+ # def patched(c):
+ # """
+ # The decorated method is patched on L{CalDAVResource} for the
+ # duration of the test.
+ # """
+ # self.patch(CalDAVResource, c.__name__, c)
+ # return c
</ins><span class="cx">
</span><del>- @patched
- def validUserIDForShare(resourceSelf, userid, request):
- """
- Temporary replacement for L{CalDAVResource.validUserIDForShare}
- that marks any principal without 'bogus' in its name.
- """
- result = principalForCalendarUserAddress(resourceSelf, userid)
- if result is None:
- return result
- return result.principalURL()
</del><ins>+ # @patched
+ # def principalForCalendarUserAddress(resourceSelf, cuaddr):
+ # if "bogus" in cuaddr:
+ # return None
+ # else:
+ # return FakePrincipal(cuaddr, self)
</ins><span class="cx">
</span><del>- @patched
- def principalForUID(resourceSelf, principalUID):
- return FakePrincipal("urn:uuid:" + principalUID, self)
</del><ins>+ # @patched
+ # def validUserIDForShare(resourceSelf, userid, request):
+ # """
+ # Temporary replacement for L{CalDAVResource.validUserIDForShare}
+ # that marks any principal without 'bogus' in its name.
+ # """
+ # result = principalForCalendarUserAddress(resourceSelf, userid)
+ # if result is None:
+ # return result
+ # return result.principalURL()
</ins><span class="cx">
</span><ins>+ # @patched
+ # def principalForUID(resourceSelf, principalUID):
+ # return FakePrincipal("urn:uuid:" + principalUID, self)
+
</ins><span class="cx"> self.resource = yield self._getResource()
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -321,7 +325,7 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> )
</span><span class="lines">@@ -351,7 +355,7 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> )
</span><span class="lines">@@ -400,7 +404,7 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> )
</span><span class="lines">@@ -475,21 +479,21 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user03"),
</span><del>- customxml.CommonName.fromString("USER03"),
</del><ins>+ customxml.CommonName.fromString("User 03"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user04"),
</span><del>- customxml.CommonName.fromString("USER04"),
</del><ins>+ customxml.CommonName.fromString("User 04"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span><span class="lines">@@ -533,14 +537,14 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user04"),
</span><del>- customxml.CommonName.fromString("USER04"),
</del><ins>+ customxml.CommonName.fromString("User 04"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span><span class="lines">@@ -584,14 +588,14 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user03"),
</span><del>- customxml.CommonName.fromString("USER03"),
</del><ins>+ customxml.CommonName.fromString("User 03"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span><span class="lines">@@ -701,7 +705,7 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> )
</span><span class="lines">@@ -738,23 +742,24 @@
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def wikiSetup(self):
</span><span class="cx"> """
</span><del>- Create a wiki called C{wiki-testing}, and share it with the user whose
</del><ins>+ Create a wiki called C{[wiki]testing}, and share it with the user whose
</ins><span class="cx"> home is at /. Return the name of the newly shared calendar in the
</span><span class="cx"> sharee's home.
</span><span class="cx"> """
</span><span class="cx">
</span><del>- self._sqlCalendarStore._directoryService = buildDirectory(homes=("wiki-testing",))
</del><ins>+ # self._sqlCalendarStore._directoryService = buildDirectory(homes=("wiki-testing",))
</ins><span class="cx"> wcreate = self._sqlCalendarStore.newTransaction("create wiki")
</span><del>- yield wcreate.calendarHomeWithUID("wiki-testing", create=True)
</del><ins>+ yield wcreate.calendarHomeWithUID(
+ u"{prefix}testing".format(prefix=WikiDirectoryService.uidPrefix),
+ create=True
+ )
</ins><span class="cx"> yield wcreate.commit()
</span><span class="cx">
</span><del>- newService = WikiDirectoryService()
- newService.realmName = self.directory.realmName
- self.directory.addService(newService)
-
</del><span class="cx"> txn = self.transactionUnderTest()
</span><del>- sharee = yield self.homeUnderTest(name="user01")
- sharer = yield txn.calendarHomeWithUID("wiki-testing")
</del><ins>+ sharee = yield self.homeUnderTest(name="user01", create=True)
+ sharer = yield txn.calendarHomeWithUID(
+ u"{prefix}testing".format(prefix=WikiDirectoryService.uidPrefix),
+ )
</ins><span class="cx"> cal = yield sharer.calendarWithName("calendar")
</span><span class="cx"> sharedName = yield cal.shareWith(sharee, _BIND_MODE_DIRECT)
</span><span class="cx"> returnValue(sharedName)
</span><span class="lines">@@ -767,13 +772,14 @@
</span><span class="cx"> to the sharee, so that delegates of the sharee get the same level of
</span><span class="cx"> access.
</span><span class="cx"> """
</span><ins>+ sharedName = yield self.wikiSetup()
+ access = WikiAccessLevel.read
</ins><span class="cx">
</span><del>- access = "read"
- def stubWikiAccessMethod(userID, wikiID):
- return access
- self.patch(sharing, "getWikiAccess", stubWikiAccessMethod)
</del><ins>+ def stubAccessForRecord(*args):
+ return succeed(access)
</ins><span class="cx">
</span><del>- sharedName = yield self.wikiSetup()
</del><ins>+ self.patch(WikiDirectoryRecord, "accessForRecord", stubAccessForRecord)
+
</ins><span class="cx"> request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/")
</span><span class="cx"> collection = yield request.locateResource("/calendars/__uids__/user01/" + sharedName)
</span><span class="cx">
</span><span class="lines">@@ -782,7 +788,7 @@
</span><span class="cx"> self.assertFalse("<write/>" in acl.toxml())
</span><span class="cx">
</span><span class="cx"> # Simulate the wiki server granting Read-Write access
</span><del>- access = "write"
</del><ins>+ access = WikiAccessLevel.write
</ins><span class="cx"> acl = (yield collection.shareeAccessControlList(request))
</span><span class="cx"> self.assertTrue("<write/>" in acl.toxml())
</span><span class="cx">
</span><span class="lines">@@ -795,10 +801,13 @@
</span><span class="cx"> un-share that collection.
</span><span class="cx"> """
</span><span class="cx"> sharedName = yield self.wikiSetup()
</span><del>- access = "write"
- def stubWikiAccessMethod(userID, wikiID):
- return access
- self.patch(sharing, "getWikiAccess", stubWikiAccessMethod)
</del><ins>+ access = WikiAccessLevel.write
+
+ def stubAccessForRecord(*args):
+ return succeed(access)
+
+ self.patch(WikiDirectoryRecord, "accessForRecord", stubAccessForRecord)
+
</ins><span class="cx"> @inlineCallbacks
</span><span class="cx"> def listChildrenViaPropfind():
</span><span class="cx"> authRecord = yield self.directory.recordWithUID(u"user01")
</span><span class="lines">@@ -814,9 +823,10 @@
</span><span class="cx"> seq.remove(shortest)
</span><span class="cx"> filtered = [elem[len(shortest):].rstrip("/") for elem in seq]
</span><span class="cx"> returnValue(filtered)
</span><ins>+
</ins><span class="cx"> childNames = yield listChildrenViaPropfind()
</span><span class="cx"> self.assertIn(sharedName, childNames)
</span><del>- access = "no-access"
</del><ins>+ access = WikiAccessLevel.none
</ins><span class="cx"> childNames = yield listChildrenViaPropfind()
</span><span class="cx"> self.assertNotIn(sharedName, childNames)
</span><span class="cx">
</span><span class="lines">@@ -841,7 +851,7 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span><span class="lines">@@ -871,7 +881,7 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span><span class="lines">@@ -915,7 +925,7 @@
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:uuid:user02"),
</span><del>- customxml.CommonName.fromString("USER02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><span class="cx"> customxml.InviteStatusNoResponse(),
</span><span class="cx"> ),
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4txdavwhoaugmentpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/txdav/who/augment.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/txdav/who/augment.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/txdav/who/augment.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -417,3 +417,7 @@
</span><span class="cx">
</span><span class="cx"> def verifyHTTPDigest(self, *args):
</span><span class="cx"> return self._baseRecord.verifyHTTPDigest(*args)
</span><ins>+
+
+ def accessForRecord(self, record):
+ return self._baseRecord.accessForRecord(record)
</ins></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4txdavwhodirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/txdav/who/directory.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/txdav/who/directory.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/txdav/who/directory.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -178,6 +178,7 @@
</span><span class="cx"> "location": "locations",
</span><span class="cx"> "resource": "resources",
</span><span class="cx"> "user": "users",
</span><ins>+ "macOSXServerWiki": "wikis",
</ins><span class="cx"> "readDelegateGroup": "readDelegateGroups",
</span><span class="cx"> "writeDelegateGroup": "writeDelegateGroups",
</span><span class="cx"> "readDelegatorGroup": "readDelegatorGroups",
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4txdavwhoutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/txdav/who/util.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/txdav/who/util.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/txdav/who/util.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx">
</span><span class="cx"> from calendarserver.tap.util import getDBPool, storeFromConfig
</span><span class="cx"> from twext.who.idirectory import (
</span><del>- RecordType, DirectoryConfigurationError, FieldName
</del><ins>+ RecordType, DirectoryConfigurationError
</ins><span class="cx"> )
</span><span class="cx"> from twext.who.ldap import DirectoryService as LDAPDirectoryService
</span><span class="cx"> from twext.who.util import ConstantsContainer
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> FieldName as CalFieldName
</span><span class="cx"> )
</span><span class="cx"> from txdav.who.xml import DirectoryService as XMLDirectoryService
</span><ins>+from txdav.who.wiki import DirectoryService as WikiDirectoryService
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> log = Logger()
</span><span class="lines">@@ -160,15 +161,29 @@
</span><span class="cx"> log.error("No directory service set up for users")
</span><span class="cx"> raise DirectoryConfigurationError
</span><span class="cx">
</span><ins>+ # Delegate service
</ins><span class="cx"> delegateDirectory = DelegateDirectoryService(
</span><span class="cx"> userDirectory.realmName,
</span><span class="cx"> store
</span><span class="cx"> )
</span><span class="cx"> aggregatedServices.append(delegateDirectory)
</span><span class="cx">
</span><ins>+ # Wiki service
+ if config.Authentication.Wiki.Enabled:
+ aggregatedServices.append(
+ WikiDirectoryService(
+ userDirectory.realmName,
+ config.Authentication.Wiki.CollabHost,
+ config.Authentication.Wiki.CollabPort
+ )
+ )
+
+ # Aggregate service
</ins><span class="cx"> aggregateDirectory = AggregateDirectoryService(
</span><span class="cx"> userDirectory.realmName, aggregatedServices
</span><span class="cx"> )
</span><ins>+
+ # Augment service
</ins><span class="cx"> try:
</span><span class="cx"> fieldNames.append(CalFieldName)
</span><span class="cx"> augmented = AugmentedDirectoryService(
</span></span></pre></div>
<a id="CalendarServerbranchesuserssagenmove2who4txdavwhowikipy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/sagen/move2who-4/txdav/who/wiki.py (13014 => 13015)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/sagen/move2who-4/txdav/who/wiki.py        2014-03-28 00:46:42 UTC (rev 13014)
+++ CalendarServer/branches/users/sagen/move2who-4/txdav/who/wiki.py        2014-03-28 02:06:05 UTC (rev 13015)
</span><span class="lines">@@ -23,21 +23,28 @@
</span><span class="cx"> "WikiAccessLevel",
</span><span class="cx"> ]
</span><span class="cx">
</span><del>-from twisted.python.constants import Names, NamedConstant
-from twisted.internet.defer import inlineCallbacks, returnValue, succeed
-from twisted.web.error import Error as WebError
-
</del><ins>+from calendarserver.platform.darwin.wiki import accessForUserToWiki
+from twext.internet.gaiendpoint import MultiFailure
</ins><span class="cx"> from twext.python.log import Logger
</span><del>-from twext.internet.gaiendpoint import MultiFailure
-from .idirectory import FieldName
</del><span class="cx"> from twext.who.directory import (
</span><span class="cx"> DirectoryService as BaseDirectoryService,
</span><span class="cx"> DirectoryRecord as BaseDirectoryRecord
</span><span class="cx"> )
</span><ins>+from twext.who.idirectory import FieldName as BaseFieldName
+from twext.who.util import ConstantsContainer
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
+from twisted.python.constants import Names, NamedConstant
+from twisted.web.error import Error as WebError
+from txdav.who.idirectory import FieldName
+from txdav.who.directory import CalendarDirectoryRecordMixin
+from txdav.xml import element as davxml
</ins><span class="cx"> from txweb2 import responsecode
</span><ins>+from txweb2.auth.wrapper import UnauthorizedResponse
+from txweb2.dav.resource import TwistedACLInheritable
+from txweb2.http import HTTPError, StatusResponse
</ins><span class="cx">
</span><del>-from calendarserver.platform.darwin.wiki import accessForUserToWiki
</del><span class="cx">
</span><ins>+log = Logger()
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> # FIXME: Should this be Flags?
</span><span class="lines">@@ -59,13 +66,20 @@
</span><span class="cx"> Mac OS X Server Wiki directory service.
</span><span class="cx"> """
</span><span class="cx">
</span><del>- uidPrefix = "[wiki]"
</del><ins>+ uidPrefix = u"[wiki]"
</ins><span class="cx">
</span><span class="cx"> recordType = RecordType
</span><span class="cx">
</span><ins>+ fieldName = ConstantsContainer((
+ BaseFieldName,
+ FieldName,
+ ))
</ins><span class="cx">
</span><del>- def __init__(self):
- BaseDirectoryService.__init__(self)
</del><ins>+
+ def __init__(self, realmName, wikiHost, wikiPort):
+ BaseDirectoryService.__init__(self, realmName)
+ self.wikiHost = wikiHost
+ self.wikiPort = wikiPort
</ins><span class="cx"> self._recordsByName = {}
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -91,9 +105,10 @@
</span><span class="cx"> record = DirectoryRecord(
</span><span class="cx"> self,
</span><span class="cx"> {
</span><del>- FieldName.uid: "{}{}".format(self.uidPrefix, name),
- FieldName.recordType: RecordType.macOSXServerWiki,
- FieldName.shortNames: [name],
</del><ins>+ self.fieldName.uid: u"{}{}".format(self.uidPrefix, name),
+ self.fieldName.recordType: RecordType.macOSXServerWiki,
+ self.fieldName.shortNames: [name],
+ self.fieldName.fullNames: [u"Wiki: {}".format(name)],
</ins><span class="cx"> }
</span><span class="cx"> )
</span><span class="cx"> self._recordsByName[name] = record
</span><span class="lines">@@ -114,8 +129,12 @@
</span><span class="cx"> return succeed(None)
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def recordsFromExpression(self, expression, records=None):
+ return succeed(())
</ins><span class="cx">
</span><del>-class DirectoryRecord(BaseDirectoryRecord):
</del><ins>+
+
+class DirectoryRecord(BaseDirectoryRecord, CalendarDirectoryRecordMixin):
</ins><span class="cx"> """
</span><span class="cx"> Mac OS X Server Wiki directory record.
</span><span class="cx"> """
</span><span class="lines">@@ -133,9 +152,13 @@
</span><span class="cx"> """
</span><span class="cx"> Look up the access level for a record in this wiki.
</span><span class="cx">
</span><del>- @param user: The record to check access for.
</del><ins>+ @param user: The record to check access for. A value of None means
+ unauthenticated
</ins><span class="cx"> """
</span><del>- guid = record.guid
</del><ins>+ if record is None:
+ uid = u"unauthenticated"
+ else:
+ uid = record.uid
</ins><span class="cx">
</span><span class="cx"> try:
</span><span class="cx"> # FIXME: accessForUserToWiki() API is lame.
</span><span class="lines">@@ -145,7 +168,7 @@
</span><span class="cx"> # When we do that note: isn't there a getPage() in twisted.web?
</span><span class="cx">
</span><span class="cx"> access = yield accessForUserToWiki(
</span><del>- guid, self.shortNames[0],
</del><ins>+ uid, self.shortNames[0],
</ins><span class="cx"> host=self.service.wikiHost,
</span><span class="cx"> port=self.service.wikiPort,
</span><span class="cx"> )
</span><span class="lines">@@ -189,4 +212,124 @@
</span><span class="cx">
</span><span class="cx"> except KeyError:
</span><span class="cx"> self.log.error("Unknown wiki access level: {level}", level=access)
</span><del>- return WikiAccessLevel.none
</del><ins>+ returnValue(WikiAccessLevel.none)
+
+
+@inlineCallbacks
+def getWikiACL(resource, request):
+ """
+ Ask the wiki server we're paired with what level of access the authnUser has.
+
+ Returns an ACL.
+
+ Wiki authentication is a bit tricky because the end-user accessing a group
+ calendar may not actually be enabled for calendaring. Therefore in that
+ situation, the authzUser will have been replaced with the wiki principal
+ in locateChild( ), so that any changes the user makes will have the wiki
+ as the originator. The authnUser will always be the end-user.
+ """
+ from twistedcaldav.directory.principal import DirectoryPrincipalResource
+
+ if (
+ not hasattr(resource, "record") or
+ resource.record.recordType != RecordType.macOSXServerWiki
+ ):
+ returnValue(None)
+
+ if hasattr(request, 'wikiACL'):
+ returnValue(request.wikiACL)
+
+ wikiRecord = resource.record
+ wikiID = wikiRecord.shortNames[0]
+ userRecord = None
+
+ try:
+ url = str(request.authnUser.children[0])
+ principal = (yield request.locateResource(url))
+ if isinstance(principal, DirectoryPrincipalResource):
+ userRecord = principal.record
+ except:
+ # TODO: better error handling
+ pass
+
+ try:
+ access = yield wikiRecord.accessForRecord(userRecord)
+
+ # The ACL we returns has ACEs for the end-user and the wiki principal
+ # in case authzUser is the wiki principal.
+ if access == WikiAccessLevel.read:
+ request.wikiACL = davxml.ACL(
+ davxml.ACE(
+ request.authnUser,
+ davxml.Grant(
+ davxml.Privilege(davxml.Read()),
+ davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
+
+ # We allow write-properties so that direct sharees can change
+ # e.g. calendar color properties
+ davxml.Privilege(davxml.WriteProperties()),
+ ),
+ TwistedACLInheritable(),
+ ),
+ davxml.ACE(
+ davxml.Principal(
+ davxml.HRef.fromString("/principals/wikis/%s/" % (wikiID,))
+ ),
+ davxml.Grant(
+ davxml.Privilege(davxml.Read()),
+ davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
+ ),
+ TwistedACLInheritable(),
+ )
+ )
+ returnValue(request.wikiACL)
+
+ elif access in (WikiAccessLevel.write, WikiAccessLevel.admin):
+ request.wikiACL = davxml.ACL(
+ davxml.ACE(
+ request.authnUser,
+ davxml.Grant(
+ davxml.Privilege(davxml.Read()),
+ davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
+ davxml.Privilege(davxml.Write()),
+ ),
+ TwistedACLInheritable(),
+ ),
+ davxml.ACE(
+ davxml.Principal(
+ davxml.HRef.fromString("/principals/wikis/%s/" % (wikiID,))
+ ),
+ davxml.Grant(
+ davxml.Privilege(davxml.Read()),
+ davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
+ davxml.Privilege(davxml.Write()),
+ ),
+ TwistedACLInheritable(),
+ )
+ )
+ returnValue(request.wikiACL)
+
+ else: # "no-access":
+
+ if userRecord is None:
+ # Return a 401 so they have an opportunity to log in
+ response = (yield UnauthorizedResponse.makeResponse(
+ request.credentialFactories,
+ request.remoteAddr,
+ ))
+ raise HTTPError(response)
+
+ raise HTTPError(
+ StatusResponse(
+ responsecode.FORBIDDEN,
+ "You are not allowed to access this wiki"
+ )
+ )
+
+ except HTTPError:
+ # pass through the HTTPError we might have raised above
+ raise
+
+ except Exception, e:
+ log.error("Wiki ACL lookup failed: %s" % (e,))
+ raise HTTPError(StatusResponse(responsecode.SERVICE_UNAVAILABLE, "Wiki ACL lookup failed"))
</ins></span></pre>
</div>
</div>
</body>
</html>