diff --git a/code/model/SiteTree.php b/code/model/SiteTree.php index 7d845aa7..01c0a089 100644 --- a/code/model/SiteTree.php +++ b/code/model/SiteTree.php @@ -682,25 +682,21 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid } /** - * This function should return true if the current user can add children - * to this page. It can be overloaded to customise the security model for an - * application. + * This function should return true if the current user can execute this action. + * It can be overloaded to customise the security model for an application. + * + * Slightly altered from parent behaviour in {@link DataObject->can()}: + * - Checks for existence of a method named "can<$perm>()" on the object + * - Calls decorators and only returns for FALSE "vetoes" + * - Falls back to {@link Permission::check()} + * - Does NOT check for many-many relations named "Can<$perm>" * - * Returns true if the member is allowed to do the given action. - * - * @uses DataExtension->can() - * - * If a page is set to inherit, but has no parent, it inherits from - * {@link SiteConfig} + * @uses DataObjectDecorator->can() * * @param string $perm The permission to be checked, such as 'View'. * @param Member $member The member whose permissions need checking. - * Defaults to the currently logged in user. - * - * @return boolean True if the the member is allowed to do the given - * action. - * - * @todo Check we get a endless recursion if we use parent::can() + * Defaults to the currently logged in user. + * @return boolean True if the the member is allowed to do the given action. */ function can($perm, $member = null) { if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) { @@ -709,7 +705,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if($member && Permission::checkMember($member, "ADMIN")) return true; - if(method_exists($this, 'can' . ucfirst($perm))) { + if(is_string($perm) && method_exists($this, 'can' . ucfirst($perm))) { $method = 'can' . ucfirst($perm); return $this->$method($member); } @@ -717,7 +713,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid $results = $this->extend('can', $member); if($results && is_array($results)) if(!min($results)) return false; - return true; + return ($member && Permission::checkMember($member, $perm)); } @@ -2293,7 +2289,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid /** * Get the class dropdown used in the CMS to change the class of a page. * This returns the list of options in the drop as a Map from class name - * to text in dropdown. + * to text in dropdown. Filters by {@link SiteTree->canCreate()}, + * as well as {@link SiteTree::$needs_permission}. * * @return array */ @@ -2306,6 +2303,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid foreach($classes as $class) { $instance = singleton($class); if((($instance instanceof HiddenClass) || !$instance->canCreate()) && ($class != $this->class)) continue; + + if($perms = $instance->stat('need_permission')) { + if(!$this->can($perms)) continue; + } $pageTypeName = $instance->i18n_singular_name(); diff --git a/tests/model/SiteTreeTest.php b/tests/model/SiteTreeTest.php index cf429926..70948f88 100644 --- a/tests/model/SiteTreeTest.php +++ b/tests/model/SiteTreeTest.php @@ -825,6 +825,23 @@ class SiteTreeTest extends SapphireTest { $valid = $classCext->validate(); $this->assertFalse($valid->valid(), "Doesnt allow child where only parent class is allowed on parent node, and asterisk prefixing is used"); } + + function testClassDropdown() { + $sitetree = new SiteTree(); + $method = new ReflectionMethod($sitetree, 'getClassDropdown'); + $method->setAccessible(true); + + Session::set("loggedInAs", null); + $this->assertArrayNotHasKey('SiteTreeTest_ClassA', $method->invoke($sitetree)); + + $this->loginWithPermission('ADMIN'); + $this->assertArrayHasKey('SiteTreeTest_ClassA', $method->invoke($sitetree)); + + $this->loginWithPermission('CMS_ACCESS_CMSMain'); + $this->assertArrayHasKey('SiteTreeTest_ClassA', $method->invoke($sitetree)); + + Session::set("loggedInAs", null); + } } /**#@+