FEATURE Allowing translation of SiteConfig (including toplevel permission groups)

BUGFIX Fixed SiteConfig->canView()/canEdit() to respect empty CanViewType/CanEditType assignments.

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/branches/2.4@97370 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2010-01-21 10:00:40 +00:00 committed by Sam Minnee
parent e08667ead5
commit 3e8526960b
6 changed files with 238 additions and 38 deletions

View File

@ -1,7 +1,14 @@
<?php
/**
* Sitewide configuration
* Sitewide configuration.
*
* h2. Translation
*
* To enable translation of configurations alongside the {@link Translatable} extension.
* This also allows assigning language-specific toplevel permissions for viewing and editing
* pages, in addition to the normal `TRANSLATE_*`/`TRANSLATE_ALL` permissions.
*
* Object::add_extension('SiteConig', 'Translatable');
*
* @author Tom Rix
* @package cms
@ -60,6 +67,13 @@ class SiteConfig extends DataObject {
$editorsOptionsField->setSource($editorsOptionsSource);
$topLevelCreatorsOptionsField->setSource($editorsOptionsSource);
// Translatable doesn't handle updateCMSFields on DataObjects,
// so add it here to save the current Locale,
// because onBeforeWrite does not work.
if(Object::has_extension('SiteConfig',"Translatable")){
$fields->push(new HiddenField("Locale"));
}
if (!Permission::check('EDIT_SITECONFIG')) {
$fields->makeFieldReadonly($viewersOptionsField);
@ -96,16 +110,22 @@ class SiteConfig extends DataObject {
}
/**
* Get the current sites SiteConfig
* Get the current sites SiteConfig, and creates a new one
* through {@link make_site_config()} if none is found.
*
* @param string $locale
* @return SiteConfig
*/
static function current_site_config() {
$siteConfig = DataObject::get_one('SiteConfig');
if (!$siteConfig) {
self::make_site_config();
static function current_site_config($locale = null) {
if(Object::has_extension('SiteConfig',"Translatable")){
$locale = isset($locale) ? $locale : Translatable::get_current_locale();
$siteConfig = Translatable::get_one_by_locale('SiteConfig', $locale);
} else {
$siteConfig = DataObject::get_one('SiteConfig');
}
if (!$siteConfig) $siteConfig = self::make_site_config($locale);
return $siteConfig;
}
@ -122,18 +142,37 @@ class SiteConfig extends DataObject {
}
/**
* Make a default site config if there isn't on already
*
* @return void
* Create SiteConfig with defaults from language file.
* if Translatable is enabled on SiteConfig, see if one already exist
* and use those values for the translated defaults.
*
* @param string $locale
* @return SiteConfig
*/
static function make_site_config() {
if(!DataObject::get_one('SiteConfig')){
$siteConfig = new SiteConfig();
$siteConfig->Title = 'Your Site Name';
$siteConfig->Tagline = 'your tagline here';
$siteConfig->write();
static function make_site_config($locale = null) {
if(!$locale) $locale = Translatable::get_current_locale();
$siteConfig = new SiteConfig();
$siteConfig->Title = _t('SiteConfig.SITENAMEDEFAULT',"Your Site Name");
$siteConfig->Tagline = _t('SiteConfig.TAGLINEDEFAULT',"your tagline here");
if($siteConfig->hasExtension('Translatable')){
$defaultConfig = DataObject::get_one('SiteConfig');
if($defaultConfig){
$siteConfig->Title = $defaultConfig->Title;
$siteConfig->Tagline = $defaultConfig->Tagline;
}
// TODO Copy view/edit group settings
// set the correct Locale
$siteConfig->Locale = $locale;
}
}
$siteConfig->write();
return $siteConfig;
}
/**
* Can a user view pages on this site? This method is only
@ -144,17 +183,15 @@ class SiteConfig extends DataObject {
* @return boolean
*/
public function canView($member = null) {
if ($this->CanViewType == 'Anyone') return true;
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
$member = Member::currentUserID();
}
if(!$member) $member = Member::currentUserID();
if($member && is_numeric($member)) $member = DataObject::get_by_id('Member', $member);
if (!$this->CanViewType || $this->CanViewType == 'Anyone') return true;
// check for any logged-in users
if($this->CanViewType == 'LoggedInUsers' && $member) return true;
// check for specific groups
if($member && is_numeric($member)) $member = DataObject::get_by_id('Member', $member);
if($this->CanViewType == 'OnlyTheseUsers' && $member && $member->inGroups($this->ViewerGroups())) return true;
return false;
@ -169,18 +206,15 @@ class SiteConfig extends DataObject {
* @return boolean
*/
public function canEdit($member = null) {
if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
$member = Member::currentUserID();
}
if(!$member) $member = Member::currentUserID();
if($member && is_numeric($member)) $member = DataObject::get_by_id('Member', $member);
// check for any logged-in users
if($this->CanEditType == 'LoggedInUsers' && $member) return true;
if(!$this->CanEditType || $this->CanEditType == 'LoggedInUsers' && $member) return true;
// check for specific groups
if($member && is_numeric($member)) $member = DataObject::get_by_id('Member', $member);
if($this->CanEditType == 'OnlyTheseUsers' && $member && $member->inGroups($this->EditorGroups())) return true;
return false;
}

View File

@ -734,7 +734,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
// check for inherit
if($this->CanViewType == 'Inherit') {
if($this->ParentID) return $this->Parent()->canView($member);
else return SiteConfig::current_site_config()->canView($member);
else return $this->getSiteConfig()->canView($member);
}
// check for any logged-in users
@ -857,7 +857,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
// decorated access checks
$results = $this->extend('canEdit', $memberID);
if($results && is_array($results)) if(!min($results)) return false;
if($this->ID) {
// Check cache (the can_edit_multiple call below will also do this, but this is quicker)
if(isset(self::$cache_permissions['edit'][$this->ID])) {
@ -866,14 +866,14 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
// Regular canEdit logic is handled by can_edit_multiple
$results = self::can_edit_multiple(array($this->ID), $memberID);
// If this page no longer exists in stage/live results won't contain the page.
// Fail-over to false
return isset($results[$this->ID]) ? $results[$this->ID] : false;
// Default for unsaved pages
} else {
return $this->SiteConfig->canEdit();
return $this->getSiteConfig()->canEdit($member);
}
}
@ -918,8 +918,13 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* Stub method to get the site config, provided so it's easy to override
*/
function getSiteConfig() {
if ($this->hasMethod('alternateSiteConfig')) return $this->alternateSiteConfig();
return SiteConfig::current_site_config();
if ($this->hasMethod('alternateSiteConfig')) {
return $this->alternateSiteConfig();
} elseif($this->hasExtension('Translatable')) {
return SiteConfig::current_site_config($this->Locale);
} else {
return SiteConfig::current_site_config();
}
}

View File

@ -76,6 +76,12 @@
* <h2>Usage for SiteTree</h2>
*
* Translatable can be used for subclasses of {@link SiteTree} as well.
*
* <code>
* Object::add_extension('SiteTree', 'Translatable');
* Object::add_extension('SiteConig', 'Translatable');
* </code>
*
* If a child page translation is requested without the parent
* page already having a translation in this language, the extension
* will recursively create translations up the tree.
@ -1167,7 +1173,6 @@ class Translatable extends DataObjectDecorator implements PermissionProvider {
*/
function canEdit($member) {
if(!$this->owner->Locale) return true;
return $this->owner->canTranslate($member, $this->owner->Locale);
}
@ -1219,6 +1224,11 @@ class Translatable extends DataObjectDecorator implements PermissionProvider {
$locales = self::get_allowed_locales();
// Fall back to any locales used in existing translations (see #4939)
if(!$locales) {
$locales = DB::query('SELECT "Locale" FROM "SiteTree" GROUP BY "Locale"')->column();
}
$permissions = array();
if($locales) foreach($locales as $locale) {
$localeName = i18n::get_locale_name($locale);

View File

@ -663,6 +663,12 @@ $lang['en_US']['SiteConfig']['SINGULARNAME'] = array(
50,
'Singular name of the object, used in dropdowns and to generally identify a single object in the interface'
);
$lang['en_US']['SiteConfig']['SITENAMEDEFAULT'] = 'Your Site Name';
$lang['en_US']['SiteConfig']['SITETAGLINE'] = 'Site Tagline/Slogan';
$lang['en_US']['SiteConfig']['SITETITLE'] = 'Site title';
$lang['en_US']['SiteConfig']['TAGLINEDEFAULT'] = 'your tagline here';
$lang['en_US']['SiteConfig']['TOPLEVELCREATE'] = 'Who can create pages in the root of the site?';
$lang['en_US']['SiteConfig']['VIEWHEADER'] = 'Who can view pages on this site?';
$lang['en_US']['SiteTree']['ACCESSANYONE'] = 'Anyone';
$lang['en_US']['SiteTree']['ACCESSHEADER'] = 'Who can view this page?';
$lang['en_US']['SiteTree']['ACCESSLOGGEDIN'] = 'Logged-in users';
@ -764,6 +770,7 @@ $lang['en_US']['SiteTree']['TABMETA'] = 'Metadata';
$lang['en_US']['SiteTree']['TABREPORTS'] = 'Reports';
$lang['en_US']['SiteTree']['TODOHELP'] = '<p>You can use this to keep track of work that needs to be done to the content of your site. To see all your pages with to do information, open the \'Site Reports\' window on the left and select \'To Do\'</p>';
$lang['en_US']['SiteTree']['TOPLEVEL'] = 'Site Content (Top Level)';
$lang['en_US']['SiteTree']['TOPLEVELCREATORGROUPS'] = 'Top level creators';
$lang['en_US']['SiteTree']['ToDo'] = 'Todo Notes';
$lang['en_US']['SiteTree']['URL'] = 'URL';
$lang['en_US']['SiteTree']['URLSegment'] = array(

View File

@ -0,0 +1,58 @@
<?php
/**
* @package sapphire
* @subpackage tests
*
* Note: Most of the permission-related SiteConfig tests are located in
* SiteTreePermissionsTest
*/
class SiteConfigTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/model/SiteConfigTest.yml';
protected $requiredExtensions = array(
'SiteTree' => array('Translatable'),
'SiteConfig' => array('Translatable'),
);
private $origLocale;
function setUp() {
parent::setUp();
$this->origLocale = Translatable::default_locale();
Translatable::set_default_locale("en_US");
}
function tearDown() {
Translatable::set_default_locale($this->origLocale);
Translatable::set_current_locale($this->origLocale);
parent::tearDown();
}
function testCurrentCreatesDefaultForLocale() {
$configEn = SiteConfig::current_site_config();
$configFr = SiteConfig::current_site_config('fr_FR');
$this->assertType('SiteConfig', $configFr);
$this->assertEquals($configFr->Locale, 'fr_FR');
$this->assertEquals($configFr->Title, $configEn->Title, 'Copies title from existing config');
}
function testCanEditTranslatedRootPages() {
$configEn = $this->objFromFixture('SiteConfig', 'en_US');
$configDe = $this->objFromFixture('SiteConfig', 'de_DE');
$pageEn = $this->objFromFixture('Page', 'root_en');
$pageDe = $pageEn->createTranslation('de_DE');
$translatorDe = $this->objFromFixture('Member', 'translator_de');
$translatorEn = $this->objFromFixture('Member', 'translator_en');
$this->assertFalse($pageEn->canEdit($translatorDe));
$this->assertTrue($pageEn->canEdit($translatorEn));
}
}
?>

View File

@ -0,0 +1,86 @@
Permission:
cmsmain1:
Code: CMS_ACCESS_CMSMain
cmsmain2:
Code: CMS_ACCESS_CMSMain
translate_all1:
Code: TRANSLATE_ALL
translate_all2:
Code: TRANSLATE_ALL
Group:
translators_de:
Code: translators_de
Permissions: =>Permission.cmsmain1,=>Permission.translate_all1
translators_en:
Code: translators_en
Permissions: =>Permission.cmsmain2,=>Permission.translate_all2
Member:
translator_de:
Email: translator_de@test.com
Password: test
Groups: =>Group.translators_de
translator_en:
Email: translator_en@test.com
Password: test
Groups: =>Group.translators_en
websiteuser:
Email: websiteuser@test.com
Password: test
Page:
root_en:
URLSegment: root-en
Locale: en_US
SiteConfig:
en_US:
Title: My test site
Locale: en_US
CanEditType: OnlyTheseUsers
EditorGroups: =>Group.translators_en
de_DE:
Title: Meine Test Seite
Locale: de_DE
CanEditType: OnlyTheseUsers
EditorGroups: =>Group.translators_de
Permission:
cmsmain1:
Code: CMS_ACCESS_CMSMain
cmsmain2:
Code: CMS_ACCESS_CMSMain
translate_all1:
Code: TRANSLATE_ALL
translate_all2:
Code: TRANSLATE_ALL
Group:
translators_de:
Code: translators_de
Permissions: =>Permission.cmsmain1,=>Permission.translate_all1
translators_en:
Code: translators_en
Permissions: =>Permission.cmsmain2,=>Permission.translate_all2
Member:
translator_de:
Email: translator_de@test.com
Password: test
Groups: =>Group.translators_de
translator_en:
Email: translator_en@test.com
Password: test
Groups: =>Group.translators_en
websiteuser:
Email: websiteuser@test.com
Password: test
Page:
root_en:
URLSegment: root-en
Locale: en_US
SiteConfig:
en_US:
Title: My test site
Locale: en_US
CanEditType: OnlyTheseUsers
EditorGroups: =>Group.translators_en
de_DE:
Title: Meine Test Seite
Locale: de_DE
CanEditType: OnlyTheseUsers
EditorGroups: =>Group.translators_de