[CalendarServer-changes] [14926] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Fri Jun 26 17:15:49 PDT 2015
Revision: 14926
http://trac.calendarserver.org//changeset/14926
Author: cdaboo at apple.com
Date: 2015-06-26 17:15:48 -0700 (Fri, 26 Jun 2015)
Log Message:
-----------
Make sure group reconciliation never attempts to share a calendar with the sharer.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/ical.py
CalendarServer/trunk/txdav/caldav/datastore/sql.py
CalendarServer/trunk/txdav/who/test/accounts/groupAccounts.xml
CalendarServer/trunk/txdav/who/test/test_group_sharees.py
Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py 2015-06-26 21:21:39 UTC (rev 14925)
+++ CalendarServer/trunk/twistedcaldav/ical.py 2015-06-27 00:15:48 UTC (rev 14926)
@@ -3579,7 +3579,19 @@
def _reconcileGroupAttendee(self, groupCUA, memberAttendeeProps):
+ """
+ Make sure there are attendee properties for every member of the group, and no
+ other attendee properties marked as a member of the group. Note that attendee
+ properties already present with a MEMBER parameter are not given a MEMBER
+ parameter if they are in the group. This ensures that manually added attendees
+ are not automatically removed when they dissappear from a group.
+ @param groupCUA: calendar user address of the group
+ @type groupCUA: L{str}
+ @param memberAttendeeProps: list of member properties
+ @type memberAttendeeProps: L{tuple}
+ """
+
changed = False
for component in self.subcomponents(ignore=True):
oldAttendeeProps = tuple(component.properties("ATTENDEE"))
@@ -3615,7 +3627,15 @@
def reconcileGroupAttendees(self, groupCUAToAttendeeMemberPropMap):
+ """
+ Reconcile the attendee properties in this L{Component}.
+ @param groupCUAToAttendeeMemberPropMap: map of group to potential attendees
+ @type groupCUAToAttendeeMemberPropMap: L{dict}
+ """
+
+ # Reconcile the member ship list of each group attendee, keeping track of which
+ # groups are actually used
changed = False
allMemberCUAs = set()
nonemptyGroupCUAs = set()
@@ -3625,7 +3645,8 @@
if memberAttendeeProps:
nonemptyGroupCUAs.add(groupCUA)
- # remove orphans
+ # Remove attendee properties that have a MEMBER value that contains only groups no longer
+ # used in this component
for component in self.subcomponents(ignore=True):
for attendeeProp in tuple(component.properties("ATTENDEE")):
if attendeeProp.hasParameter("MEMBER"):
Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py 2015-06-26 21:21:39 UTC (rev 14925)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py 2015-06-27 00:15:48 UTC (rev 14926)
@@ -2156,11 +2156,13 @@
changed = True
for memberUID in memberUIDs - boundUIDs:
- shareeView = yield self.shareeView(memberUID)
- newMode = _BIND_MODE_GROUP if shareeView is None else shareeView._groupModeAfterAddingOneGroupSharee()
- if newMode is not None:
- yield super(Calendar, self).inviteUIDToShare(memberUID, newMode)
- changed = True
+ # Never reconcile the sharer
+ if memberUID != self._home.uid():
+ shareeView = yield self.shareeView(memberUID)
+ newMode = _BIND_MODE_GROUP if shareeView is None else shareeView._groupModeAfterAddingOneGroupSharee()
+ if newMode is not None:
+ yield super(Calendar, self).inviteUIDToShare(memberUID, newMode)
+ changed = True
returnValue(changed)
@@ -2744,6 +2746,7 @@
if attendeeProp.parameterValue("CUTYPE") == "X-SERVER-GROUP"
])
+ # Map each group attendee to a list of potential member properties
groupCUAToAttendeeMemberPropMap = {}
for groupCUA in groupCUAs:
Modified: CalendarServer/trunk/txdav/who/test/accounts/groupAccounts.xml
===================================================================
--- CalendarServer/trunk/txdav/who/test/accounts/groupAccounts.xml 2015-06-26 21:21:39 UTC (rev 14925)
+++ CalendarServer/trunk/txdav/who/test/accounts/groupAccounts.xml 2015-06-27 00:15:48 UTC (rev 14926)
@@ -136,4 +136,21 @@
<member-uid>group03</member-uid>
<member-uid>user10</member-uid>
</record>
+ <record type="group">
+ <short-name>group05</short-name>
+ <uid>group05</uid>
+ <guid>20000000-0000-0000-0000-000000000005</guid>
+ <full-name>Group 05</full-name>
+ <email>group05 at example.com</email>
+ <member-uid>user01</member-uid>
+ <member-uid>user02</member-uid>
+ </record>
+ <record type="group">
+ <short-name>group06</short-name>
+ <uid>group06</uid>
+ <guid>20000000-0000-0000-0000-000000000006</guid>
+ <full-name>Group 06</full-name>
+ <email>group06 at example.com</email>
+ <member-uid>user02</member-uid>
+ </record>
</directory>
Modified: CalendarServer/trunk/txdav/who/test/test_group_sharees.py
===================================================================
--- CalendarServer/trunk/txdav/who/test/test_group_sharees.py 2015-06-26 21:21:39 UTC (rev 14925)
+++ CalendarServer/trunk/txdav/who/test/test_group_sharees.py 2015-06-27 00:15:48 UTC (rev 14926)
@@ -348,3 +348,164 @@
yield calendar.uninviteUIDFromShare("group02")
noinvites = yield calendar.sharingInvites()
self.assertEqual(len(noinvites), 3)
+
+
+ @inlineCallbacks
+ def test_no_self_invite(self):
+ """
+ Test that group shares where the group includes the sharee work. Then remove
+ the sharee from the group and make sure it works.
+ """
+
+ record02 = yield self.transactionUnderTest().directoryService().recordWithUID("user02")
+
+ @inlineCallbacks
+ def expandedMembers(self, records=None, seen=None):
+
+ if self.uid == "group05":
+ returnValue(frozenset((record02,)))
+ else:
+ returnValue((yield unpatchedExpandedMembers(self, records, seen)))
+
+ unpatchedExpandedMembers = CalendarDirectoryRecordMixin.expandedMembers
+
+ # setup group cacher
+ groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
+ groupsToRefresh = yield groupCacher.groupsToRefresh(self.transactionUnderTest())
+ self.assertEqual(len(groupsToRefresh), 0)
+ wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "group05")
+ self.assertEqual(len(wps), 0)
+
+ yield self._check_notifications("user01", [])
+
+ # Invite
+ calendar = yield self.calendarUnderTest(home="user01", name="calendar")
+ invites = yield calendar.sharingInvites()
+ self.assertEqual(len(invites), 0)
+ self.assertFalse(calendar.isShared())
+
+ yield self._check_notifications("user01", [])
+ shareeViews = yield calendar.inviteUIDToShare("group05", _BIND_MODE_READ)
+ self.assertEqual(len(shareeViews), 1)
+ calendar = yield self.calendarUnderTest(home="user01", name="calendar")
+ invites = yield calendar.sharingInvites()
+ self.assertEqual(len(invites), 1)
+ for invite in invites:
+ shareeView = yield calendar.shareeView(invite.shareeUID)
+ self.assertEqual(invite.ownerUID, "user01")
+ self.assertEqual(invite.uid, shareeView.shareName())
+ self.assertEqual(invite.mode, _BIND_MODE_GROUP)
+ self.assertEqual((yield shareeView.effectiveShareMode()), _BIND_MODE_READ)
+ self.assertEqual(invite.status, _BIND_STATUS_INVITED)
+ self.assertEqual(invite.summary, None)
+ yield self._check_notifications(invite.shareeUID, [invite.uid, ])
+
+ # 1 group members
+ self.patch(CalendarDirectoryRecordMixin, "expandedMembers", expandedMembers)
+
+ wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "group05")
+ self.assertEqual(len(wps), 1)
+ yield self.commit()
+ yield JobItem.waitEmpty(self._sqlCalendarStore.newTransaction, reactor, 60)
+
+ calendar = yield self.calendarUnderTest(home="user01", name="calendar")
+ invites = yield calendar.sharingInvites()
+ self.assertEqual(len(invites), 1)
+ for invite in invites:
+ shareeView = yield calendar.shareeView(invite.shareeUID)
+ self.assertEqual(invite.ownerUID, "user01")
+ self.assertEqual(invite.uid, shareeView.shareName())
+ self.assertEqual(invite.mode, _BIND_MODE_GROUP)
+ self.assertEqual((yield shareeView.effectiveShareMode()), _BIND_MODE_READ)
+ self.assertEqual(invite.status, _BIND_STATUS_INVITED)
+ self.assertEqual(invite.summary, None)
+ yield self._check_notifications(invite.shareeUID, [invite.uid, ])
+
+ yield self._check_notifications("user01", [])
+
+ # Uninvite
+ calendar = yield self.calendarUnderTest(home="user01", name="calendar")
+ yield calendar.uninviteUIDFromShare("group05")
+ noinvites = yield calendar.sharingInvites()
+ self.assertEqual(len(noinvites), 0)
+
+
+ @inlineCallbacks
+ def test_no_self_invite_on_add(self):
+ """
+ Test that the sharee is not invited to their own share when they are added as a member
+ of a group to whom the calendar is shared.
+ """
+
+ record01 = yield self.transactionUnderTest().directoryService().recordWithUID("user01")
+ record02 = yield self.transactionUnderTest().directoryService().recordWithUID("user02")
+
+ @inlineCallbacks
+ def expandedMembers(self, records=None, seen=None):
+
+ if self.uid == "group06":
+ returnValue(frozenset((record01, record02,)))
+ else:
+ returnValue((yield unpatchedExpandedMembers(self, records, seen)))
+
+ unpatchedExpandedMembers = CalendarDirectoryRecordMixin.expandedMembers
+
+ # setup group cacher
+ groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
+ groupsToRefresh = yield groupCacher.groupsToRefresh(self.transactionUnderTest())
+ self.assertEqual(len(groupsToRefresh), 0)
+ wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "group06")
+ self.assertEqual(len(wps), 0)
+
+ yield self._check_notifications("user01", [])
+
+ # Invite
+ calendar = yield self.calendarUnderTest(home="user01", name="calendar")
+ invites = yield calendar.sharingInvites()
+ self.assertEqual(len(invites), 0)
+ self.assertFalse(calendar.isShared())
+
+ yield self._check_notifications("user01", [])
+ shareeViews = yield calendar.inviteUIDToShare("group06", _BIND_MODE_READ)
+ self.assertEqual(len(shareeViews), 1)
+ calendar = yield self.calendarUnderTest(home="user01", name="calendar")
+ invites = yield calendar.sharingInvites()
+ self.assertEqual(len(invites), 1)
+ for invite in invites:
+ shareeView = yield calendar.shareeView(invite.shareeUID)
+ self.assertEqual(invite.ownerUID, "user01")
+ self.assertEqual(invite.uid, shareeView.shareName())
+ self.assertEqual(invite.mode, _BIND_MODE_GROUP)
+ self.assertEqual((yield shareeView.effectiveShareMode()), _BIND_MODE_READ)
+ self.assertEqual(invite.status, _BIND_STATUS_INVITED)
+ self.assertEqual(invite.summary, None)
+ yield self._check_notifications(invite.shareeUID, [invite.uid, ])
+
+ # 1 group members
+ self.patch(CalendarDirectoryRecordMixin, "expandedMembers", expandedMembers)
+
+ wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "group06")
+ self.assertEqual(len(wps), 1)
+ yield self.commit()
+ yield JobItem.waitEmpty(self._sqlCalendarStore.newTransaction, reactor, 60)
+
+ calendar = yield self.calendarUnderTest(home="user01", name="calendar")
+ invites = yield calendar.sharingInvites()
+ self.assertEqual(len(invites), 1)
+ for invite in invites:
+ shareeView = yield calendar.shareeView(invite.shareeUID)
+ self.assertEqual(invite.ownerUID, "user01")
+ self.assertEqual(invite.uid, shareeView.shareName())
+ self.assertEqual(invite.mode, _BIND_MODE_GROUP)
+ self.assertEqual((yield shareeView.effectiveShareMode()), _BIND_MODE_READ)
+ self.assertEqual(invite.status, _BIND_STATUS_INVITED)
+ self.assertEqual(invite.summary, None)
+ yield self._check_notifications(invite.shareeUID, [invite.uid, ])
+
+ yield self._check_notifications("user01", [])
+
+ # Uninvite
+ calendar = yield self.calendarUnderTest(home="user01", name="calendar")
+ yield calendar.uninviteUIDFromShare("group06")
+ noinvites = yield calendar.sharingInvites()
+ self.assertEqual(len(noinvites), 0)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20150626/11417e38/attachment-0001.html>
More information about the calendarserver-changes
mailing list