From dfdaac48ca38e179efcfb2cfd905baa577b379fd Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Tue, 8 May 2018 06:04:59 +0800 Subject: [PATCH] ENHANCEMENT Backport versioned querystring fix (#2153) * Backport versioned querystring fix * Fix versioned state reset * Fix up tests * Fix permissions test * Linting --- code/controllers/CMSMain.php | 2 +- code/model/SiteTree.php | 17 +-- code/model/SiteTreeFileExtension.php | 24 ++-- tests/controller/ContentControllerTest.php | 14 ++- tests/model/RedirectorPageTest.php | 41 ++++--- tests/model/SiteTreePermissionsTest.php | 133 +++++++++++---------- 6 files changed, 127 insertions(+), 104 deletions(-) diff --git a/code/controllers/CMSMain.php b/code/controllers/CMSMain.php index 2c25e083..46673e55 100644 --- a/code/controllers/CMSMain.php +++ b/code/controllers/CMSMain.php @@ -188,7 +188,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr '/', // trailing slash needed if $action is null! "$action" ); - $this->extend('updateLink', $link); + $this->extend('updateLink', $link, $action); return $link; } diff --git a/code/model/SiteTree.php b/code/model/SiteTree.php index ddaeeac5..230419d0 100755 --- a/code/model/SiteTree.php +++ b/code/model/SiteTree.php @@ -465,7 +465,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * @return string */ public function Link($action = null) { - return Controller::join_links(Director::baseURL(), $this->RelativeLink($action)); + $relativeLink = $this->RelativeLink($action); + $link = Controller::join_links(Director::baseURL(), $relativeLink); + $this->extend('updateLink', $link, $action, $relativeLink); + return $link; } /** @@ -542,7 +545,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * @return string */ public function getAbsoluteLiveLink($includeStageEqualsLive = true) { - $oldStage = Versioned::current_stage(); + $oldMode = Versioned::get_reading_mode(); Versioned::reading_stage('Live'); $live = Versioned::get_one_by_stage('SiteTree', 'Live', array( '"SiteTree"."ID"' => $this->ID @@ -556,7 +559,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid $link = null; } - Versioned::reading_stage($oldStage); + Versioned::set_reading_mode($oldMode); return $link; } @@ -2429,7 +2432,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid $this->invokeWithExtensions('onBeforeUnpublish', $this); - $origStage = Versioned::current_stage(); + $origMode = Versioned::get_reading_mode(); Versioned::reading_stage('Live'); // We should only unpublish virtualpages that exist on live @@ -2445,7 +2448,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // $page->write() calls syncLinkTracking, which does all the hard work for us. $page->write(); } - Versioned::reading_stage($origStage); + Versioned::set_reading_mode($origMode); // Unpublish any published virtual pages if ($virtualPages) foreach($virtualPages as $vp) $vp->doUnpublish(); @@ -2521,7 +2524,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing('SiteTree', false); } - $oldStage = Versioned::current_stage(); + $oldMode = Versioned::get_reading_mode(); Versioned::reading_stage('Stage'); $this->forceChange(); $this->write(); @@ -2534,7 +2537,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid $page->write(); } - Versioned::reading_stage($oldStage); + Versioned::set_reading_mode($oldMode); $this->invokeWithExtensions('onAfterRestoreToStage', $this); diff --git a/code/model/SiteTreeFileExtension.php b/code/model/SiteTreeFileExtension.php index a763207a..3766bf1e 100644 --- a/code/model/SiteTreeFileExtension.php +++ b/code/model/SiteTreeFileExtension.php @@ -60,7 +60,7 @@ class SiteTreeFileExtension extends DataExtension { SiteTreeFileExtension::BackLinkTracking() have been deprecated. Please manipluate the returned list directly.', Deprecation::SCOPE_GLOBAL); } - + if(class_exists("Subsite")){ $rememberSubsiteFilter = Subsite::$disable_subsite_filter; Subsite::disable_subsite_filter(true); @@ -71,7 +71,7 @@ class SiteTreeFileExtension extends DataExtension { SiteTreeFileExtension::BackLinkTracking() have been deprecated. Please manipluate the returned list directly.', Deprecation::SCOPE_GLOBAL); } - + $links = $this->owner->getManyManyComponents('BackLinkTracking'); if($this->owner->ID) { $links = $links @@ -80,14 +80,14 @@ class SiteTreeFileExtension extends DataExtension { ->limit($limit); } $this->owner->extend('updateBackLinkTracking', $links); - + if(class_exists("Subsite")){ Subsite::disable_subsite_filter($rememberSubsiteFilter); } - + return $links; } - + /** * @todo Unnecessary shortcut for AssetTableField, coupled with cms module. * @@ -101,7 +101,7 @@ class SiteTreeFileExtension extends DataExtension { return 0; } } - + /** * Updates link tracking. */ @@ -110,7 +110,7 @@ class SiteTreeFileExtension extends DataExtension { // site does its thing $brokenPageIDs = $this->owner->BackLinkTracking()->column("ID"); if($brokenPageIDs) { - $origStage = Versioned::current_stage(); + $origMode = Versioned::get_reading_mode(); // This will syncLinkTracking on draft Versioned::reading_stage('Stage'); @@ -124,10 +124,10 @@ class SiteTreeFileExtension extends DataExtension { $brokenPage->write(); } - Versioned::reading_stage($origStage); + Versioned::set_reading_mode($origMode); } } - + /** * Rewrite links to the $old file to now point to the $new file. * @@ -138,15 +138,15 @@ class SiteTreeFileExtension extends DataExtension { */ public function updateLinks($old, $new) { if(class_exists('Subsite')) Subsite::disable_subsite_filter(true); - + $pages = $this->owner->BackLinkTracking(); $summary = ""; if($pages) { foreach($pages as $page) $page->rewriteFileURL($old,$new); } - + if(class_exists('Subsite')) Subsite::disable_subsite_filter(false); } - + } diff --git a/tests/controller/ContentControllerTest.php b/tests/controller/ContentControllerTest.php index ce2c4a21..cf2aa40f 100755 --- a/tests/controller/ContentControllerTest.php +++ b/tests/controller/ContentControllerTest.php @@ -7,16 +7,21 @@ class ContentControllerTest extends FunctionalTest { protected static $fixture_file = 'ContentControllerTest.yml'; - protected static $use_draft_site = true; - protected static $disable_themes = true; + public function setUp() { + parent::setUp(); + Config::inst()->update('Director', 'alternate_base_url', '/'); + $this->useDraftSite(false); + } + /** * Test that nested pages, basic actions, and nested/non-nested URL switching works properly */ public function testNestedPages() { RootURLController::reset(); + $this->useDraftSite(true); Config::inst()->update('SiteTree', 'nested_urls', true); $this->assertEquals('Home Page', $this->get('/')->getBody()); @@ -52,7 +57,7 @@ class ContentControllerTest extends FunctionalTest { */ public function testChildrenOf() { $controller = new ContentController(); - + $this->useDraftSite(true); Config::inst()->update('SiteTree', 'nested_urls', true); $this->assertEquals(1, $controller->ChildrenOf('/')->Count()); @@ -70,6 +75,7 @@ class ContentControllerTest extends FunctionalTest { public function testDeepNestedURLs() { Config::inst()->update('SiteTree', 'nested_urls', true); + $this->useDraftSite(true); $page = new Page(); $page->URLSegment = 'base-page'; @@ -126,7 +132,7 @@ class ContentControllerTest extends FunctionalTest { $this->assertContains( sprintf('Testlink', $linkedPage->Link()), - $this->get($page->RelativeLink())->getBody(), + $this->get($page->Link())->getBody(), '"sitetree_link" shortcodes get parsed properly' ); } diff --git a/tests/model/RedirectorPageTest.php b/tests/model/RedirectorPageTest.php index 8bdd7e1e..199a7294 100644 --- a/tests/model/RedirectorPageTest.php +++ b/tests/model/RedirectorPageTest.php @@ -2,47 +2,58 @@ class RedirectorPageTest extends FunctionalTest { protected static $fixture_file = 'RedirectorPageTest.yml'; - protected static $use_draft_site = true; + protected $autoFollowRedirection = false; - + + public function setUp() { + parent::setUp(); + $this->useDraftSite(false); + $this->logInWithPermission('ADMIN'); + foreach (SiteTree::get() as $page) { + $page->doPublish(); + } + Config::inst()->update('Director', 'alternate_base_url', '/'); + } + public function testGoodRedirectors() { /* For good redirectors, the final destination URL will be returned */ $this->assertEquals("http://www.google.com", $this->objFromFixture('RedirectorPage','goodexternal')->Link()); - $this->assertEquals(Director::baseURL() . "redirection-dest/", $this->objFromFixture('RedirectorPage','goodinternal')->redirectionLink()); - $this->assertEquals(Director::baseURL() . "redirection-dest/", $this->objFromFixture('RedirectorPage','goodinternal')->Link()); + $this->assertEquals("/redirection-dest/", $this->objFromFixture('RedirectorPage','goodinternal')->redirectionLink()); + $this->assertEquals("/redirection-dest/", $this->objFromFixture('RedirectorPage','goodinternal')->Link()); } public function testEmptyRedirectors() { /* If a redirector page is misconfigured, then its link method will just return the usual URLSegment-generated value */ $page1 = $this->objFromFixture('RedirectorPage','badexternal'); - $this->assertEquals(Director::baseURL() . 'bad-external/', $page1->Link()); + $this->assertEquals('/bad-external/', $page1->Link()); /* An error message will be shown if you visit it */ - $content = $this->get(Director::makeRelative($page1->Link()))->getBody(); + $content = $this->get($page1->Link())->getBody(); $this->assertContains('message-setupWithoutRedirect', $content); /* This also applies for internal links */ $page2 = $this->objFromFixture('RedirectorPage','badinternal'); - $this->assertEquals(Director::baseURL() . 'bad-internal/', $page2->Link()); - $content = $this->get(Director::makeRelative($page2->Link()))->getBody(); + $this->assertEquals('/bad-internal/', $page2->Link()); + $content = $this->get($page2->Link())->getBody(); $this->assertContains('message-setupWithoutRedirect', $content); } public function testReflexiveAndTransitiveInternalRedirectors() { /* Reflexive redirectors are those that point to themselves. They should behave the same as an empty redirector */ + /** @var RedirectorPage $page */ $page = $this->objFromFixture('RedirectorPage','reflexive'); - $this->assertEquals(Director::baseURL() . 'reflexive/', $page->Link()); - $content = $this->get(Director::makeRelative($page->Link()))->getBody(); + $this->assertEquals('/reflexive/', $page->Link()); + $content = $this->get($page->Link())->getBody(); $this->assertContains('message-setupWithoutRedirect', $content); /* Transitive redirectors are those that point to another redirector page. They should send people to the URLSegment * of the destination page - the middle-stop, so to speak. That should redirect to the final destination */ - $page = $this->objFromFixture('RedirectorPage','transitive'); - $this->assertEquals(Director::baseURL() . 'good-internal/', $page->Link()); - + $page = $this->objFromFixture('RedirectorPage', 'transitive'); + $this->assertEquals('/good-internal/', $page->Link()); + $this->autoFollowRedirection = false; - $response = $this->get(Director::makeRelative($page->Link())); - $this->assertEquals(Director::baseURL() . "redirection-dest/", $response->getHeader("Location")); + $response = $this->get($page->Link()); + $this->assertEquals("/redirection-dest/", $response->getHeader("Location")); } public function testExternalURLGetsPrefixIfNotSet() { diff --git a/tests/model/SiteTreePermissionsTest.php b/tests/model/SiteTreePermissionsTest.php index efaac31d..7a5bbee5 100644 --- a/tests/model/SiteTreePermissionsTest.php +++ b/tests/model/SiteTreePermissionsTest.php @@ -8,61 +8,64 @@ */ class SiteTreePermissionsTest extends FunctionalTest { protected static $fixture_file = "SiteTreePermissionsTest.yml"; - + protected $illegalExtensions = array( 'SiteTree' => array('SiteTreeSubsites') ); - + public function setUp() { parent::setUp(); - + $this->useDraftSite(); - + // we're testing HTTP status codes before being redirected to login forms $this->autoFollowRedirection = false; } - + public function testAccessingStageWithBlankStage() { $this->useDraftSite(false); $this->autoFollowRedirection = false; - + $page = $this->objFromFixture('Page', 'draftOnlyPage'); if($member = Member::currentUser()) { $member->logOut(); } - + $response = $this->get($page->URLSegment . '?stage=Live'); - $this->assertEquals($response->getStatusCode(), '404'); - + $this->assertEquals(404, $response->getStatusCode()); + $response = $this->get($page->URLSegment . '?stage='); - $this->assertEquals($response->getStatusCode(), '404'); - + $this->assertEquals(404, $response->getStatusCode()); + // should be prompted for a login try { $response = $this->get($page->URLSegment . '?stage=Stage'); } catch(SS_HTTPResponse_Exception $responseException) { $response = $responseException->getResponse(); } - $this->assertEquals($response->getStatusCode(), '302'); + $this->assertEquals(302, $response->getStatusCode()); $this->assertContains( Config::inst()->get('Security', 'login_url'), $response->getHeader('Location') ); - + $this->logInWithPermission('ADMIN'); - + $response = $this->get($page->URLSegment . '?stage=Live'); - $this->assertEquals($response->getStatusCode(), '404'); - - $response = $this->get($page->URLSegment . '?stage=Stage'); - $this->assertEquals($response->getStatusCode(), '200'); - + $this->assertEquals(404, $response->getStatusCode()); + $response = $this->get($page->URLSegment . '?stage='); - $this->assertEquals($response->getStatusCode(), '404'); + $this->assertEquals(404, $response->getStatusCode()); + + $response = $this->get($page->URLSegment . '?stage=Stage'); + $this->assertEquals(200, $response->getStatusCode()); + + $response = $this->get($page->URLSegment . '?stage='); + $this->assertEquals(200, $response->getStatusCode()); } - + public function testPermissionCheckingWorksOnDeletedPages() { // Set up fixture - a published page deleted from draft $this->logInWithPermission("ADMIN"); @@ -77,18 +80,18 @@ class SiteTreePermissionsTest extends FunctionalTest { // subadmin has edit rights on that page $member = $this->objFromFixture('Member','subadmin'); $member->logIn(); - + // Test can_edit_multiple $this->assertEquals( array($pageID => true), SiteTree::can_edit_multiple(array($pageID), $member->ID) ); - + // Test canEdit $member->logIn(); $this->assertTrue($page->canEdit()); } - + public function testPermissionCheckingWorksOnUnpublishedPages() { // Set up fixture - an unpublished page $this->logInWithPermission("ADMIN"); @@ -125,7 +128,7 @@ class SiteTreePermissionsTest extends FunctionalTest { // subadmin had edit rights on that page, but now it's gone $member = $this->objFromFixture('Member','subadmin'); $member->logIn(); - + $this->assertFalse($page->canEdit()); } @@ -142,19 +145,19 @@ class SiteTreePermissionsTest extends FunctionalTest { $editor = $this->objFromFixture('Member', 'editor'); $websiteuser = $this->objFromFixture('Member', 'websiteuser'); - + $this->assertTrue($page->canViewStage('Live', $websiteuser)); $this->assertFalse($page->canViewStage('Stage', $websiteuser)); - + $this->assertTrue($page->canViewStage('Live', $editor)); $this->assertTrue($page->canViewStage('Stage', $editor)); $this->useDraftSite(); } - + public function testAccessTabOnlyDisplaysWithGrantAccessPermissions() { $page = $this->objFromFixture('Page', 'standardpage'); - + $subadminuser = $this->objFromFixture('Member', 'subadmin'); $this->session()->inst_set('loggedInAs', $subadminuser->ID); $fields = $page->getSettingsFields(); @@ -166,7 +169,7 @@ class SiteTreePermissionsTest extends FunctionalTest { $fields->dataFieldByName('CanEditType')->isReadonly(), 'Users with SITETREE_GRANT_ACCESS permission can change "edit" permissions in cms fields' ); - + $editoruser = $this->objFromFixture('Member', 'editor'); $this->session()->inst_set('loggedInAs', $editoruser->ID); $fields = $page->getSettingsFields(); @@ -178,13 +181,13 @@ class SiteTreePermissionsTest extends FunctionalTest { $fields->dataFieldByName('CanEditType')->isReadonly(), 'Users without SITETREE_GRANT_ACCESS permission cannot change "edit" permissions in cms fields' ); - + $this->session()->inst_set('loggedInAs', null); } - + public function testRestrictedViewLoggedInUsers() { $page = $this->objFromFixture('Page', 'restrictedViewLoggedInUsers'); - + // unauthenticated users $this->assertFalse( $page->canView(FALSE), @@ -197,7 +200,7 @@ class SiteTreePermissionsTest extends FunctionalTest { 302, 'Unauthenticated members cant view a page marked as "Viewable for any logged in users"' ); - + // website users $websiteuser = $this->objFromFixture('Member', 'websiteuser'); $this->assertTrue( @@ -213,10 +216,10 @@ class SiteTreePermissionsTest extends FunctionalTest { ); $this->session()->inst_set('loggedInAs', null); } - + public function testRestrictedViewOnlyTheseUsers() { $page = $this->objFromFixture('Page', 'restrictedViewOnlyWebsiteUsers'); - + // unauthenticcated users $this->assertFalse( $page->canView(FALSE), @@ -229,7 +232,7 @@ class SiteTreePermissionsTest extends FunctionalTest { 302, 'Unauthenticated members cant view a page marked as "Viewable by these groups"' ); - + // subadmin users $subadminuser = $this->objFromFixture('Member', 'subadmin'); $this->assertFalse( @@ -244,7 +247,7 @@ class SiteTreePermissionsTest extends FunctionalTest { 'Authenticated members cant view a page marked as "Viewable by these groups" if theyre not in the listed groups' ); $this->session()->inst_set('loggedInAs', null); - + // website users $websiteuser = $this->objFromFixture('Member', 'websiteuser'); $this->assertTrue( @@ -260,16 +263,16 @@ class SiteTreePermissionsTest extends FunctionalTest { ); $this->session()->inst_set('loggedInAs', null); } - + public function testRestrictedEditLoggedInUsers() { $page = $this->objFromFixture('Page', 'restrictedEditLoggedInUsers'); - + // unauthenticcated users $this->assertFalse( $page->canEdit(FALSE), 'Unauthenticated members cant edit a page marked as "Editable by logged in users"' ); - + // website users $websiteuser = $this->objFromFixture('Member', 'websiteuser'); $websiteuser->logIn(); @@ -277,7 +280,7 @@ class SiteTreePermissionsTest extends FunctionalTest { $page->canEdit($websiteuser), 'Authenticated members cant edit a page marked as "Editable by logged in users" if they dont have cms permissions' ); - + // subadmin users $subadminuser = $this->objFromFixture('Member', 'subadmin'); $this->assertTrue( @@ -285,23 +288,23 @@ class SiteTreePermissionsTest extends FunctionalTest { 'Authenticated members can edit a page marked as "Editable by logged in users" if they have cms permissions and belong to any of these groups' ); } - + public function testRestrictedEditOnlySubadminGroup() { $page = $this->objFromFixture('Page', 'restrictedEditOnlySubadminGroup'); - + // unauthenticated users $this->assertFalse( $page->canEdit(FALSE), 'Unauthenticated members cant edit a page marked as "Editable by these groups"' ); - + // subadmin users $subadminuser = $this->objFromFixture('Member', 'subadmin'); $this->assertTrue( $page->canEdit($subadminuser), 'Authenticated members can view a page marked as "Editable by these groups" if theyre in the listed groups' ); - + // website users $websiteuser = $this->objFromFixture('Member', 'websiteuser'); $this->assertFalse( @@ -309,11 +312,11 @@ class SiteTreePermissionsTest extends FunctionalTest { 'Authenticated members cant edit a page marked as "Editable by these groups" if theyre not in the listed groups' ); } - + public function testRestrictedViewInheritance() { $parentPage = $this->objFromFixture('Page', 'parent_restrictedViewOnlySubadminGroup'); $childPage = $this->objFromFixture('Page', 'child_restrictedViewOnlySubadminGroup'); - + // unauthenticated users $this->assertFalse( $childPage->canView(FALSE), @@ -326,7 +329,7 @@ class SiteTreePermissionsTest extends FunctionalTest { 302, 'Unauthenticated members cant view a page marked as "Viewable by these groups" by inherited permission' ); - + // subadmin users $subadminuser = $this->objFromFixture('Member', 'subadmin'); $this->assertTrue( @@ -342,17 +345,17 @@ class SiteTreePermissionsTest extends FunctionalTest { ); $this->session()->inst_set('loggedInAs', null); } - + public function testRestrictedEditInheritance() { $parentPage = $this->objFromFixture('Page', 'parent_restrictedEditOnlySubadminGroup'); $childPage = $this->objFromFixture('Page', 'child_restrictedEditOnlySubadminGroup'); - + // unauthenticated users $this->assertFalse( $childPage->canEdit(FALSE), 'Unauthenticated members cant edit a page marked as "Editable by these groups" by inherited permission' ); - + // subadmin users $subadminuser = $this->objFromFixture('Member', 'subadmin'); $this->assertTrue( @@ -360,11 +363,11 @@ class SiteTreePermissionsTest extends FunctionalTest { 'Authenticated members can edit a page marked as "Editable by these groups" if theyre in the listed groups by inherited permission' ); } - + public function testDeleteRestrictedChild() { $parentPage = $this->objFromFixture('Page', 'deleteTestParentPage'); $childPage = $this->objFromFixture('Page', 'deleteTestChildPage'); - + // unauthenticated users $this->assertFalse( $parentPage->canDelete(FALSE), @@ -375,13 +378,13 @@ class SiteTreePermissionsTest extends FunctionalTest { 'Unauthenticated members cant delete a child page marked as "Editable by these groups"' ); } - + public function testRestrictedEditLoggedInUsersDeletedFromStage() { $page = $this->objFromFixture('Page', 'restrictedEditLoggedInUsers'); $pageID = $page->ID; - + $this->logInWithPermission("ADMIN"); - + $page->doPublish(); $page->deleteFromStage('Stage'); @@ -402,40 +405,40 @@ class SiteTreePermissionsTest extends FunctionalTest { $siteconfig = $this->objFromFixture('SiteConfig', 'default'); $editor = $this->objFromFixture('Member', 'editor'); $editorGroup = $this->objFromFixture('Group', 'editorgroup'); - + $siteconfig->CanViewType = 'Anyone'; $siteconfig->write(); $this->assertTrue($page->canView(FALSE), 'Anyone can view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to LoggedInUsers'); - + $siteconfig->CanViewType = 'LoggedInUsers'; $siteconfig->write(); $this->assertFalse($page->canView(FALSE), 'Anonymous can\'t view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to LoggedInUsers'); - + $siteconfig->CanViewType = 'LoggedInUsers'; $siteconfig->write(); $this->assertTrue($page->canView($editor), 'Users can view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to LoggedInUsers'); - + $siteconfig->CanViewType = 'OnlyTheseUsers'; $siteconfig->ViewerGroups()->add($editorGroup); $siteconfig->write(); $this->assertTrue($page->canView($editor), 'Editors can view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to OnlyTheseUsers'); $this->assertFalse($page->canView(FALSE), 'Anonymous can\'t view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to OnlyTheseUsers'); } - + public function testInheritCanEditFromSiteConfig() { $page = $this->objFromFixture('Page', 'inheritWithNoParent'); $siteconfig = $this->objFromFixture('SiteConfig', 'default'); $editor = $this->objFromFixture('Member', 'editor'); $user = $this->objFromFixture('Member', 'websiteuser'); $editorGroup = $this->objFromFixture('Group', 'editorgroup'); - + $siteconfig->CanEditType = 'LoggedInUsers'; $siteconfig->write(); - + $this->assertFalse($page->canEdit(FALSE), 'Anonymous can\'t edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to LoggedInUsers'); $this->session()->inst_set('loggedInAs', $editor->ID); $this->assertTrue($page->canEdit(), 'Users can edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to LoggedInUsers'); - + $siteconfig->CanEditType = 'OnlyTheseUsers'; $siteconfig->EditorGroups()->add($editorGroup); $siteconfig->write();