From 17dde8ff581382af0d4bd23ecbc7ac257410a4ef Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Tue, 30 Aug 2011 18:58:36 +0200 Subject: [PATCH] FEATURE Blacklisting of page types by subsite through Subsite->PageTypeBlacklist (AIR-20) --- code/SiteTreeSubsites.php | 18 ++++++++-- code/Subsite.php | 28 +++++++++++++-- javascript/LeftAndMain_Subsites.js | 18 ++++++++++ tests/SiteTreeSubsitesTest.php | 58 ++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 5 deletions(-) diff --git a/code/SiteTreeSubsites.php b/code/SiteTreeSubsites.php index 110bca5..19d4bcb 100644 --- a/code/SiteTreeSubsites.php +++ b/code/SiteTreeSubsites.php @@ -397,6 +397,18 @@ class SiteTreeSubsites extends SiteTreeDecorator { function cacheKeyComponent() { return 'subsite-'.Subsite::currentSubsiteID(); } -} - -?> + + /** + * @param Member + * @return boolean|null + */ + function canCreate($member = null) { + // Typically called on a singleton, so we're not using the Subsite() relation + $subsite = Subsite::currentSubsite(); + if($subsite && $subsite->exists() && $subsite->PageTypeBlacklist) { + $blacklisted = explode(',', $subsite->PageTypeBlacklist); + // All subclasses need to be listed explicitly + if(in_array($this->owner->class, $blacklisted)) return false; + } + } +} \ No newline at end of file diff --git a/code/Subsite.php b/code/Subsite.php index c2347ec..6f29dc9 100644 --- a/code/Subsite.php +++ b/code/Subsite.php @@ -31,7 +31,10 @@ class Subsite extends DataObject implements PermissionProvider { // Used to hide unfinished/private subsites from public view. // If unset, will default to true - 'IsPublic' => 'Boolean' + 'IsPublic' => 'Boolean', + + // Comma-separated list of disallowed page types + 'PageTypeBlacklist' => 'Text', ); static $has_one = array( @@ -164,6 +167,13 @@ class Subsite extends DataObject implements PermissionProvider { "SubsiteID", $this->ID); $languageSelector = new DropdownField('Language', 'Language', i18n::get_common_locales()); + + $pageTypeMap = array(); + $pageTypes = SiteTree::page_type_classes(); + foreach($pageTypes as $pageType) { + $pageTypeMap[$pageType] = singleton($pageType)->i18n_singular_name(); + } + asort($pageTypeMap); $fields = new FieldSet( new TabSet('Root', @@ -178,7 +188,21 @@ class Subsite extends DataObject implements PermissionProvider { new CheckboxField('DefaultSite', 'Default site', $this->DefaultSite), new CheckboxField('IsPublic', 'Enable public access', $this->IsPublic), - new DropdownField('Theme','Theme', $this->allowedThemes(), $this->Theme) + new DropdownField('Theme','Theme', $this->allowedThemes(), $this->Theme), + + + new LiteralField( + 'PageTypeBlacklistToggle', + sprintf( + '
%s
', + _t('Subsite.PageTypeBlacklistField', 'Disallow page types?') + ) + ), + new CheckboxSetField( + 'PageTypeBlacklist', + false, + $pageTypeMap + ) ) ), new HiddenField('ID', '', $this->ID), diff --git a/javascript/LeftAndMain_Subsites.js b/javascript/LeftAndMain_Subsites.js index b999808..318b08f 100644 --- a/javascript/LeftAndMain_Subsites.js +++ b/javascript/LeftAndMain_Subsites.js @@ -78,6 +78,24 @@ Behaviour.register({ $('Form_EditForm_Subsites').parentNode.style.display = Form.Element.getValue($('Form_EditForm').AccessAllSubsites)==1 ? 'none' : ''; } + }, + + /** + * Binding a visibility toggle anchor to a longer list of checkboxes. + * Hidden by default, unless either the toggle checkbox, or any of the + * actual value checkboxes are selected. + */ + 'a#PageTypeBlacklistToggle': { + onclick: function(e) { + jQuery('#PageTypeBlacklist').toggle(); + } + }, + + '#PageTypeBlacklist': { + initialize: function() { + var hasLimits = Boolean(jQuery(this).find('input:checked').length); + jQuery(this).toggle(hasLimits); + } } }); diff --git a/tests/SiteTreeSubsitesTest.php b/tests/SiteTreeSubsitesTest.php index 27d4881..111f106 100644 --- a/tests/SiteTreeSubsitesTest.php +++ b/tests/SiteTreeSubsitesTest.php @@ -1,8 +1,14 @@ objFromFixture('Subsite_Template', 'main'); $subsite1 = $this->objFromFixture('Subsite_Template', 'subsite1'); @@ -160,4 +166,56 @@ class SiteTreeSubsitesTest extends SapphireTest { $this->assertEquals($p2->ID, SiteTree::get_by_link('test-page')->ID); } + function testPageTypesBlacklistInClassDropdown() { + Session::set("loggedInAs", null); + + $s1 = $this->objFromFixture('Subsite','domaintest1'); + $s2 = $this->objFromFixture('Subsite','domaintest2'); + $page = singleton('SiteTree'); + + $method = new ReflectionMethod($page, 'getClassDropdown'); + $method->setAccessible(true); + + $s1->PageTypeBlacklist = 'SiteTreeSubsitesTest_ClassA,ErrorPage'; + $s1->write(); + + Subsite::changeSubsite($s1); + $this->assertArrayNotHasKey('ErrorPage', $method->invoke($page)); + $this->assertArrayNotHasKey('SiteTreeSubsitesTest_ClassA', $method->invoke($page)); + $this->assertArrayHasKey('SiteTreeSubsitesTest_ClassB', $method->invoke($page)); + + Subsite::changeSubsite($s2); + $this->assertArrayHasKey('ErrorPage', $method->invoke($page)); + $this->assertArrayHasKey('SiteTreeSubsitesTest_ClassA', $method->invoke($page)); + $this->assertArrayHasKey('SiteTreeSubsitesTest_ClassB', $method->invoke($page)); + } + + function testPageTypesBlacklistInCMSMain() { + Session::set("loggedInAs", null); + + $cmsmain = new CMSMain(); + + $s1 = $this->objFromFixture('Subsite','domaintest1'); + $s2 = $this->objFromFixture('Subsite','domaintest2'); + + $s1->PageTypeBlacklist = 'SiteTreeSubsitesTest_ClassA,ErrorPage'; + $s1->write(); + + Subsite::changeSubsite($s1); + $classes = $cmsmain->PageTypes()->column('ClassName'); + $this->assertNotContains('ErrorPage', $classes); + $this->assertNotContains('SiteTreeSubsitesTest_ClassA', $classes); + $this->assertContains('SiteTreeSubsitesTest_ClassB', $classes); + + Subsite::changeSubsite($s2); + $classes = $cmsmain->PageTypes()->column("ClassName"); + $this->assertContains('ErrorPage', $classes); + $this->assertContains('SiteTreeSubsitesTest_ClassA', $classes); + $this->assertContains('SiteTreeSubsitesTest_ClassB', $classes); + } + } + +class SiteTreeSubsitesTest_ClassA extends SiteTree implements TestOnly {} + +class SiteTreeSubsitesTest_ClassB extends SiteTree implements TestOnly {} \ No newline at end of file