<!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>[13362] CalendarServer/trunk</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/13362">13362</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2014-04-23 09:47:07 -0700 (Wed, 23 Apr 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Hide missing or invalid proxyFors. Fix some sharing issues related to missing or invalid users.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunktwistedcaldavdirectoryprincipalpy">CalendarServer/trunk/twistedcaldav/directory/principal.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavdirectorytestaugmentsxml">CalendarServer/trunk/twistedcaldav/directory/test/augments.xml</a></li>
<li><a href="#CalendarServertrunktwistedcaldavdirectorytesttest_principalpy">CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavresourcepy">CalendarServer/trunk/twistedcaldav/resource.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavsharingpy">CalendarServer/trunk/twistedcaldav/sharing.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavtesttest_sharingpy">CalendarServer/trunk/twistedcaldav/test/test_sharing.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavtestutilpy">CalendarServer/trunk/twistedcaldav/test/util.py</a></li>
<li><a href="#CalendarServertrunktxdavcommondatastoretestutilpy">CalendarServer/trunk/txdav/common/datastore/test/util.py</a></li>
<li><a href="#CalendarServertrunktxdavwhodirectorypy">CalendarServer/trunk/txdav/who/directory.py</a></li>
</ul>
<h3>Removed Paths</h3>
<ul>
<li><a href="#CalendarServertrunktwistedcaldavdirectorytestutilpy">CalendarServer/trunk/twistedcaldav/directory/test/util.py</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunktwistedcaldavdirectoryprincipalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/directory/principal.py        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -986,7 +986,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def proxyFor(self, readWrite):
</del><ins>+ def proxyFor(self, readWrite, ignoreDisabled=True):
</ins><span class="cx"> """
</span><span class="cx"> Returns the set of principals currently delegating to this principal
</span><span class="cx"> with the access indicated by the readWrite argument. If readWrite is
</span><span class="lines">@@ -995,7 +995,9 @@
</span><span class="cx">
</span><span class="cx"> @param readWrite: Whether to look up read-write delegators, or
</span><span class="cx"> read-only delegators
</span><del>- @type readWrite: C{bool}
</del><ins>+ @type readWrite: L{bool}
+ @param ignoreDisabled: If L{True} disabled delegators are not returned
+ @type ignoreDisabled: L{bool}
</ins><span class="cx">
</span><span class="cx"> @return: A Deferred firing with a set of principals
</span><span class="cx"> """
</span><span class="lines">@@ -1021,7 +1023,7 @@
</span><span class="cx">
</span><span class="cx"> for record in proxyForRecords:
</span><span class="cx"> principal = yield self.parent.principalForRecord(record)
</span><del>- if principal is not None:
</del><ins>+ if principal is not None and (not ignoreDisabled or principal.record.hasCalendars):
</ins><span class="cx"> proxyFors.add(principal)
</span><span class="cx">
</span><span class="cx"> returnValue(proxyFors)
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavdirectorytestaugmentsxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/directory/test/augments.xml (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/directory/test/augments.xml        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/twistedcaldav/directory/test/augments.xml        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -66,12 +66,37 @@
</span><span class="cx"> <enable-calendar>false</enable-calendar>
</span><span class="cx"> <enable-addressbook>false</enable-addressbook>
</span><span class="cx"> </record>
</span><del>- <record repeat="100">
- <uid>user%02d</uid>
</del><ins>+ <record>
+ <uid>user01</uid>
</ins><span class="cx"> <enable-calendar>true</enable-calendar>
</span><span class="cx"> <enable-addressbook>true</enable-addressbook>
</span><span class="cx"> </record>
</span><span class="cx"> <record>
</span><ins>+ <uid>user02</uid>
+ <enable-calendar>true</enable-calendar>
+ <enable-addressbook>true</enable-addressbook>
+ </record>
+ <record>
+ <uid>user03</uid>
+ <enable-calendar>true</enable-calendar>
+ <enable-addressbook>true</enable-addressbook>
+ </record>
+ <record>
+ <uid>user04</uid>
+ <enable-calendar>true</enable-calendar>
+ <enable-addressbook>true</enable-addressbook>
+ </record>
+ <record>
+ <uid>user05</uid>
+ <enable-calendar>true</enable-calendar>
+ <enable-addressbook>true</enable-addressbook>
+ </record>
+ <record>
+ <uid>user06</uid>
+ <enable-calendar>true</enable-calendar>
+ <enable-addressbook>true</enable-addressbook>
+ </record>
+ <record>
</ins><span class="cx"> <uid>right_coast</uid>
</span><span class="cx"> <enable-calendar>true</enable-calendar>
</span><span class="cx"> <enable-addressbook>true</enable-addressbook>
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavdirectorytesttest_principalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -15,18 +15,11 @@
</span><span class="cx"> ##
</span><span class="cx"> from __future__ import print_function
</span><span class="cx">
</span><del>-from urllib import quote
-from uuid import UUID
</del><ins>+from twext.who.idirectory import RecordType
</ins><span class="cx">
</span><ins>+from twisted.cred.credentials import UsernamePassword
</ins><span class="cx"> from twisted.internet.defer import inlineCallbacks, returnValue
</span><del>-from twisted.cred.credentials import UsernamePassword
</del><span class="cx">
</span><del>-from txweb2.dav.resource import AccessDeniedError
-from txweb2.http import HTTPError
-from txweb2.test.test_server import SimpleRequest
-
-from txdav.xml import element as davxml
-
</del><span class="cx"> from twistedcaldav import carddavxml
</span><span class="cx"> from twistedcaldav.cache import DisabledCacheNotifier
</span><span class="cx"> from twistedcaldav.caldavxml import caldav_namespace
</span><span class="lines">@@ -38,10 +31,19 @@
</span><span class="cx"> DirectoryPrincipalTypeProvisioningResource,
</span><span class="cx"> )
</span><span class="cx"> from twistedcaldav.test.util import StoreTestCase
</span><ins>+
+from txdav.who.delegates import addDelegate
</ins><span class="cx"> from txdav.who.idirectory import AutoScheduleMode, RecordType as CalRecordType
</span><del>-from twext.who.idirectory import RecordType
</del><ins>+from txdav.xml import element as davxml
</ins><span class="cx">
</span><ins>+from txweb2.dav.resource import AccessDeniedError
+from txweb2.http import HTTPError
+from txweb2.test.test_server import SimpleRequest
</ins><span class="cx">
</span><ins>+from urllib import quote
+from uuid import UUID
+
+
</ins><span class="cx"> class ProvisionedPrincipals(StoreTestCase):
</span><span class="cx"> """
</span><span class="cx"> Directory service provisioned principals.
</span><span class="lines">@@ -53,7 +55,6 @@
</span><span class="cx"> self.principalRootResource = self.actualRoot.getChild("principals")
</span><span class="cx">
</span><span class="cx">
</span><del>-
</del><span class="cx"> @inlineCallbacks
</span><span class="cx"> def test_hierarchy(self):
</span><span class="cx"> """
</span><span class="lines">@@ -169,7 +170,7 @@
</span><span class="cx"> Test of a test routine...
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if True: # user.enabled:
</span><span class="cx"> self.assertEquals(recordResource.record, record)
</span><span class="lines">@@ -185,7 +186,7 @@
</span><span class="cx"> DirectoryPrincipalProvisioningResource.principalForShortName()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ provisioningResource, recordType, _ignore_recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> principal = yield provisioningResource.principalForShortName(
</span><span class="cx"> recordType, record.shortNames[0]
</span><span class="lines">@@ -246,7 +247,7 @@
</span><span class="cx"> DirectoryPrincipalProvisioningResource.principalForUID()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ provisioningResource, _ignore_recordType, _ignore_recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> principal = yield provisioningResource.principalForUID(record.uid)
</span><span class="cx"> if True: # user.enabled:
</span><span class="lines">@@ -262,7 +263,7 @@
</span><span class="cx"> DirectoryPrincipalProvisioningResource.principalForRecord()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ provisioningResource, _ignore_recordType, _ignore_recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> principal = yield provisioningResource.principalForRecord(record)
</span><span class="cx"> if True: # user.enabled:
</span><span class="lines">@@ -279,7 +280,7 @@
</span><span class="cx"> .principalForCalendarUserAddress()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ provisioningResource, _ignore_recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx">
</span><span class="cx"> test_items = tuple(record.calendarUserAddresses)
</span><span class="lines">@@ -347,7 +348,7 @@
</span><span class="cx"> .principalForCalendarUserAddress()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ provisioningResource, _ignore_recordType, _ignore_recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> principal = yield provisioningResource.principalForRecord(record)
</span><span class="cx"> if True: # user.enabled:
</span><span class="lines">@@ -465,7 +466,7 @@
</span><span class="cx"> self.directory.recordType.user,
</span><span class="cx"> )
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ provisioningResource, recordType, _ignore_recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx">
</span><span class="cx"> if record.hasCalendars:
</span><span class="lines">@@ -488,7 +489,7 @@
</span><span class="cx"> self.directory.recordType.resource,
</span><span class="cx"> )
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ provisioningResource, recordType, _ignore_recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if record.hasCalendars:
</span><span class="cx"> principal = (
</span><span class="lines">@@ -515,7 +516,7 @@
</span><span class="cx"> that is an instance of DisabledCacheNotifier
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, _ignore_record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if True: # user.enabled:
</span><span class="cx"> self.failUnless(
</span><span class="lines">@@ -532,7 +533,7 @@
</span><span class="cx"> DirectoryPrincipalResource.displayName()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, _ignore_record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> self.failUnless(recordResource.displayName())
</span><span class="cx">
</span><span class="lines">@@ -543,7 +544,7 @@
</span><span class="cx"> DirectoryPrincipalResource.groupMembers()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> members = yield recordResource.groupMembers()
</span><span class="cx"> self.failUnless(
</span><span class="lines">@@ -559,7 +560,7 @@
</span><span class="cx"> DirectoryPrincipalResource.groupMemberships()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if True: # user.enabled:
</span><span class="cx"> memberships = yield recordResource.groupMemberships()
</span><span class="lines">@@ -579,7 +580,7 @@
</span><span class="cx"> DirectoryPrincipalResource.principalUID()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> self.assertEquals(record.uid, recordResource.principalUID())
</span><span class="cx">
</span><span class="lines">@@ -590,7 +591,7 @@
</span><span class="cx"> DirectoryPrincipalResource.calendarUserAddresses()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if record.hasCalendars:
</span><span class="cx"> self.assertEqual(
</span><span class="lines">@@ -609,7 +610,7 @@
</span><span class="cx"> DirectoryPrincipalResource.canonicalCalendarUserAddress()
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if record.hasCalendars:
</span><span class="cx"> self.failUnless(
</span><span class="lines">@@ -625,7 +626,7 @@
</span><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if record.hasContacts:
</span><span class="cx"> homeURLs = tuple(recordResource.addressBookHomeURLs())
</span><span class="lines">@@ -684,7 +685,7 @@
</span><span class="cx">
</span><span class="cx"> # Calendar home provisioners should result in calendar homes.
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if record.hasCalendars:
</span><span class="cx"> homeURLs = tuple(recordResource.calendarHomeURLs())
</span><span class="lines">@@ -746,7 +747,7 @@
</span><span class="cx">
</span><span class="cx"> # Default state - resources and locations, enabled, others not
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if record.hasCalendars:
</span><span class="cx"> if recordType in (CalRecordType.location, CalRecordType.resource):
</span><span class="lines">@@ -757,7 +758,7 @@
</span><span class="cx"> # Set config to allow users
</span><span class="cx"> self.patch(config.Scheduling.Options.AutoSchedule, "AllowUsers", True)
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if record.hasCalendars:
</span><span class="cx"> if (
</span><span class="lines">@@ -777,7 +778,7 @@
</span><span class="cx"> # Set config to disallow all
</span><span class="cx"> self.patch(config.Scheduling.Options.AutoSchedule, "Enabled", False)
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, recordType, recordResource, record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if record.hasCalendars:
</span><span class="cx"> self.assertFalse((yield recordResource.canAutoSchedule()))
</span><span class="lines">@@ -829,7 +830,7 @@
</span><span class="cx"> Default access controls for principals.
</span><span class="cx"> """
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, _ignore_record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if True: # user.enabled:
</span><span class="cx"> for args in (
</span><span class="lines">@@ -1016,7 +1017,7 @@
</span><span class="cx"> def _authReadOnlyPrivileges(self, resource, url):
</span><span class="cx"> items = []
</span><span class="cx"> for (
</span><del>- provisioningResource, recordType, recordResource, record
</del><ins>+ _ignore_provisioningResource, _ignore_recordType, recordResource, _ignore_record
</ins><span class="cx"> ) in (yield self._allRecords()):
</span><span class="cx"> if True: # user.enabled:
</span><span class="cx"> items.append((
</span><span class="lines">@@ -1039,3 +1040,62 @@
</span><span class="cx"> results.append((resource, url, principal, privilege, allowed))
</span><span class="cx">
</span><span class="cx"> returnValue(results)
</span><ins>+
+
+
+class ProxyPrincipals(StoreTestCase):
+ """
+ Directory service proxy principals.
+ """
+ @inlineCallbacks
+ def setUp(self):
+ yield super(ProxyPrincipals, self).setUp()
+
+ self.principalRootResource = self.actualRoot.getChild("principals")
+
+
+ @inlineCallbacks
+ def test_hideDisabledProxies(self):
+ """
+ Make sure users that are missing or not enabled for calendaring are removed
+ from the proxyFor list.
+ """
+
+ # Check proxies empty right now
+ principal01 = yield self.principalRootResource.principalForUID((yield self.userUIDFromShortName("user01")))
+ self.assertTrue(len((yield principal01.proxyFor(False))) == 0)
+ self.assertTrue(len((yield principal01.proxyFor(True))) == 0)
+
+ principal02 = yield self.principalRootResource.principalForUID((yield self.userUIDFromShortName("user02")))
+ self.assertTrue(len((yield principal02.proxyFor(False))) == 0)
+ self.assertTrue(len((yield principal02.proxyFor(True))) == 0)
+
+ principal03 = yield self.principalRootResource.principalForUID((yield self.userUIDFromShortName("user03")))
+ self.assertTrue(len((yield principal03.proxyFor(False))) == 0)
+ self.assertTrue(len((yield principal03.proxyFor(True))) == 0)
+
+ # Make user01 a read-only proxy for user02 and user03
+ yield addDelegate(self.transactionUnderTest(), principal02.record, principal01.record, False)
+ yield addDelegate(self.transactionUnderTest(), principal03.record, principal01.record, False)
+ yield self.commit()
+
+ self.assertTrue(len((yield principal01.proxyFor(False))) == 2)
+ self.assertTrue(len((yield principal01.proxyFor(True))) == 0)
+
+ # Now disable user02
+ yield self.changeRecord(principal02.record, self.directory.fieldName.hasCalendars, False)
+
+ self.assertTrue(len((yield principal01.proxyFor(False))) == 1)
+ self.assertTrue(len((yield principal01.proxyFor(True))) == 0)
+
+ # Now enable user02
+ yield self.changeRecord(principal02.record, self.directory.fieldName.hasCalendars, True)
+
+ self.assertTrue(len((yield principal01.proxyFor(False))) == 2)
+ self.assertTrue(len((yield principal01.proxyFor(True))) == 0)
+
+ # Now remove user02
+ yield self.directory.removeRecords((principal02.record.uid,))
+
+ self.assertTrue(len((yield principal01.proxyFor(False))) == 1)
+ self.assertTrue(len((yield principal01.proxyFor(True))) == 0)
</ins></span></pre></div>
<a id="CalendarServertrunktwistedcaldavdirectorytestutilpy"></a>
<div class="delfile"><h4>Deleted: CalendarServer/trunk/twistedcaldav/directory/test/util.py (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/directory/test/util.py        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/twistedcaldav/directory/test/util.py        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -1,386 +0,0 @@
</span><del>-##
-# Copyright (c) 2005-2014 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-
-from twisted.trial.unittest import SkipTest
-from twisted.cred.credentials import UsernamePassword
-from txweb2.auth.digest import DigestedCredentials, calcResponse, calcHA1
-
-from twistedcaldav.directory.directory import DirectoryService
-from twistedcaldav.directory.directory import UnknownRecordTypeError
-from twistedcaldav.directory.util import transactionFromRequest
-from twistedcaldav.test.util import TestCase
-
-# FIXME: Add tests for GUID hooey, once we figure out what that means here
-
-class DirectoryTestCase (TestCase):
- """
- Tests a directory implementation.
- """
- # Subclass should init this to a set of recordtypes.
- recordTypes = set()
-
- # Subclass should init this to a dict of username keys and dict values.
- users = {}
-
- # Subclass should init this to a dict of groupname keys and dict values.
- groups = {}
-
- # Subclass should init this to a dict of locationnames keys and dict values.
- locations = {}
-
- # Subclass should init this to a dict of resourcenames keys and dict values.
- resources = {}
-
- # Subclass should init this to a dict of addressname keys and dict values.
- addresses = {}
-
-
- # Subclass should init this to an IDirectoryService implementation class.
- def service(self):
- """
- Returns an IDirectoryService.
- """
- raise NotImplementedError("Subclass needs to implement service()")
-
- # For aggregator subclasses
- recordTypePrefixes = ("",)
-
-
- def test_realm(self):
- """
- IDirectoryService.realm
- """
- self.failUnless(self.service().realmName)
-
-
- def test_recordTypes(self):
- """
- IDirectoryService.recordTypes()
- """
- if not self.recordTypes:
- raise SkipTest("No record types")
-
- self.assertEquals(set(self.service().recordTypes()), self.recordTypes)
-
-
- def test_recordWithShortName(self):
- """
- IDirectoryService.recordWithShortName()
- """
- for recordType, data in (
- (DirectoryService.recordType_users , self.users),
- (DirectoryService.recordType_groups , self.groups),
- (DirectoryService.recordType_locations, self.locations),
- (DirectoryService.recordType_resources, self.resources),
- ):
- if not data:
- raise SkipTest("No %s" % (recordType,))
-
- service = self.service()
- for shortName, info in data.iteritems():
- record = service.recordWithShortName(info.get("prefix", "") + recordType, shortName)
- self.failUnless(record, "No record (%s)%s" % (info.get("prefix", "") + recordType, shortName))
- self.compare(record, shortName, data[shortName])
-
- for prefix in self.recordTypePrefixes:
- try:
- record = service.recordWithShortName(prefix + recordType, "IDunnoWhoThisIsIReallyDont")
- except UnknownRecordTypeError:
- continue
- self.assertEquals(record, None)
-
-
- def test_recordWithUID(self):
- service = self.service()
- record = None
-
- for shortName, what in self.allEntries():
- guid = what["guid"]
- if guid is not None:
- record = service.recordWithUID(guid)
- self.compare(record, shortName, what)
-
- if record is None:
- raise SkipTest("No GUIDs provided to test")
-
-
- def test_recordWithCalendarUserAddress(self):
- service = self.service()
- record = None
-
- for shortName, what in self.allEntries():
- for address in what["addresses"]:
- record = service.recordWithCalendarUserAddress(address)
- self.compare(record, shortName, what)
-
- if record is None:
- raise SkipTest("No calendar user addresses provided to test")
-
-
- def test_groupMembers(self):
- """
- IDirectoryRecord.members()
- """
- if not self.groups:
- raise SkipTest("No groups")
-
- service = self.service()
- for group, info in self.groups.iteritems():
- prefix = info.get("prefix", "")
- groupRecord = service.recordWithShortName(prefix + DirectoryService.recordType_groups, group)
- result = set((m.recordType, prefix + m.shortNames[0]) for m in groupRecord.members())
- expected = set(self.groups[group]["members"])
- self.assertEquals(
- result, expected,
- "Wrong membership for group %r: %s != %s" % (group, result, expected)
- )
-
-
- def test_groupMemberships(self):
- """
- IDirectoryRecord.groups()
- """
- if not self.users:
- raise SkipTest("No users")
- if not self.groups:
- raise SkipTest("No groups")
-
- for recordType, data in (
- (DirectoryService.recordType_users , self.users),
- (DirectoryService.recordType_groups, self.groups),
- ):
- service = self.service()
- for shortName, info in data.iteritems():
- prefix = info.get("prefix", "")
- record = service.recordWithShortName(prefix + recordType, shortName)
- result = set(prefix + g.shortNames[0] for g in record.groups())
- expected = set(g for g in self.groups if (record.recordType, shortName) in self.groups[g]["members"])
- self.assertEquals(
- result, expected,
- "Wrong groups for %s %r: %s != %s" % (record.recordType, shortName, result, expected)
- )
-
-
- def recordNames(self, recordType):
- service = self.service()
- names = set()
- for prefix in self.recordTypePrefixes:
- try:
- records = service.listRecords(prefix + recordType)
- except UnknownRecordTypeError:
- continue
- assert records is not None, "%r(%r) returned None" % (service.listRecords, recordType)
- for record in records:
- names.add(prefix + record.shortNames[0])
-
- return names
-
-
- def allEntries(self):
- for data, _ignore_recordType in (
- (self.users, DirectoryService.recordType_users),
- (self.groups, DirectoryService.recordType_groups),
- (self.locations, DirectoryService.recordType_locations),
- (self.resources, DirectoryService.recordType_resources),
- ):
- for item in data.iteritems():
- yield item
-
-
- def compare(self, record, shortName, data):
- def value(key):
- if key in data:
- return data[key]
- else:
- return None
-
- guid = value("guid")
- if guid is not None:
- guid = record.guid
-
- addresses = set(value("addresses"))
- if record.hasCalendars:
- addresses.add("urn:x-uid:%s" % (record.uid,))
- addresses.add("urn:uuid:%s" % (record.guid,))
- addresses.add("/principals/__uids__/%s/" % (record.uid,))
- addresses.add("/principals/%s/%s/" % (record.recordType, record.shortNames[0],))
-
- if hasattr(record.service, "recordTypePrefix"):
- prefix = record.service.recordTypePrefix
- else:
- prefix = ""
-
- self.assertEquals(prefix + record.shortNames[0], shortName)
- self.assertEquals(set(record.calendarUserAddresses), addresses)
-
- if value("guid"):
- self.assertEquals(record.guid, value("guid"))
-
- if value("name"):
- self.assertEquals(record.fullName, value("name"))
-
-
- def servicePrefix(self):
- service = self.service()
- if hasattr(service, "recordTypePrefix"):
- return service.recordTypePrefix
- else:
- return ""
-
-
-
-class NonCachingTestCase (DirectoryTestCase):
-
- def test_listRecords_user(self):
- """
- IDirectoryService.listRecords(DirectoryService.recordType_users)
- """
- if not self.users:
- raise SkipTest("No users")
-
- self.assertEquals(self.recordNames(DirectoryService.recordType_users), set(self.users.keys()))
-
-
- def test_listRecords_group(self):
- """
- IDirectoryService.listRecords(DirectoryService.recordType_groups)
- """
- if not self.groups:
- raise SkipTest("No groups")
-
- self.assertEquals(self.recordNames(DirectoryService.recordType_groups), set(self.groups.keys()))
-
-
- def test_listRecords_locations(self):
- """
- IDirectoryService.listRecords("locations")
- """
- if not self.resources:
- raise SkipTest("No locations")
-
- self.assertEquals(self.recordNames(DirectoryService.recordType_locations), set(self.locations.keys()))
-
-
- def test_listRecords_resources(self):
- """
- IDirectoryService.listRecords("resources")
- """
- if not self.resources:
- raise SkipTest("No resources")
-
- self.assertEquals(self.recordNames(DirectoryService.recordType_resources), set(self.resources.keys()))
-
-
-
-class BasicTestCase (DirectoryTestCase):
- """
- Tests a directory implementation with basic auth.
- """
- def test_verifyCredentials_basic(self):
- """
- IDirectoryRecord.verifyCredentials() with basic
- """
- if not self.users:
- raise SkipTest("No users")
-
- service = self.service()
- for user in self.users:
- userRecord = service.recordWithShortName(DirectoryService.recordType_users, user)
- self.failUnless(userRecord.verifyCredentials(UsernamePassword(user, self.users[user]["password"])))
-
-
-
-# authRequest = {
-# username="username",
-# realm="test realm",
-# nonce="178288758716122392881254770685",
-# uri="/write/",
-# response="62f388be1cf678fbdfce87910871bcc5",
-# opaque="1041524039",
-# algorithm="md5",
-# cnonce="29fc54aa1641c6fa0e151419361c8f23",
-# nc=00000001,
-# qop="auth",
-# }
-
-class DigestTestCase (DirectoryTestCase):
- """
- Tests a directory implementation with digest auth.
- """
- def test_verifyCredentials_digest(self):
- """
- IDirectoryRecord.verifyCredentials() with digest
- """
- if not self.users:
- raise SkipTest("No users")
-
- service = self.service()
- for user in self.users:
- for good in (True, True, False, False, True):
- userRecord = service.recordWithShortName(DirectoryService.recordType_users, user)
-
- # I'm glad this is so simple...
- response = calcResponse(
- calcHA1(
- "md5",
- user,
- service.realmName,
- self.users[user]["password"],
- "booger",
- "phlegm",
- ),
- "md5",
- "booger",
- None,
- "phlegm",
- "auth",
- "GET",
- "/",
- None,
- )
-
- if good:
- noise = ""
- else:
- noise = "blah"
-
- credentials = DigestedCredentials(
- user,
- "GET",
- service.realmName,
- {
- "response": response,
- "uri": "/",
- "nonce": "booger" + noise,
- "cnonce": "phlegm",
- "nc": None,
- },
- )
-
- if good:
- self.failUnless(userRecord.verifyCredentials(credentials))
- else:
- self.failIf(userRecord.verifyCredentials(credentials))
-
-
-
-def maybeCommit(req):
- class JustForCleanup(object):
- def newTransaction(self, *whatever):
- return self
- def commit(self):
- return
- transactionFromRequest(req, JustForCleanup()).commit()
</del></span></pre></div>
<a id="CalendarServertrunktwistedcaldavresourcepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/resource.py (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/resource.py        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/twistedcaldav/resource.py        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -2567,7 +2567,10 @@
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def _otherPrincipalHomeURL(self, otherUID):
</span><span class="cx"> ownerPrincipal = (yield self.principalForUID(otherUID))
</span><del>- returnValue(ownerPrincipal.calendarHomeURLs()[0])
</del><ins>+ if ownerPrincipal and len(ownerPrincipal.calendarHomeURLs()):
+ returnValue(ownerPrincipal.calendarHomeURLs()[0])
+ else:
+ returnValue(None)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><span class="lines">@@ -2822,7 +2825,7 @@
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def _otherPrincipalHomeURL(self, otherUID):
</span><span class="cx"> ownerPrincipal = (yield self.principalForUID(otherUID))
</span><del>- returnValue(ownerPrincipal.addressBookHomeURLs()[0])
</del><ins>+ returnValue(ownerPrincipal.addressBookHomeURLs()[0] if ownerPrincipal else None)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavsharingpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/sharing.py (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/sharing.py        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/twistedcaldav/sharing.py        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -91,12 +91,16 @@
</span><span class="cx"> invitations = yield self.validateInvites(request, invitations)
</span><span class="cx">
</span><span class="cx"> ownerPrincipal = yield self.principalForUID(self._newStoreObject.ownerHome().uid())
</span><del>- # FIXME: use urn:x-uid in all cases
- if self.isCalendarCollection():
- owner = ownerPrincipal.principalURL()
</del><ins>+ if ownerPrincipal is None:
+ owner = "invalid"
+ ownerCN = "Invalid"
</ins><span class="cx"> else:
</span><del>- owner = "urn:x-uid:" + ownerPrincipal.principalUID()
- ownerCN = ownerPrincipal.displayName()
</del><ins>+ # FIXME: use urn:x-uid in all cases
+ if self.isCalendarCollection():
+ owner = ownerPrincipal.principalURL()
+ else:
+ owner = "urn:x-uid:" + ownerPrincipal.principalUID()
+ ownerCN = ownerPrincipal.displayName()
</ins><span class="cx">
</span><span class="cx"> returnValue(customxml.Invite(
</span><span class="cx"> customxml.Organizer(
</span><span class="lines">@@ -435,12 +439,15 @@
</span><span class="cx"> # assert request
</span><span class="cx"> if invitations is None:
</span><span class="cx"> invitations = yield self._newStoreObject.allInvitations()
</span><ins>+ adjusted_invitations = []
</ins><span class="cx"> for invitation in invitations:
</span><span class="cx"> if invitation.status != _BIND_STATUS_INVALID:
</span><span class="cx"> if not (yield self.validUserIDForShare("urn:x-uid:" + invitation.shareeUID, request)):
</span><span class="cx"> self.log.error("Invalid sharee detected: {uid}", uid=invitation.shareeUID)
</span><ins>+ invitation = invitation._replace(status=_BIND_STATUS_INVALID)
+ adjusted_invitations.append(invitation)
</ins><span class="cx">
</span><del>- returnValue(invitations)
</del><ins>+ returnValue(adjusted_invitations)
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def inviteUserToShare(self, userid, cn, ace, summary, request):
</span><span class="lines">@@ -519,12 +526,18 @@
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def uninviteSingleUserFromShare(self, userid, aces, request): #@UnusedVariable
</span><span class="cx">
</span><del>- # Cancel invites - we'll just use whatever userid we are given
</del><ins>+ # Cancel invites - we'll just use whatever userid we are given. However, if we
+ # cannot find a matching principal, try to extract the uid from the userid
+ # and use that (to allow invalid principals to be removed).
</ins><span class="cx"> sharee = yield self.principalForCalendarUserAddress(userid)
</span><del>- if not sharee:
</del><ins>+ if sharee is not None:
+ uid = sharee.principalUID()
+ elif userid.startswith("urn:x-uid:"):
+ uid = userid[10:]
+ else:
</ins><span class="cx"> returnValue(False)
</span><span class="cx">
</span><del>- result = (yield self._newStoreObject.uninviteUserFromShare(sharee.principalUID()))
</del><ins>+ result = (yield self._newStoreObject.uninviteUserFromShare(uid))
</ins><span class="cx">
</span><span class="cx"> returnValue(result)
</span><span class="cx">
</span><span class="lines">@@ -793,7 +806,7 @@
</span><span class="cx"> if child._newStoreObject is not None and not child._newStoreObject.owned():
</span><span class="cx"> ownerHomeURL = (yield self._otherPrincipalHomeURL(child._newStoreObject.ownerHome().uid()))
</span><span class="cx"> ownerView = yield child._newStoreObject.ownerView()
</span><del>- child.setShare(joinURL(ownerHomeURL, ownerView.name()))
</del><ins>+ child.setShare(joinURL(ownerHomeURL, ownerView.name()) if ownerHomeURL else None)
</ins><span class="cx"> access = yield child._checkAccessControl()
</span><span class="cx"> if access is None:
</span><span class="cx"> returnValue(None)
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavtesttest_sharingpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/test/test_sharing.py (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/test/test_sharing.py        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/twistedcaldav/test/test_sharing.py        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -23,7 +23,6 @@
</span><span class="cx">
</span><span class="cx"> from twistedcaldav import customxml
</span><span class="cx"> from twistedcaldav.config import config
</span><del>-from twistedcaldav.directory.principal import DirectoryCalendarPrincipalResource
</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><span class="lines">@@ -35,7 +34,6 @@
</span><span class="cx"> from txdav.who.wiki import (
</span><span class="cx"> DirectoryRecord as WikiDirectoryRecord,
</span><span class="cx"> DirectoryService as WikiDirectoryService,
</span><del>- RecordType as WikiRecordType,
</del><span class="cx"> WikiAccessLevel
</span><span class="cx"> )
</span><span class="cx">
</span><span class="lines">@@ -53,78 +51,6 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-class FakeHome(object):
- pass
-
-
-
-class FakeRecord(object):
-
- def __init__(self, name, cuaddr):
- self.fullName = name
- self.guid = name
- self.calendarUserAddresses = set((cuaddr,))
- if name.startswith(WikiDirectoryService.uidPrefix):
- recordType = WikiRecordType.macOSXServerWiki
- else:
- recordType = None
- self.recordType = recordType
- self.shortNames = [name]
-
-
-
-class FakePrincipal(DirectoryCalendarPrincipalResource):
-
- invalid_names = set()
-
- def __init__(self, cuaddr, test):
- if cuaddr.startswith("mailto:"):
- name = cuaddr[7:].split('@')[0]
- elif cuaddr.startswith("urn:x-uid:"):
- name = cuaddr[10:]
- elif cuaddr.startswith("urn:uuid:"):
- name = cuaddr[9:]
- else:
- name = cuaddr
-
- self.path = "/principals/__uids__/%s" % (name,)
- self.homepath = "/calendars/__uids__/%s" % (name,)
- self.displayname = name.upper()
- self.record = FakeRecord(name, cuaddr)
- self._test = test
- self._name = name
-
-
- @inlineCallbacks
- def calendarHome(self, request):
- if self._name in self.invalid_names:
- returnValue(None)
- a, _ignore_seg = yield self._test.calendarCollection.locateChild(request, ["__uids__"])
- b, _ignore_seg = yield a.locateChild(request, [self._name])
- if b is None:
- # XXX all tests except test_noWikiAccess currently rely on the
- # fake thing here.
- returnValue(FakeHome())
- returnValue(b)
-
-
- def calendarHomeURLs(self):
- return (self.homepath,)
-
-
- def principalURL(self):
- return self.path
-
-
- def principalUID(self):
- return self.record.guid
-
-
- def displayName(self):
- return self.displayname
-
-
-
</del><span class="cx"> class SharingTests(StoreTestCase):
</span><span class="cx">
</span><span class="cx"> def configure(self):
</span><span class="lines">@@ -140,39 +66,6 @@
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def setUp(self):
</span><span class="cx"> yield super(SharingTests, self).setUp()
</span><del>-
- # FIXME: not sure what these were for:
-
- # 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
-
- # @patched
- # def principalForCalendarUserAddress(resourceSelf, cuaddr):
- # if "bogus" in cuaddr:
- # return None
- # else:
- # return FakePrincipal(cuaddr, self)
-
- # @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()
-
- # @patched
- # def principalForUID(resourceSelf, principalUID):
- # return FakePrincipal("urn:uuid:" + principalUID, self)
-
</del><span class="cx"> self.resource = yield self._getResource()
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -216,9 +109,9 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def _doPOSTSharerAccept(self, body, resultcode=responsecode.OK):
- authRecord = yield self.directory.recordWithUID(u"user02")
- request = SimpleStoreRequest(self, "POST", "/calendars/__uids__/user02/", content=body, authRecord=authRecord)
</del><ins>+ def _doPOSTSharerAccept(self, body, resultcode=responsecode.OK, sharer="user02"):
+ authRecord = yield self.directory.recordWithUID(unicode(sharer))
+ request = SimpleStoreRequest(self, "POST", "/calendars/__uids__/{}/".format(sharer), content=body, authRecord=authRecord)
</ins><span class="cx"> request.headers.setHeader("content-type", MimeType("text", "xml"))
</span><span class="cx"> response = yield self.send(request)
</span><span class="cx"> response = IResponse(response)
</span><span class="lines">@@ -248,12 +141,22 @@
</span><span class="cx"> return None
</span><span class="cx">
</span><span class="cx">
</span><ins>+ def _getUIDElementValues(self, xml):
+
+ results = {}
+ for user in xml.children:
+ href = str(user.childOfType(davxml.HRef))
+ uid = str(user.childOfType(customxml.UID))
+ results[href] = uid
+ return results
+
+
</ins><span class="cx"> def _clearUIDElementValue(self, xml):
</span><span class="cx">
</span><span class="cx"> for user in xml.children:
</span><del>- for element in user.children:
- if type(element) == customxml.UID:
- element.children[0].data = ""
</del><ins>+ uid = user.childOfType(customxml.UID)
+ if uid is not None:
+ uid.children[0].data = ""
</ins><span class="cx"> return xml
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -713,25 +616,24 @@
</span><span class="cx"> )
</span><span class="cx"> ))
</span><span class="cx">
</span><del>- self.resource.validUserIDForShare = lambda userid, request: None
- self.resource.principalForCalendarUserAddress = lambda cuaddr: None
- self.resource.principalForUID = lambda principalUID: None
</del><ins>+ record = yield self.userRecordWithShortName("user02")
+ yield self.changeRecord(record, self.directory.fieldName.hasCalendars, False)
</ins><span class="cx">
</span><span class="cx"> propInvite = (yield self.resource.readProperty(customxml.Invite, None))
</span><span class="cx"> self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
</span><span class="cx"> customxml.InviteUser(
</span><span class="cx"> customxml.UID.fromString(""),
</span><span class="cx"> davxml.HRef.fromString("urn:x-uid:user02"),
</span><del>- customxml.CommonName.fromString("user02"),
</del><ins>+ customxml.CommonName.fromString("User 02"),
</ins><span class="cx"> customxml.InviteAccess(customxml.ReadWriteAccess()),
</span><del>- customxml.InviteStatusNoResponse(),
</del><ins>+ customxml.InviteStatusInvalid(),
</ins><span class="cx"> )
</span><span class="cx"> ))
</span><span class="cx">
</span><span class="cx"> yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
</span><span class="cx"> <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
</span><span class="cx"> <CS:remove>
</span><del>- <D:href>mailto:user02@example.com</D:href>
</del><ins>+ <D:href>urn:x-uid:user02</D:href>
</ins><span class="cx"> </CS:remove>
</span><span class="cx"> </CS:share>
</span><span class="cx"> """)
</span><span class="lines">@@ -832,7 +734,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def test_POSTDowngradeWithDisabledInvitee(self):
</del><ins>+ def test_POSTDowngradeWithMissingInvitee(self):
</ins><span class="cx">
</span><span class="cx"> yield self.resource.upgradeToShare()
</span><span class="cx">
</span><span class="lines">@@ -857,12 +759,14 @@
</span><span class="cx"> ),
</span><span class="cx"> ))
</span><span class="cx">
</span><del>- self.patch(FakePrincipal, "invalid_names", set(("user02",)))
</del><ins>+ yield self.directory.removeRecords(((yield self.userUIDFromShortName("user02")),))
+ self.assertTrue((yield self.userUIDFromShortName("user02")) is None)
+
</ins><span class="cx"> yield self.resource.downgradeFromShare(norequest())
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><del>- def test_POSTRemoveWithDisabledInvitee(self):
</del><ins>+ def test_POSTRemoveWithMissingInvitee(self):
</ins><span class="cx">
</span><span class="cx"> yield self.resource.upgradeToShare()
</span><span class="cx">
</span><span class="lines">@@ -887,12 +791,13 @@
</span><span class="cx"> ),
</span><span class="cx"> ))
</span><span class="cx">
</span><del>- self.patch(FakePrincipal, "invalid_names", set(("user02",)))
</del><ins>+ yield self.directory.removeRecords(((yield self.userUIDFromShortName("user02")),))
+ self.assertTrue((yield self.userUIDFromShortName("user02")) is None)
</ins><span class="cx">
</span><span class="cx"> yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
</span><span class="cx"> <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
</span><span class="cx"> <CS:remove>
</span><del>- <D:href>mailto:user02@example.com</D:href>
</del><ins>+ <D:href>urn:x-uid:user02</D:href>
</ins><span class="cx"> </CS:remove>
</span><span class="cx"> </CS:share>
</span><span class="cx"> """)
</span><span class="lines">@@ -948,10 +853,286 @@
</span><span class="cx"> )
</span><span class="cx"> href = self._getHRefElementValue(result) + "/"
</span><span class="cx">
</span><del>- self.patch(FakePrincipal, "invalid_names", set(("user01",)))
</del><ins>+ record = yield self.userRecordWithShortName("user01")
+ yield self.changeRecord(record, self.directory.fieldName.hasCalendars, False)
</ins><span class="cx">
</span><span class="cx"> resource = (yield self._getResourceSharer(href))
</span><span class="cx"> yield resource.removeShareeResource(SimpleStoreRequest(self, "DELETE", href))
</span><span class="cx">
</span><span class="cx"> resource = (yield self._getResourceSharer(href))
</span><span class="cx"> self.assertFalse(resource.exists())
</span><ins>+
+
+ @inlineCallbacks
+ def test_POSTShareeRemoveWithMissingSharer(self):
+
+ yield self.resource.upgradeToShare()
+
+ yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
+ <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
+ <CS:set>
+ <D:href>mailto:user02@example.com</D:href>
+ <CS:summary>My Shared Calendar</CS:summary>
+ <CS:read-write/>
+ </CS:set>
+ </CS:share>
+ """)
+
+ propInvite = (yield self.resource.readProperty(customxml.Invite, None))
+ uid = self._getUIDElementValue(propInvite)
+ self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
+ customxml.InviteUser(
+ customxml.UID.fromString(""),
+ davxml.HRef.fromString("urn:x-uid:user02"),
+ customxml.CommonName.fromString("User 02"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusNoResponse(),
+ ),
+ ))
+
+ result = (yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
+ <invite-reply xmlns='http://calendarserver.org/ns/'>
+ <href xmlns='DAV:'>mailto:user01@example.com</href>
+ <invite-accepted/>
+ <hosturl>
+ <href xmlns='DAV:'>/calendars/__uids__/user01/calendar/</href>
+ </hosturl>
+ <in-reply-to>%s</in-reply-to>
+ <summary>The Shared Calendar</summary>
+ <common-name>User 02</common-name>
+ <first-name>user</first-name>
+ <last-name>02</last-name>
+ </invite-reply>
+ """ % (uid,))
+ )
+ href = self._getHRefElementValue(result) + "/"
+
+ yield self.directory.removeRecords(((yield self.userUIDFromShortName("user01")),))
+ self.assertTrue((yield self.userUIDFromShortName("user01")) is None)
+
+ resource = (yield self._getResourceSharer(href))
+ yield resource.removeShareeResource(SimpleStoreRequest(self, "DELETE", href))
+
+ resource = (yield self._getResourceSharer(href))
+ self.assertFalse(resource.exists())
+
+
+ @inlineCallbacks
+ def test_shareeInviteWithDisabledSharer(self):
+
+ yield self.resource.upgradeToShare()
+
+ yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
+ <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
+ <CS:set>
+ <D:href>mailto:user02@example.com</D:href>
+ <CS:summary>My Shared Calendar</CS:summary>
+ <CS:read-write/>
+ </CS:set>
+ </CS:share>
+ """)
+
+ propInvite = (yield self.resource.readProperty(customxml.Invite, None))
+ uid = self._getUIDElementValue(propInvite)
+ self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
+ customxml.InviteUser(
+ customxml.UID.fromString(""),
+ davxml.HRef.fromString("urn:x-uid:user02"),
+ customxml.CommonName.fromString("User 02"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusNoResponse(),
+ ),
+ ))
+
+ result = (yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
+ <invite-reply xmlns='http://calendarserver.org/ns/'>
+ <href xmlns='DAV:'>mailto:user01@example.com</href>
+ <invite-accepted/>
+ <hosturl>
+ <href xmlns='DAV:'>/calendars/__uids__/user01/calendar/</href>
+ </hosturl>
+ <in-reply-to>%s</in-reply-to>
+ <summary>The Shared Calendar</summary>
+ <common-name>User 02</common-name>
+ <first-name>user</first-name>
+ <last-name>02</last-name>
+ </invite-reply>
+ """ % (uid,))
+ )
+ href = self._getHRefElementValue(result) + "/"
+
+ record = yield self.userRecordWithShortName("user01")
+ yield self.changeRecord(record, self.directory.fieldName.hasCalendars, False)
+
+ resource = (yield self._getResourceSharer(href))
+ propInvite = yield resource.inviteProperty(None)
+ self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
+ customxml.Organizer(
+ davxml.HRef.fromString("/principals/__uids__/user01/"),
+ customxml.CommonName.fromString("User 01"),
+ ),
+ customxml.InviteUser(
+ davxml.HRef.fromString("urn:x-uid:user02"),
+ customxml.CommonName.fromString("User 02"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusAccepted(),
+ ),
+ ))
+
+
+ @inlineCallbacks
+ def test_shareeInviteWithMissingSharer(self):
+
+ yield self.resource.upgradeToShare()
+
+ yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
+ <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
+ <CS:set>
+ <D:href>mailto:user02@example.com</D:href>
+ <CS:summary>My Shared Calendar</CS:summary>
+ <CS:read-write/>
+ </CS:set>
+ </CS:share>
+ """)
+
+ propInvite = (yield self.resource.readProperty(customxml.Invite, None))
+ uid = self._getUIDElementValue(propInvite)
+ self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
+ customxml.InviteUser(
+ customxml.UID.fromString(""),
+ davxml.HRef.fromString("urn:x-uid:user02"),
+ customxml.CommonName.fromString("User 02"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusNoResponse(),
+ ),
+ ))
+
+ result = (yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
+ <invite-reply xmlns='http://calendarserver.org/ns/'>
+ <href xmlns='DAV:'>mailto:user01@example.com</href>
+ <invite-accepted/>
+ <hosturl>
+ <href xmlns='DAV:'>/calendars/__uids__/user01/calendar/</href>
+ </hosturl>
+ <in-reply-to>%s</in-reply-to>
+ <summary>The Shared Calendar</summary>
+ <common-name>User 02</common-name>
+ <first-name>user</first-name>
+ <last-name>02</last-name>
+ </invite-reply>
+ """ % (uid,))
+ )
+ href = self._getHRefElementValue(result) + "/"
+
+ yield self.directory.removeRecords(((yield self.userUIDFromShortName("user01")),))
+ self.assertTrue((yield self.userUIDFromShortName("user01")) is None)
+
+ resource = (yield self._getResourceSharer(href))
+ propInvite = yield resource.inviteProperty(None)
+ self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
+ customxml.Organizer(
+ davxml.HRef.fromString("invalid"),
+ customxml.CommonName.fromString("Invalid"),
+ ),
+ customxml.InviteUser(
+ davxml.HRef.fromString("urn:x-uid:user02"),
+ customxml.CommonName.fromString("User 02"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusAccepted(),
+ ),
+ ))
+
+
+ @inlineCallbacks
+ def test_hideInvalidSharers(self):
+
+ yield self.resource.upgradeToShare()
+
+ yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
+ <CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
+ <CS:set>
+ <D:href>mailto:user02@example.com</D:href>
+ <CS:summary>My Shared Calendar</CS:summary>
+ <CS:read-write/>
+ </CS:set>
+ <CS:set>
+ <D:href>mailto:user03@example.com</D:href>
+ <CS:summary>My Shared Calendar</CS:summary>
+ <CS:read-write/>
+ </CS:set>
+ </CS:share>
+ """)
+
+ propInvite = (yield self.resource.readProperty(customxml.Invite, None))
+ uids = self._getUIDElementValues(propInvite)
+ self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
+ customxml.InviteUser(
+ customxml.UID.fromString(""),
+ davxml.HRef.fromString("urn:x-uid:user02"),
+ customxml.CommonName.fromString("User 02"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusNoResponse(),
+ ),
+ customxml.InviteUser(
+ customxml.UID.fromString(""),
+ davxml.HRef.fromString("urn:x-uid:user03"),
+ customxml.CommonName.fromString("User 03"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusNoResponse(),
+ ),
+ ))
+
+ yield self._doPOSTSharerAccept("""<?xml version='1.0' encoding='UTF-8'?>
+ <invite-reply xmlns='http://calendarserver.org/ns/'>
+ <href xmlns='DAV:'>mailto:user01@example.com</href>
+ <invite-accepted/>
+ <hosturl>
+ <href xmlns='DAV:'>/calendars/__uids__/user01/calendar/</href>
+ </hosturl>
+ <in-reply-to>%s</in-reply-to>
+ <summary>The Shared Calendar</summary>
+ <common-name>User 02</common-name>
+ <first-name>user</first-name>
+ <last-name>02</last-name>
+ </invite-reply>
+ """ % (uids["urn:x-uid:user02"],))
+
+ yield self._doPOSTSharerAccept(
+ """<?xml version='1.0' encoding='UTF-8'?>
+ <invite-reply xmlns='http://calendarserver.org/ns/'>
+ <href xmlns='DAV:'>mailto:user01@example.com</href>
+ <invite-accepted/>
+ <hosturl>
+ <href xmlns='DAV:'>/calendars/__uids__/user01/calendar/</href>
+ </hosturl>
+ <in-reply-to>%s</in-reply-to>
+ <summary>The Shared Calendar</summary>
+ <common-name>User 03</common-name>
+ <first-name>user</first-name>
+ <last-name>03</last-name>
+ </invite-reply>
+ """ % (uids["urn:x-uid:user03"],),
+ sharer="user03"
+ )
+
+ record = yield self.directory.recordWithUID((yield self.userUIDFromShortName("user02")))
+ yield self.changeRecord(record, self.directory.fieldName.hasCalendars, False)
+
+ resource = yield self._getResource()
+ propInvite = yield resource.inviteProperty(None)
+ self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
+ customxml.InviteUser(
+ customxml.UID.fromString(""),
+ davxml.HRef.fromString("urn:x-uid:user02"),
+ customxml.CommonName.fromString("User 02"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusInvalid(),
+ ),
+ customxml.InviteUser(
+ customxml.UID.fromString(""),
+ davxml.HRef.fromString("urn:x-uid:user03"),
+ customxml.CommonName.fromString("User 03"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusAccepted(),
+ ),
+ ))
</ins></span></pre></div>
<a id="CalendarServertrunktwistedcaldavtestutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/test/util.py (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/test/util.py        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/twistedcaldav/test/util.py        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -77,8 +77,6 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-
-
</del><span class="cx"> class SimpleStoreRequest(SimpleRequest):
</span><span class="cx"> """
</span><span class="cx"> A SimpleRequest that automatically grabs the proper transaction for a test.
</span><span class="lines">@@ -190,7 +188,6 @@
</span><span class="cx"> proxies.setContent(proxiesFile.getContent())
</span><span class="cx">
</span><span class="cx">
</span><del>-
</del><span class="cx"> def createHierarchy(self, structure, root=None):
</span><span class="cx"> if root is None:
</span><span class="cx"> root = os.path.abspath(self.mktemp())
</span><span class="lines">@@ -407,7 +404,6 @@
</span><span class="cx"> config.UsePackageTimezones = True
</span><span class="cx">
</span><span class="cx">
</span><del>-
</del><span class="cx"> def setUp(self):
</span><span class="cx"> super(TestCase, self).setUp()
</span><span class="cx">
</span><span class="lines">@@ -430,7 +426,6 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><del>-
</del><span class="cx"> class norequest(object):
</span><span class="cx"> def addResponseFilter(self, filter):
</span><span class="cx"> "stub; ignore me"
</span></span></pre></div>
<a id="CalendarServertrunktxdavcommondatastoretestutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/common/datastore/test/util.py (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/common/datastore/test/util.py        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/txdav/common/datastore/test/util.py        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -38,10 +38,9 @@
</span><span class="cx">
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> from twext.python.filepath import CachingFilePath
</span><del>-from twistedcaldav.ical import Component as VComponent, Component
</del><span class="cx"> from twext.enterprise.adbapi2 import ConnectionPool
</span><span class="cx"> from twext.enterprise.ienterprise import AlreadyFinishedError
</span><del>-from txweb2.dav.resource import TwistedGETContentMD5
</del><ins>+from twext.who.directory import DirectoryRecord
</ins><span class="cx">
</span><span class="cx"> from twisted.application.service import Service
</span><span class="cx"> from twisted.internet import reactor
</span><span class="lines">@@ -52,6 +51,7 @@
</span><span class="cx">
</span><span class="cx"> from twistedcaldav import ical
</span><span class="cx"> from twistedcaldav.config import config
</span><ins>+from twistedcaldav.ical import Component as VComponent, Component
</ins><span class="cx"> from twistedcaldav.stdconfig import DEFAULT_CONFIG
</span><span class="cx"> from twistedcaldav.vcard import Component as ABComponent
</span><span class="cx">
</span><span class="lines">@@ -63,6 +63,8 @@
</span><span class="cx"> from txdav.common.datastore.sql_tables import schema
</span><span class="cx"> from txdav.common.icommondatastore import NoSuchHomeChildError
</span><span class="cx">
</span><ins>+from txweb2.dav.resource import TwistedGETContentMD5
+
</ins><span class="cx"> from zope.interface.exceptions import BrokenMethodImplementation, \
</span><span class="cx"> DoesNotImplement
</span><span class="cx"> from zope.interface.verify import verifyObject
</span><span class="lines">@@ -823,7 +825,27 @@
</span><span class="cx"> .addressbookObjectWithName(name)))
</span><span class="cx">
</span><span class="cx">
</span><ins>+ @inlineCallbacks
+ def userRecordWithShortName(self, shortname):
+ record = yield self.directory.recordWithShortName(self.directory.recordType.user, shortname)
+ returnValue(record)
</ins><span class="cx">
</span><ins>+
+ @inlineCallbacks
+ def userUIDFromShortName(self, shortname):
+ record = yield self.directory.recordWithShortName(self.directory.recordType.user, shortname)
+ returnValue(record.uid if record is not None else None)
+
+
+ @inlineCallbacks
+ def changeRecord(self, record, fieldname, value):
+ fields = record.fields.copy()
+ fields[fieldname] = value
+ updatedRecord = DirectoryRecord(self.directory, fields)
+ yield self.directory.updateRecords((updatedRecord,))
+
+
+
</ins><span class="cx"> class StubNotifierFactory(object):
</span><span class="cx"> """
</span><span class="cx"> For testing push notifications without an XMPP server.
</span></span></pre></div>
<a id="CalendarServertrunktxdavwhodirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/who/directory.py (13361 => 13362)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/who/directory.py        2014-04-23 00:49:34 UTC (rev 13361)
+++ CalendarServer/trunk/txdav/who/directory.py        2014-04-23 16:47:07 UTC (rev 13362)
</span><span class="lines">@@ -377,9 +377,6 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def enabledAsOrganizer(self):
</span><del>- # FIXME:
- from twistedcaldav.config import config
-
</del><span class="cx"> if self.recordType == self.service.recordType.user:
</span><span class="cx"> return True
</span><span class="cx"> elif self.recordType == self.service.recordType.group:
</span><span class="lines">@@ -396,9 +393,6 @@
</span><span class="cx"> """
</span><span class="cx"> URL of the server hosting this record. Return None if hosted on this server.
</span><span class="cx"> """
</span><del>- # FIXME:
- from twistedcaldav.config import config
-
</del><span class="cx"> if config.Servers.Enabled and getattr(self, "serviceNodeUID", None):
</span><span class="cx"> return Servers.getServerURIById(self.serviceNodeUID)
</span><span class="cx"> else:
</span><span class="lines">@@ -409,9 +403,6 @@
</span><span class="cx"> """
</span><span class="cx"> Server hosting this record. Return None if hosted on this server.
</span><span class="cx"> """
</span><del>- # FIXME:
- from twistedcaldav.config import config
-
</del><span class="cx"> if config.Servers.Enabled and getattr(self, "serviceNodeUID", None):
</span><span class="cx"> return Servers.getServerById(self.serviceNodeUID)
</span><span class="cx"> else:
</span><span class="lines">@@ -428,17 +419,11 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def calendarsEnabled(self):
</span><del>- # FIXME:
- from twistedcaldav.config import config
-
</del><span class="cx"> return config.EnableCalDAV and self.hasCalendars
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def canAutoSchedule(self, organizer=None):
</span><del>- # FIXME:
- from twistedcaldav.config import config
-
</del><span class="cx"> if config.Scheduling.Options.AutoSchedule.Enabled:
</span><span class="cx"> if (
</span><span class="cx"> config.Scheduling.Options.AutoSchedule.Always or
</span></span></pre>
</div>
</div>
</body>
</html>