diff --git a/code/model/SiteTree.php b/code/model/SiteTree.php index 656bcd2489..ea05d31b17 100755 --- a/code/model/SiteTree.php +++ b/code/model/SiteTree.php @@ -1158,10 +1158,11 @@ static public function prepopulate_permission_cache($permission = 'CanEditType', * @param string $siteConfigMethod Method to call on {@link SiteConfig} for toplevel items, e.g. "canEdit" * @param string $globalPermission If the member doesn't have this permission code, don't bother iterating deeper * @param bool $useCached + * @param array $stages Which stages to check permissions against, defaults to both Stage and Live * @return array An map of {@link SiteTree} ID keys to boolean values */ public static function batch_permission_check($ids, $memberID, $typeField, $groupJoinTable, $siteConfigMethod, - $globalPermission = null, $useCached = true) { + $globalPermission = null, $useCached = true, $stages = array('Stage', 'Live')) { if($globalPermission === NULL) $globalPermission = array('CMS_ACCESS_LeftAndMain', 'CMS_ACCESS_CMSMain'); // Sanitise the IDs @@ -1169,7 +1170,7 @@ public static function batch_permission_check($ids, $memberID, $typeField, $grou // This is the name used on the permission cache // converts something like 'CanEditType' to 'edit'. - $cacheKey = strtolower(substr($typeField, 3, -4)) . "-$memberID"; + $cacheKey = strtolower(substr($typeField, 3, -4)) . "-$memberID" . implode('-', $stages); // Default result: nothing editable $result = array_fill_keys($ids, false); @@ -1206,7 +1207,7 @@ public static function batch_permission_check($ids, $memberID, $typeField, $grou $combinedStageResult = array(); - foreach(array('Stage', 'Live') as $stage) { + foreach($stages as $stage) { // Start by filling the array with the pages that actually exist $table = ($stage=='Stage') ? "SiteTree" : "SiteTree_$stage"; @@ -1257,7 +1258,7 @@ public static function batch_permission_check($ids, $memberID, $typeField, $grou } if($groupedByParent) { - $actuallyInherited = self::batch_permission_check(array_keys($groupedByParent), $memberID, $typeField, $groupJoinTable, $siteConfigMethod); + $actuallyInherited = self::batch_permission_check(array_keys($groupedByParent), $memberID, $typeField, $groupJoinTable, $siteConfigMethod, $globalPermission, $useCached, array($stage)); if($actuallyInherited) { $parentIDs = array_keys(array_filter($actuallyInherited)); foreach($parentIDs as $parentID) { diff --git a/tests/model/SiteTreePermissionsTest.php b/tests/model/SiteTreePermissionsTest.php index 90e7fa8e65..efaac31db1 100644 --- a/tests/model/SiteTreePermissionsTest.php +++ b/tests/model/SiteTreePermissionsTest.php @@ -445,5 +445,47 @@ public function testInheritCanEditFromSiteConfig() { $this->session()->inst_set('loggedInAs', $user->ID); $this->assertFalse($page->canEdit($user), 'Website user can\'t edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to OnlyTheseUsers'); } - + + /** + * Ensure that flipping parent / child relationship on live doesn't + * cause infinite loop + */ + public function testMobiusHierarchy() + { + // login as admin to be able to publish + $adminID = $this->logInWithPermission('ADMIN'); + + $parentPage = new Page(); + $parentPage->Title = 'Parent Page'; + $parentPage->doPublish(); + + $childPage = new Page(); + $childPage->Title = 'Child Page'; + $childPage->ParentID = $parentPage->ID; + $childPage->doPublish(); + + //flip parent/child relation + $childPage->ParentID = 0; + $childPage->write(); + + $parentPage->ParentID = $childPage->ID; + $parentPage->write(); + + $this->assertTrue($childPage->isPublished()); + $this->assertTrue($parentPage->isPublished()); + + $result = SiteTree::batch_permission_check(array( + $parentPage->ID, + $childPage->ID, + ), $adminID, 'CanEditType', 'SiteTree_EditorGroups', 'canEditPages'); + + $this->assertArrayHasKey($childPage->ID, $result); + $this->assertArrayHasKey($parentPage->ID, $result); + + // mr potato head can't edit + $this->assertTrue($result[$parentPage->ID]); + $this->assertTrue($result[$childPage->ID]); + + } + }