[CalendarServer-changes] [13362] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Wed Apr 23 09:47:07 PDT 2014
Revision: 13362
http://trac.calendarserver.org//changeset/13362
Author: cdaboo at apple.com
Date: 2014-04-23 09:47:07 -0700 (Wed, 23 Apr 2014)
Log Message:
-----------
Hide missing or invalid proxyFors. Fix some sharing issues related to missing or invalid users.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/directory/principal.py
CalendarServer/trunk/twistedcaldav/directory/test/augments.xml
CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py
CalendarServer/trunk/twistedcaldav/resource.py
CalendarServer/trunk/twistedcaldav/sharing.py
CalendarServer/trunk/twistedcaldav/test/test_sharing.py
CalendarServer/trunk/twistedcaldav/test/util.py
CalendarServer/trunk/txdav/common/datastore/test/util.py
CalendarServer/trunk/txdav/who/directory.py
Removed Paths:
-------------
CalendarServer/trunk/twistedcaldav/directory/test/util.py
Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- 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)
@@ -986,7 +986,7 @@
@inlineCallbacks
- def proxyFor(self, readWrite):
+ def proxyFor(self, readWrite, ignoreDisabled=True):
"""
Returns the set of principals currently delegating to this principal
with the access indicated by the readWrite argument. If readWrite is
@@ -995,7 +995,9 @@
@param readWrite: Whether to look up read-write delegators, or
read-only delegators
- @type readWrite: C{bool}
+ @type readWrite: L{bool}
+ @param ignoreDisabled: If L{True} disabled delegators are not returned
+ @type ignoreDisabled: L{bool}
@return: A Deferred firing with a set of principals
"""
@@ -1021,7 +1023,7 @@
for record in proxyForRecords:
principal = yield self.parent.principalForRecord(record)
- if principal is not None:
+ if principal is not None and (not ignoreDisabled or principal.record.hasCalendars):
proxyFors.add(principal)
returnValue(proxyFors)
Modified: CalendarServer/trunk/twistedcaldav/directory/test/augments.xml
===================================================================
--- 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)
@@ -66,12 +66,37 @@
<enable-calendar>false</enable-calendar>
<enable-addressbook>false</enable-addressbook>
</record>
- <record repeat="100">
- <uid>user%02d</uid>
+ <record>
+ <uid>user01</uid>
<enable-calendar>true</enable-calendar>
<enable-addressbook>true</enable-addressbook>
</record>
<record>
+ <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>
<uid>right_coast</uid>
<enable-calendar>true</enable-calendar>
<enable-addressbook>true</enable-addressbook>
Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py
===================================================================
--- 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)
@@ -15,18 +15,11 @@
##
from __future__ import print_function
-from urllib import quote
-from uuid import UUID
+from twext.who.idirectory import RecordType
+from twisted.cred.credentials import UsernamePassword
from twisted.internet.defer import inlineCallbacks, returnValue
-from twisted.cred.credentials import UsernamePassword
-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
-
from twistedcaldav import carddavxml
from twistedcaldav.cache import DisabledCacheNotifier
from twistedcaldav.caldavxml import caldav_namespace
@@ -38,10 +31,19 @@
DirectoryPrincipalTypeProvisioningResource,
)
from twistedcaldav.test.util import StoreTestCase
+
+from txdav.who.delegates import addDelegate
from txdav.who.idirectory import AutoScheduleMode, RecordType as CalRecordType
-from twext.who.idirectory import RecordType
+from txdav.xml import element as davxml
+from txweb2.dav.resource import AccessDeniedError
+from txweb2.http import HTTPError
+from txweb2.test.test_server import SimpleRequest
+from urllib import quote
+from uuid import UUID
+
+
class ProvisionedPrincipals(StoreTestCase):
"""
Directory service provisioned principals.
@@ -53,7 +55,6 @@
self.principalRootResource = self.actualRoot.getChild("principals")
-
@inlineCallbacks
def test_hierarchy(self):
"""
@@ -169,7 +170,7 @@
Test of a test routine...
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
) in (yield self._allRecords()):
if True: # user.enabled:
self.assertEquals(recordResource.record, record)
@@ -185,7 +186,7 @@
DirectoryPrincipalProvisioningResource.principalForShortName()
"""
for (
- provisioningResource, recordType, recordResource, record
+ provisioningResource, recordType, _ignore_recordResource, record
) in (yield self._allRecords()):
principal = yield provisioningResource.principalForShortName(
recordType, record.shortNames[0]
@@ -246,7 +247,7 @@
DirectoryPrincipalProvisioningResource.principalForUID()
"""
for (
- provisioningResource, recordType, recordResource, record
+ provisioningResource, _ignore_recordType, _ignore_recordResource, record
) in (yield self._allRecords()):
principal = yield provisioningResource.principalForUID(record.uid)
if True: # user.enabled:
@@ -262,7 +263,7 @@
DirectoryPrincipalProvisioningResource.principalForRecord()
"""
for (
- provisioningResource, recordType, recordResource, record
+ provisioningResource, _ignore_recordType, _ignore_recordResource, record
) in (yield self._allRecords()):
principal = yield provisioningResource.principalForRecord(record)
if True: # user.enabled:
@@ -279,7 +280,7 @@
.principalForCalendarUserAddress()
"""
for (
- provisioningResource, recordType, recordResource, record
+ provisioningResource, _ignore_recordType, recordResource, record
) in (yield self._allRecords()):
test_items = tuple(record.calendarUserAddresses)
@@ -347,7 +348,7 @@
.principalForCalendarUserAddress()
"""
for (
- provisioningResource, recordType, recordResource, record
+ provisioningResource, _ignore_recordType, _ignore_recordResource, record
) in (yield self._allRecords()):
principal = yield provisioningResource.principalForRecord(record)
if True: # user.enabled:
@@ -465,7 +466,7 @@
self.directory.recordType.user,
)
for (
- provisioningResource, recordType, recordResource, record
+ provisioningResource, recordType, _ignore_recordResource, record
) in (yield self._allRecords()):
if record.hasCalendars:
@@ -488,7 +489,7 @@
self.directory.recordType.resource,
)
for (
- provisioningResource, recordType, recordResource, record
+ provisioningResource, recordType, _ignore_recordResource, record
) in (yield self._allRecords()):
if record.hasCalendars:
principal = (
@@ -515,7 +516,7 @@
that is an instance of DisabledCacheNotifier
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, _ignore_record
) in (yield self._allRecords()):
if True: # user.enabled:
self.failUnless(
@@ -532,7 +533,7 @@
DirectoryPrincipalResource.displayName()
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, _ignore_record
) in (yield self._allRecords()):
self.failUnless(recordResource.displayName())
@@ -543,7 +544,7 @@
DirectoryPrincipalResource.groupMembers()
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
) in (yield self._allRecords()):
members = yield recordResource.groupMembers()
self.failUnless(
@@ -559,7 +560,7 @@
DirectoryPrincipalResource.groupMemberships()
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
) in (yield self._allRecords()):
if True: # user.enabled:
memberships = yield recordResource.groupMemberships()
@@ -579,7 +580,7 @@
DirectoryPrincipalResource.principalUID()
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
) in (yield self._allRecords()):
self.assertEquals(record.uid, recordResource.principalUID())
@@ -590,7 +591,7 @@
DirectoryPrincipalResource.calendarUserAddresses()
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
) in (yield self._allRecords()):
if record.hasCalendars:
self.assertEqual(
@@ -609,7 +610,7 @@
DirectoryPrincipalResource.canonicalCalendarUserAddress()
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
) in (yield self._allRecords()):
if record.hasCalendars:
self.failUnless(
@@ -625,7 +626,7 @@
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
) in (yield self._allRecords()):
if record.hasContacts:
homeURLs = tuple(recordResource.addressBookHomeURLs())
@@ -684,7 +685,7 @@
# Calendar home provisioners should result in calendar homes.
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, record
) in (yield self._allRecords()):
if record.hasCalendars:
homeURLs = tuple(recordResource.calendarHomeURLs())
@@ -746,7 +747,7 @@
# Default state - resources and locations, enabled, others not
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, recordType, recordResource, record
) in (yield self._allRecords()):
if record.hasCalendars:
if recordType in (CalRecordType.location, CalRecordType.resource):
@@ -757,7 +758,7 @@
# Set config to allow users
self.patch(config.Scheduling.Options.AutoSchedule, "AllowUsers", True)
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, recordType, recordResource, record
) in (yield self._allRecords()):
if record.hasCalendars:
if (
@@ -777,7 +778,7 @@
# Set config to disallow all
self.patch(config.Scheduling.Options.AutoSchedule, "Enabled", False)
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, recordType, recordResource, record
) in (yield self._allRecords()):
if record.hasCalendars:
self.assertFalse((yield recordResource.canAutoSchedule()))
@@ -829,7 +830,7 @@
Default access controls for principals.
"""
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, _ignore_record
) in (yield self._allRecords()):
if True: # user.enabled:
for args in (
@@ -1016,7 +1017,7 @@
def _authReadOnlyPrivileges(self, resource, url):
items = []
for (
- provisioningResource, recordType, recordResource, record
+ _ignore_provisioningResource, _ignore_recordType, recordResource, _ignore_record
) in (yield self._allRecords()):
if True: # user.enabled:
items.append((
@@ -1039,3 +1040,62 @@
results.append((resource, url, principal, privilege, allowed))
returnValue(results)
+
+
+
+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)
Deleted: CalendarServer/trunk/twistedcaldav/directory/test/util.py
===================================================================
--- 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)
@@ -1,386 +0,0 @@
-##
-# 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()
Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- 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)
@@ -2567,7 +2567,10 @@
@inlineCallbacks
def _otherPrincipalHomeURL(self, otherUID):
ownerPrincipal = (yield self.principalForUID(otherUID))
- returnValue(ownerPrincipal.calendarHomeURLs()[0])
+ if ownerPrincipal and len(ownerPrincipal.calendarHomeURLs()):
+ returnValue(ownerPrincipal.calendarHomeURLs()[0])
+ else:
+ returnValue(None)
@inlineCallbacks
@@ -2822,7 +2825,7 @@
@inlineCallbacks
def _otherPrincipalHomeURL(self, otherUID):
ownerPrincipal = (yield self.principalForUID(otherUID))
- returnValue(ownerPrincipal.addressBookHomeURLs()[0])
+ returnValue(ownerPrincipal.addressBookHomeURLs()[0] if ownerPrincipal else None)
@inlineCallbacks
Modified: CalendarServer/trunk/twistedcaldav/sharing.py
===================================================================
--- 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)
@@ -91,12 +91,16 @@
invitations = yield self.validateInvites(request, invitations)
ownerPrincipal = yield self.principalForUID(self._newStoreObject.ownerHome().uid())
- # FIXME: use urn:x-uid in all cases
- if self.isCalendarCollection():
- owner = ownerPrincipal.principalURL()
+ if ownerPrincipal is None:
+ owner = "invalid"
+ ownerCN = "Invalid"
else:
- owner = "urn:x-uid:" + ownerPrincipal.principalUID()
- ownerCN = ownerPrincipal.displayName()
+ # FIXME: use urn:x-uid in all cases
+ if self.isCalendarCollection():
+ owner = ownerPrincipal.principalURL()
+ else:
+ owner = "urn:x-uid:" + ownerPrincipal.principalUID()
+ ownerCN = ownerPrincipal.displayName()
returnValue(customxml.Invite(
customxml.Organizer(
@@ -435,12 +439,15 @@
# assert request
if invitations is None:
invitations = yield self._newStoreObject.allInvitations()
+ adjusted_invitations = []
for invitation in invitations:
if invitation.status != _BIND_STATUS_INVALID:
if not (yield self.validUserIDForShare("urn:x-uid:" + invitation.shareeUID, request)):
self.log.error("Invalid sharee detected: {uid}", uid=invitation.shareeUID)
+ invitation = invitation._replace(status=_BIND_STATUS_INVALID)
+ adjusted_invitations.append(invitation)
- returnValue(invitations)
+ returnValue(adjusted_invitations)
def inviteUserToShare(self, userid, cn, ace, summary, request):
@@ -519,12 +526,18 @@
@inlineCallbacks
def uninviteSingleUserFromShare(self, userid, aces, request): #@UnusedVariable
- # Cancel invites - we'll just use whatever userid we are given
+ # 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).
sharee = yield self.principalForCalendarUserAddress(userid)
- if not sharee:
+ if sharee is not None:
+ uid = sharee.principalUID()
+ elif userid.startswith("urn:x-uid:"):
+ uid = userid[10:]
+ else:
returnValue(False)
- result = (yield self._newStoreObject.uninviteUserFromShare(sharee.principalUID()))
+ result = (yield self._newStoreObject.uninviteUserFromShare(uid))
returnValue(result)
@@ -793,7 +806,7 @@
if child._newStoreObject is not None and not child._newStoreObject.owned():
ownerHomeURL = (yield self._otherPrincipalHomeURL(child._newStoreObject.ownerHome().uid()))
ownerView = yield child._newStoreObject.ownerView()
- child.setShare(joinURL(ownerHomeURL, ownerView.name()))
+ child.setShare(joinURL(ownerHomeURL, ownerView.name()) if ownerHomeURL else None)
access = yield child._checkAccessControl()
if access is None:
returnValue(None)
Modified: CalendarServer/trunk/twistedcaldav/test/test_sharing.py
===================================================================
--- 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)
@@ -23,7 +23,6 @@
from twistedcaldav import customxml
from twistedcaldav.config import config
-from twistedcaldav.directory.principal import DirectoryCalendarPrincipalResource
from twistedcaldav.test.test_cache import StubResponseCacheResource
from twistedcaldav.test.util import norequest, StoreTestCase, SimpleStoreRequest
@@ -35,7 +34,6 @@
from txdav.who.wiki import (
DirectoryRecord as WikiDirectoryRecord,
DirectoryService as WikiDirectoryService,
- RecordType as WikiRecordType,
WikiAccessLevel
)
@@ -53,78 +51,6 @@
-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
-
-
-
class SharingTests(StoreTestCase):
def configure(self):
@@ -140,39 +66,6 @@
@inlineCallbacks
def setUp(self):
yield super(SharingTests, self).setUp()
-
- # 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)
-
self.resource = yield self._getResource()
@@ -216,9 +109,9 @@
@inlineCallbacks
- 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)
+ 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)
request.headers.setHeader("content-type", MimeType("text", "xml"))
response = yield self.send(request)
response = IResponse(response)
@@ -248,12 +141,22 @@
return None
+ 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
+
+
def _clearUIDElementValue(self, xml):
for user in xml.children:
- for element in user.children:
- if type(element) == customxml.UID:
- element.children[0].data = ""
+ uid = user.childOfType(customxml.UID)
+ if uid is not None:
+ uid.children[0].data = ""
return xml
@@ -713,25 +616,24 @@
)
))
- self.resource.validUserIDForShare = lambda userid, request: None
- self.resource.principalForCalendarUserAddress = lambda cuaddr: None
- self.resource.principalForUID = lambda principalUID: None
+ record = yield self.userRecordWithShortName("user02")
+ yield self.changeRecord(record, self.directory.fieldName.hasCalendars, False)
propInvite = (yield self.resource.readProperty(customxml.Invite, None))
self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
customxml.InviteUser(
customxml.UID.fromString(""),
davxml.HRef.fromString("urn:x-uid:user02"),
- customxml.CommonName.fromString("user02"),
+ customxml.CommonName.fromString("User 02"),
customxml.InviteAccess(customxml.ReadWriteAccess()),
- customxml.InviteStatusNoResponse(),
+ customxml.InviteStatusInvalid(),
)
))
yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
<CS:remove>
- <D:href>mailto:user02 at example.com</D:href>
+ <D:href>urn:x-uid:user02</D:href>
</CS:remove>
</CS:share>
""")
@@ -832,7 +734,7 @@
@inlineCallbacks
- def test_POSTDowngradeWithDisabledInvitee(self):
+ def test_POSTDowngradeWithMissingInvitee(self):
yield self.resource.upgradeToShare()
@@ -857,12 +759,14 @@
),
))
- self.patch(FakePrincipal, "invalid_names", set(("user02",)))
+ yield self.directory.removeRecords(((yield self.userUIDFromShortName("user02")),))
+ self.assertTrue((yield self.userUIDFromShortName("user02")) is None)
+
yield self.resource.downgradeFromShare(norequest())
@inlineCallbacks
- def test_POSTRemoveWithDisabledInvitee(self):
+ def test_POSTRemoveWithMissingInvitee(self):
yield self.resource.upgradeToShare()
@@ -887,12 +791,13 @@
),
))
- self.patch(FakePrincipal, "invalid_names", set(("user02",)))
+ yield self.directory.removeRecords(((yield self.userUIDFromShortName("user02")),))
+ self.assertTrue((yield self.userUIDFromShortName("user02")) is None)
yield self._doPOST("""<?xml version="1.0" encoding="utf-8" ?>
<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
<CS:remove>
- <D:href>mailto:user02 at example.com</D:href>
+ <D:href>urn:x-uid:user02</D:href>
</CS:remove>
</CS:share>
""")
@@ -948,10 +853,286 @@
)
href = self._getHRefElementValue(result) + "/"
- self.patch(FakePrincipal, "invalid_names", set(("user01",)))
+ record = yield self.userRecordWithShortName("user01")
+ yield self.changeRecord(record, self.directory.fieldName.hasCalendars, False)
resource = (yield self._getResourceSharer(href))
yield resource.removeShareeResource(SimpleStoreRequest(self, "DELETE", href))
resource = (yield self._getResourceSharer(href))
self.assertFalse(resource.exists())
+
+
+ @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 at 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 at 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 at 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 at 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 at 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 at 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 at example.com</D:href>
+ <CS:summary>My Shared Calendar</CS:summary>
+ <CS:read-write/>
+ </CS:set>
+ <CS:set>
+ <D:href>mailto:user03 at 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 at 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 at 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(),
+ ),
+ ))
Modified: CalendarServer/trunk/twistedcaldav/test/util.py
===================================================================
--- 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)
@@ -77,8 +77,6 @@
-
-
class SimpleStoreRequest(SimpleRequest):
"""
A SimpleRequest that automatically grabs the proper transaction for a test.
@@ -190,7 +188,6 @@
proxies.setContent(proxiesFile.getContent())
-
def createHierarchy(self, structure, root=None):
if root is None:
root = os.path.abspath(self.mktemp())
@@ -407,7 +404,6 @@
config.UsePackageTimezones = True
-
def setUp(self):
super(TestCase, self).setUp()
@@ -430,7 +426,6 @@
-
class norequest(object):
def addResponseFilter(self, filter):
"stub; ignore me"
Modified: CalendarServer/trunk/txdav/common/datastore/test/util.py
===================================================================
--- 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)
@@ -38,10 +38,9 @@
from twext.python.log import Logger
from twext.python.filepath import CachingFilePath
-from twistedcaldav.ical import Component as VComponent, Component
from twext.enterprise.adbapi2 import ConnectionPool
from twext.enterprise.ienterprise import AlreadyFinishedError
-from txweb2.dav.resource import TwistedGETContentMD5
+from twext.who.directory import DirectoryRecord
from twisted.application.service import Service
from twisted.internet import reactor
@@ -52,6 +51,7 @@
from twistedcaldav import ical
from twistedcaldav.config import config
+from twistedcaldav.ical import Component as VComponent, Component
from twistedcaldav.stdconfig import DEFAULT_CONFIG
from twistedcaldav.vcard import Component as ABComponent
@@ -63,6 +63,8 @@
from txdav.common.datastore.sql_tables import schema
from txdav.common.icommondatastore import NoSuchHomeChildError
+from txweb2.dav.resource import TwistedGETContentMD5
+
from zope.interface.exceptions import BrokenMethodImplementation, \
DoesNotImplement
from zope.interface.verify import verifyObject
@@ -823,7 +825,27 @@
.addressbookObjectWithName(name)))
+ @inlineCallbacks
+ def userRecordWithShortName(self, shortname):
+ record = yield self.directory.recordWithShortName(self.directory.recordType.user, shortname)
+ returnValue(record)
+
+ @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,))
+
+
+
class StubNotifierFactory(object):
"""
For testing push notifications without an XMPP server.
Modified: CalendarServer/trunk/txdav/who/directory.py
===================================================================
--- 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)
@@ -377,9 +377,6 @@
def enabledAsOrganizer(self):
- # FIXME:
- from twistedcaldav.config import config
-
if self.recordType == self.service.recordType.user:
return True
elif self.recordType == self.service.recordType.group:
@@ -396,9 +393,6 @@
"""
URL of the server hosting this record. Return None if hosted on this server.
"""
- # FIXME:
- from twistedcaldav.config import config
-
if config.Servers.Enabled and getattr(self, "serviceNodeUID", None):
return Servers.getServerURIById(self.serviceNodeUID)
else:
@@ -409,9 +403,6 @@
"""
Server hosting this record. Return None if hosted on this server.
"""
- # FIXME:
- from twistedcaldav.config import config
-
if config.Servers.Enabled and getattr(self, "serviceNodeUID", None):
return Servers.getServerById(self.serviceNodeUID)
else:
@@ -428,17 +419,11 @@
def calendarsEnabled(self):
- # FIXME:
- from twistedcaldav.config import config
-
return config.EnableCalDAV and self.hasCalendars
@inlineCallbacks
def canAutoSchedule(self, organizer=None):
- # FIXME:
- from twistedcaldav.config import config
-
if config.Scheduling.Options.AutoSchedule.Enabled:
if (
config.Scheduling.Options.AutoSchedule.Always or
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140423/9a5df3ed/attachment-0001.html>
More information about the calendarserver-changes
mailing list