Merge remote-tracking branch 'origin/0.3'

Conflicts:
	code/SubsiteAdmin.php
	code/extensions/LeftAndMainSubsites.php
	code/extensions/SiteTreeSubsites.php
	code/model/Subsite.php
	composer.json
	javascript/SubsitesTreeDropdownField.js
	lang/en_US.php
	tests/SubsiteAdminTest.php
	tests/SubsiteTest.php
	tests/SubsiteTest.yml
	tests/SubsitesVirtualPageTest.php
This commit is contained in:
Ingo Schommer 2013-01-03 17:38:51 +01:00
commit 82f1d980e8
21 changed files with 424 additions and 297 deletions

View File

@ -101,6 +101,27 @@ Not all themes might be suitable or adapted for all subsites. You can optionally
:::php
Subsite::set_allowed_themes(array('blackcandy','mytheme'));
### Public display of a subsite
By default, each subsite is available to the public (= not logged-in),
provided a correct host mapping is set up. A subsite can be marked as non-public
in its settings, in which case it only shows if a user with CMS permissions is logged in.
This is useful to create and check subsites on a live system before publishing them.
Please note that you need to filter for this manually in your own queries:
$publicSubsites = DataObject::get(
'Subsite',
Subsite::$check_is_public ? '"IsPublic"=1' : '';
);
To ensure the logged-in status of a member is carried across to subdomains,
you also need to configure PHP session cookies to be set
for all subdomains:
// Example matching subsite1.example.org and www.example.org
Session::set_cookie_domain('.example.org');
## Screenshots
![](docs/en/_images/subsites-module-adminscreenshot-new.png)

View File

@ -6,25 +6,22 @@
*/
class SubsiteAdmin extends ModelAdmin {
static $managed_models = array('Subsite', 'Subsite_Template');
static $managed_models = array('Subsite');
static $url_segment = 'subsites';
static $menu_title = "Subsites";
public $showImportForm=false;
public function getEditForm($id = null, $fields = null) {
$form = parent::getEditForm($id, $fields);
if($this->modelClass=='Subsite') {
$grid=$form->Fields()->dataFieldByName('Subsite');
if($grid) {
$grid->getConfig()->removeComponentsByType('GridFieldDetailForm');
$grid->getConfig()->addComponent(new GridFieldSubsiteDetailForm());
}
$grid=$form->Fields()->dataFieldByName('Subsite');
if($grid) {
$grid->getConfig()->removeComponentsByType('GridFieldDetailForm');
$grid->getConfig()->addComponent(new GridFieldSubsiteDetailForm());
}
return $form;
}
}

View File

@ -6,6 +6,8 @@
*/
class LeftAndMainSubsites extends Extension {
static $allowed_actions = array('CopyToSubsite');
function init() {
Requirements::css('subsites/css/LeftAndMain_Subsites.css');
Requirements::javascript('subsites/javascript/LeftAndMain_Subsites.js');
@ -21,10 +23,18 @@ class LeftAndMainSubsites extends Extension {
Subsite::changeSubsite($_GET['SubsiteID']);
//Redirect to clear the current page
$this->owner->redirect('admin/pages');
return $this->owner->redirect('admin/pages');
}
// Set subsite ID based on currently shown record
$req = $this->owner->getRequest();
$id = $req->param('ID');
if($id && is_numeric($id)) {
$record = DataObject::get_by_id($this->owner->stat('tree_class'), $id);
if($record) Session::set('SubsiteID', $record->SubsiteID);
}
}
/**
* Set the title of the CMS tree
*/
@ -53,7 +63,7 @@ class LeftAndMainSubsites extends Extension {
case "CMSMain":
// If there's a default site then main site has no meaning
$showMainSite = !DataObject::get_one('Subsite',"\"DefaultSite\"=1 AND \"IsPublic\"=1");
$showMainSite = !DataObject::get_one('Subsite',"\"DefaultSite\"=1");
$subsites = Subsite::accessible_sites($accessPerm, $showMainSite);
break;
@ -95,7 +105,7 @@ class LeftAndMainSubsites extends Extension {
$selected = $subsite->ID == $currentSubsiteID ? ' selected="selected"' : '';
$output .= "\n<option value=\"{$subsite->ID}\"$selected>". Convert::raw2xml($subsite->Title) . "</option>";
}
}
$output .= '</select>';
@ -103,7 +113,7 @@ class LeftAndMainSubsites extends Extension {
return $output;
}else {
return '<span>'.$list->First()->Title.'</span>';
}
}
}
}
@ -128,7 +138,7 @@ class LeftAndMainSubsites extends Extension {
// Switch to a subsite that this user can actually access.
$member = Member::currentUser();
if($member && Permission::checkMember($member, 'ADMIN')) return true; // admin can access all subsites
$sites = Subsite::accessible_sites("CMS_ACCESS_{$this->owner->class}", true)->map('ID', 'Title');
if(is_object($sites)) $sites = $sites->toArray();
@ -144,7 +154,7 @@ class LeftAndMainSubsites extends Extension {
if($candidate->controller != $this->owner->class) {
$sites = Subsite::accessible_sites("CMS_ACCESS_{$candidate->controller}", true)->map('ID', 'Title');
if(is_object($sites)) $sites = $sites->toArray();
if($sites && !isset($sites[Subsite::currentSubsiteID()])) {
$siteIDs = array_keys($sites);
Subsite::changeSubsite($siteIDs[0]);
@ -156,12 +166,12 @@ class LeftAndMainSubsites extends Extension {
}
}
// If all of those fail, you really don't have access to the CMS
// If all of those fail, you really don't have access to the CMS
return null;
}
function augmentNewSiteTreeItem(&$item) {
$item->SubsiteID = isset($_POST['SubsiteID']) ? $_POST['SubsiteID'] : Subsite::currentSubsiteID();
$item->SubsiteID = isset($_POST['SubsiteID']) ? $_POST['SubsiteID'] : Subsite::currentSubsiteID();
}
function onAfterSave($record) {
@ -170,5 +180,13 @@ class LeftAndMainSubsites extends Extension {
}
}
}
function copytosubsite($data, $form) {
$page = DataObject::get_by_id('SiteTree', $data['ID']);
$subsite = DataObject::get_by_id('Subsite', $data['CopyToSubsiteID']);
$newPage = $page->duplicateToSubsite($subsite->ID, true);
$response = $this->owner->getResponse();
$response->addHeader('X-Reload', true);
return $this->owner->redirect(Controller::join_links($this->owner->Link('show'), $newPage->ID));
}
}

View File

@ -4,45 +4,23 @@
* Extension for the SiteTree object to add subsites support
*/
class SiteTreeSubsites extends DataExtension {
static $template_variables = array(
'((Company Name))' => 'Title'
);
static $template_fields = array(
"URLSegment",
"Title",
"MenuTitle",
"Content",
"MetaTitle",
"MetaDescription",
"MetaKeywords",
);
/**
* Set the fields that will be copied from the template.
* Note that ParentID and Sort are implied.
*/
static function set_template_fields($fieldList) {
self::$template_fields = $fieldList;
}
public static $has_one=array(
'Subsite' => 'Subsite', // The subsite that this page belongs to
'MasterPage' => 'SiteTree',// Optional; the page that is the content master
'Subsite' => 'Subsite', // The subsite that this page belongs to
'MasterPage' => 'SiteTree',// Optional; the page that is the content master
);
public static $has_many=array(
'RelatedPages' => 'RelatedPageLink'
'RelatedPages' => 'RelatedPageLink'
);
public static $many_many=array(
'CrossSubsiteLinkTracking' => 'SiteTree' // Stored separately, as the logic for URL rewriting is different
'CrossSubsiteLinkTracking' => 'SiteTree' // Stored separately, as the logic for URL rewriting is different
);
public static $belongs_many_many=array(
'BackCrossSubsiteLinkTracking' => 'SiteTree'
);
'BackCrossSubsiteLinkTracking' => 'SiteTree'
);
public static $many_many_extraFields=array(
"CrossSubsiteLinkTracking" => array("FieldName" => "Varchar")
@ -90,7 +68,69 @@ class SiteTreeSubsites extends DataExtension {
}
function updateCMSFields(FieldList $fields) {
if($this->owner->MasterPageID) $fields->addFieldToTab('Root.Main', new HeaderField('This page\'s content is copied from a master page: ' . $this->owner->MasterPage()->Title, 2), 'Title');
$subsites = Subsite::accessible_sites("CMS_ACCESS_CMSMain");
$subsitesMap = array();
if($subsites && $subsites->Count()) {
$subsitesMap = $subsites->map('ID', 'Title');
unset($subsitesMap[$this->owner->SubsiteID]);
}
// Master page notice
if($this->owner->MasterPageID) {
$masterPage = $this->owner->MasterPage();
$masterNoteField = new LiteralField(
'MasterLink',
sprintf(
_t(
'SiteTreeSubsites.MasterLinkNote',
'<p>This page\'s content is copied from the <a href="%s" target="_blank">%s</a> master page (<a href="%s">edit</a>)</p>'
),
$masterPage->AbsoluteLink(),
$masterPage->Title,
Controller::join_links(
singleton('CMSMain')->Link('show'),
$masterPage->ID
)
)
);
$fields->addFieldToTab('Root.Main',$masterNoteField);
}
// Master page edit field (only allowed from default subsite to avoid inconsistent relationships)
$isDefaultSubsite = $this->owner->SubsiteID == 0 || $this->owner->Subsite()->DefaultSite;
if($isDefaultSubsite && $subsitesMap) {
$fields->addFieldToTab(
'Root.Main',
new DropdownField(
"CopyToSubsiteID",
_t('SiteTreeSubsites.CopyToSubsite', "Copy page to subsite"),
$subsitesMap,
''
)
);
$fields->addFieldToTab(
'Root.Main',
$copyAction = new InlineFormAction(
"copytosubsite",
_t('SiteTreeSubsites.CopyAction', "Copy")
)
);
$copyAction->includeDefaultJS(false);
} else {
$defaultSubsite = DataObject::get_one('Subsite', '"DefaultSite" = 1');
if($defaultSubsite) {
$fields->addFieldToTab('Root.Main',
$masterPageField = new SubsitesTreeDropdownField(
"MasterPageID",
_t('VirtualPage.MasterPage', "Master page"),
"SiteTree",
"ID",
"MenuTitle"
)
);
$masterPageField->setSubsiteID($defaultSubsite->ID);
}
}
// replace readonly link prefix
$subsite = $this->owner->Subsite();
@ -221,9 +261,8 @@ class SiteTreeSubsites extends DataExtension {
/**
* Create a duplicate of this page and save it to another subsite
* @param $subsiteID int|Subsite The Subsite to copy to, or its ID
* @param $isTemplate boolean If this is true, then the current page will be treated as the template, and MasterPageID will be set
*/
public function duplicateToSubsite($subsiteID = null, $isTemplate = true) {
public function duplicateToSubsite($subsiteID = null) {
if(is_object($subsiteID)) {
$subsite = $subsiteID;
$subsiteID = $subsite->ID;
@ -241,9 +280,7 @@ class SiteTreeSubsites extends DataExtension {
$page->CheckedPublicationDifferences = $page->AddedToStage = true;
$subsiteID = ($subsiteID ? $subsiteID : $oldSubsite);
$page->SubsiteID = $subsiteID;
if($isTemplate) $page->MasterPageID = $this->owner->ID;
$page->MasterPageID = $this->owner->ID;
$page->write();
Subsite::changeSubsite($oldSubsite);
@ -331,4 +368,4 @@ class SiteTreeSubsites extends DataExtension {
if(in_array($this->owner->class, $blacklisted)) return false;
}
}
}
}

View File

@ -19,7 +19,7 @@ class GridFieldSubsiteDetailForm_ItemRequest extends GridFieldDetailForm_ItemReq
$form=parent::ItemEditForm();
if($this->record->ID == 0) {
$templates = Subsite_Template::get()->sort('Title');
$templates = Subsite::get()->sort('Title');
$templateArray = array();
if($templates) {
$templateArray = $templates->map('ID', 'Title');
@ -35,9 +35,9 @@ class GridFieldSubsiteDetailForm_ItemRequest extends GridFieldDetailForm_ItemReq
$new_record = $this->record->ID == 0;
if($new_record && isset($data['TemplateID']) && !empty($data['TemplateID'])) {
$template = Subsite_Template::get()->byID(intval($data['TemplateID']));
$template = Subsite::get()->byID(intval($data['TemplateID']));
if($template) {
$this->record=$template->createInstance($data['Title']);
$this->record = $template->duplicate();
}
}

View File

@ -76,6 +76,8 @@ class Subsite extends DataObject implements PermissionProvider {
*/
private static $_cache_accessible_sites = array();
private static $_cache_subsite_for_domain = array();
/**
* @var array $allowed_themes Numeric array of all themes which are allowed to be selected for all subsites.
* Corresponds to subfolder names within the /themes folder. By default, all themes contained in this folder
@ -90,6 +92,11 @@ class Subsite extends DataObject implements PermissionProvider {
*/
static $strict_subdomain_matching = false;
/**
* @var boolean Respects the IsPublic flag when retrieving subsites
*/
static $check_is_public = true;
static function set_allowed_domains($domain){
user_error('Subsite::set_allowed_domains() is deprecated; it is no longer necessary '
. 'because users can now enter any domain name', E_USER_NOTICE);
@ -240,7 +247,7 @@ class Subsite extends DataObject implements PermissionProvider {
function getCMSActions() {
return new FieldList(
new FormAction('callPageMethod', "Create copy", null, 'adminDuplicate')
new FormAction('callPageMethod', "Create copy", null, 'adminDuplicate')
);
}
@ -286,7 +293,7 @@ JS;
$id = self::getSubsiteIDForDomain();
Session::set('SubsiteID', $id);
}
return (int)$id;
}
@ -334,19 +341,25 @@ JS;
* @param $host The host to find the subsite for. If not specified, $_SERVER['HTTP_HOST'] is used.
* @return int Subsite ID
*/
static function getSubsiteIDForDomain($host = null, $returnMainIfNotFound = true) {
static function getSubsiteIDForDomain($host = null, $checkPermissions = true) {
if($host == null) $host = $_SERVER['HTTP_HOST'];
if(!Subsite::$strict_subdomain_matching) $host = preg_replace('/^www\./', '', $host);
$SQL_host = Convert::raw2sql($host);
$matchingDomains = DataObject::get("SubsiteDomain", "'$SQL_host' LIKE replace(\"SubsiteDomain\".\"Domain\",'*','%')",
"\"IsPrimary\" DESC")->innerJoin('Subsite', "\"Subsite\".\"ID\" = \"SubsiteDomain\".\"SubsiteID\" AND
\"Subsite\".\"IsPublic\"=1");
if(!Subsite::$strict_subdomain_matching) $host = preg_replace('/^www\./', '', $host);
$cacheKey = implode('_', array($host, Member::currentUserID(), Subsite::$check_is_public));
if(isset(self::$_cache_subsite_for_domain[$cacheKey])) return self::$_cache_subsite_for_domain[$cacheKey];
$SQL_host = Convert::raw2sql($host);
$joinFilter = self::$check_is_public ? "AND \"Subsite\".\"IsPublic\"=1" : '';
$matchingDomains = DataObject::get(
"SubsiteDomain",
"'$SQL_host' LIKE replace(\"SubsiteDomain\".\"Domain\",'*','%')",
"\"IsPrimary\" DESC"
)->innerJoin('Subsite', "\"Subsite\".\"ID\" = \"SubsiteDomain\".\"SubsiteID\" AND \"Subsite\".\"IsPublic\"=1");;
if($matchingDomains && $matchingDomains->Count()>0) {
$subsiteIDs = array_unique($matchingDomains->map('SubsiteID')->keys());
$subsiteDomains = array_unique($matchingDomains->map('Domain')->keys());
if($matchingDomains && $matchingDomains->Count()) {
$subsiteIDs = array_unique($matchingDomains->column('SubsiteID'));
$subsiteDomains = array_unique($matchingDomains->column('Domain'));
if(sizeof($subsiteIDs) > 1) {
throw new UnexpectedValueException(sprintf(
"Multiple subsites match on '%s': %s",
@ -355,16 +368,18 @@ JS;
));
}
return $subsiteIDs[0];
$subsiteID = $subsiteIDs[0];
} else if($default = DataObject::get_one('Subsite', "\"DefaultSite\" = 1")) {
// Check for a 'default' subsite
$subsiteID = $default->ID;
} else {
// Default subsite id = 0, the main site
$subsiteID = 0;
}
// Check for a 'default' subsite
if ($default = DataObject::get_one('Subsite', "\"DefaultSite\" = 1")) {
return $default->ID;
}
self::$_cache_subsite_for_domain[$cacheKey] = $subsiteID;
// Default subsite id = 0, the main site
return 0;
return $subsiteID;
}
function getMembersByPermission($permissionCodes = array('ADMIN')){
@ -434,7 +449,7 @@ JS;
AND \"Group\".\"AccessAllSubsites\" = 1
AND \"MemberID\" = {$memberID}
")->value();
// There has to be at least one that allows access.
return ($groupCount + $roleCount > 0);
}
@ -443,13 +458,13 @@ JS;
* Duplicate this subsite
*/
function duplicate($doWrite = true) {
$newTemplate = parent::duplicate($doWrite);
$duplicate = parent::duplicate($doWrite);
$oldSubsiteID = Session::get('SubsiteID');
self::changeSubsite($this->ID);
/*
* Copy data from this template to the given subsite. Does this using an iterative depth-first search.
* Copy data from this object to the given subsite. Does this using an iterative depth-first search.
* This will make sure that the new parents on the new subsite are correct, and there are no funny
* issues with having to check whether or not the new parents have been added to the site tree
* when a page, etc, is duplicated
@ -457,15 +472,19 @@ JS;
$stack = array(array(0,0));
while(count($stack) > 0) {
list($sourceParentID, $destParentID) = array_pop($stack);
$children = Versioned::get_by_stage('Page', 'Live', "\"ParentID\" = $sourceParentID", '');
if($children) {
foreach($children as $child) {
$childClone = $child->duplicateToSubsite($newTemplate, false);
self::changeSubsite($duplicate->ID); //Change to destination subsite
$childClone = $child->duplicateToSubsite($duplicate, false);
$childClone->ParentID = $destParentID;
$childClone->writeToStage('Stage');
$childClone->publish('Stage', 'Live');
self::changeSubsite($this->ID); //Change Back to this subsite
array_push($stack, array($child->ID, $childClone->ID));
}
}
@ -473,7 +492,7 @@ JS;
self::changeSubsite($oldSubsiteID);
return $newTemplate;
return $duplicate;
}
@ -481,7 +500,7 @@ JS;
* Return the subsites that the current user can access.
* Look for one of the given permission codes on the site.
*
* Sites and Templates will only be included if they have a Title
* Sites will only be included if they have a Title
*
* @param $permCode array|string Either a single permission code or an array of permission codes.
* @param $includeMainSite If true, the main site will be included if appropriate.
@ -505,15 +524,13 @@ JS;
return self::$_cache_accessible_sites[$cacheKey];
}
$templateClassList = "'" . implode("', '", ClassInfo::subclassesFor("Subsite_Template")) . "'";
$subsites = DataList::create('Subsite')
->where("\"Subsite\".\"Title\" != ''")
->leftJoin('Group_Subsites', "\"Group_Subsites\".\"SubsiteID\" = \"Subsite\".\"ID\"")
->innerJoin('Group', "\"Group\".\"ID\" = \"Group_Subsites\".\"GroupID\" OR \"Group\".\"AccessAllSubsites\" = 1")
->innerJoin('Group_Members', "\"Group_Members\".\"GroupID\"=\"Group\".\"ID\" AND \"Group_Members\".\"MemberID\" = $member->ID")
->innerJoin('Permission', "\"Group\".\"ID\"=\"Permission\".\"GroupID\" AND \"Permission\".\"Code\" IN ($SQL_codes, 'ADMIN')");
if(!$subsites) $subsites = new ArrayList();
$rolesSubsites = DataList::create('Subsite')
@ -548,7 +565,7 @@ JS;
}
self::$_cache_accessible_sites[$cacheKey] = $subsites;
return $subsites;
}
@ -621,65 +638,6 @@ JS;
*/
static function on_db_reset() {
self::$_cache_accessible_sites = array();
}
}
/**
* An instance of subsite that can be duplicated to provide a quick way to create new subsites.
*
* @package subsites
*/
class Subsite_Template extends Subsite {
/**
* Create an instance of this template, with the given title & domain
*/
function createInstance($title, $domain = null) {
$intranet = Object::create('Subsite');
$intranet->Title = $title;
$intranet->TemplateID = $this->ID;
$intranet->write();
if($domain) {
$intranetDomain = Object::create('SubsiteDomain');
$intranetDomain->SubsiteID = $intranet->ID;
$intranetDomain->Domain = $domain;
$intranetDomain->write();
}
$oldSubsiteID = Session::get('SubsiteID');
self::changeSubsite($this->ID);
/*
* Copy site content from this template to the given subsite. Does this using an iterative depth-first search.
* This will make sure that the new parents on the new subsite are correct, and there are no funny
* issues with having to check whether or not the new parents have been added to the site tree
* when a page, etc, is duplicated
*/
$stack = array(array(0,0));
while(count($stack) > 0) {
list($sourceParentID, $destParentID) = array_pop($stack);
$children = Versioned::get_by_stage('SiteTree', 'Live', "\"ParentID\" = $sourceParentID", '');
if($children) {
foreach($children as $child) {
//Change to destination subsite
self::changeSubsite($intranet->ID);
$childClone = $child->duplicateToSubsite($intranet);
$childClone->ParentID = $destParentID;
$childClone->writeToStage('Stage');
$childClone->publish('Stage', 'Live');
//Change Back to this subsite
self::changeSubsite($this->ID);
array_push($stack, array($child->ID, $childClone->ID));
}
}
}
self::changeSubsite($oldSubsiteID);
return $intranet;
self::$_cache_subsite_for_domain = array();
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* Handy alternative to copying pages when creating a subsite through the UI.
* Can be used to batch-add new pages after subsite creation,
* or simply to process a large site outside of the UI.
*
* Example: sake dev/tasks/SubsiteCopyPagesTask from=<subsite-source> to=<subsite-target>
*/
class SubsiteCopyPagesTask extends BuildTask {
protected $title = 'Copy pages to different subsite';
protected $description = '';
function run($request) {
$subsiteFromId = $request->getVar('from');
if(!is_numeric($subsiteFromId)) throw new InvalidArgumentException('Missing "from" parameter');
$subsiteFrom = DataObject::get_by_id('Subsite', $subsiteFromId);
if(!$subsiteFrom) throw new InvalidArgumentException('Subsite not found');
$subsiteToId = $request->getVar('to');
if(!is_numeric($subsiteToId)) throw new InvalidArgumentException('Missing "to" parameter');
$subsiteTo = DataObject::get_by_id('Subsite', $subsiteToId);
if(!$subsiteTo) throw new InvalidArgumentException('Subsite not found');
$useVirtualPages = (bool)$request->getVar('virtual');
Subsite::changeSubsite($subsiteFrom);
// Copy data from this template to the given subsite. Does this using an iterative depth-first search.
// This will make sure that the new parents on the new subsite are correct, and there are no funny
// issues with having to check whether or not the new parents have been added to the site tree
// when a page, etc, is duplicated
$stack = array(array(0,0));
while(count($stack) > 0) {
list($sourceParentID, $destParentID) = array_pop($stack);
$children = Versioned::get_by_stage('SiteTree', 'Live', "\"ParentID\" = $sourceParentID", '');
if($children) {
foreach($children as $child) {
if($useVirtualPages) {
$childClone = new SubsitesVirtualPage();
$childClone->writeToStage('Stage');
$childClone->CopyContentFromID = $child->ID;
$childClone->SubsiteID = $subsiteTo->ID;
} else {
$childClone = $child->duplicateToSubsite($subsiteTo->ID, true);
}
$childClone->ParentID = $destParentID;
$childClone->writeToStage('Stage');
$childClone->publish('Stage', 'Live');
array_push($stack, array($child->ID, $childClone->ID));
$this->log(sprintf('Copied "%s" (#%d, %s)', $child->Title, $child->ID, $child->Link()));
}
}
unset($children);
}
}
function log($msg) {
echo $msg . "\n";
}
}

View File

@ -48,5 +48,13 @@
});
}
});
$('.cms-edit-form input[name=action_copytosubsite]').entwine({
onclick: function(e) {
var form = this.closest('form');
form.trigger('submit', [this]);
}
});
});
})(jQuery);

View File

@ -1,26 +1,28 @@
(function($) {
$.entwine('ss', function($) {
$('.TreeDropdownField').entwine({
subsiteID: function() {
var subsiteSel = $$('#CopyContentFromID_SubsiteID select')[0];
subsiteSel.onchange = (function() {
this.createTreeNode(true);
this.ajaxGetTree((function(response) {
this.newTreeReady(response, true);
this.updateTreeLabel();
}).bind(this));
}).bind(this);
return subsiteSel.options[subsiteSel.selectedIndex].value;
},
subsiteID: function() {
var subsiteSel = $$('#CopyContentFromID_SubsiteID select')[0];
if(!subsiteSel) return;
subsiteSel.onchange = (function() {
this.createTreeNode(true);
this.ajaxGetTree((function(response) {
this.newTreeReady(response, true);
this.updateTreeLabel();
}).bind(this));
}).bind(this);
return subsiteSel.options[subsiteSel.selectedIndex].value;
},
getRequestParams: function() {
var name=this.find(':input:hidden').attr('name');
var obj={};
obj[name+'_SubsiteID']=parseInt(this.subsiteID());
return obj;
}
}
});
});
})(jQuery);

13
tests/BaseSubsiteTest.php Normal file
View File

@ -0,0 +1,13 @@
<?php
class BaseSubsiteTest extends SapphireTest {
/**
* Avoid subsites filtering on fixture fetching.
*/
function objFromFixture($class, $id) {
Subsite::disable_subsite_filter(true);
$obj = parent::objFromFixture($class, $id);
Subsite::disable_subsite_filter(false);
return $obj;
}
}

View File

@ -1,6 +1,6 @@
<?php
class FileSubsitesTest extends SapphireTest {
class FileSubsitesTest extends BaseSubsiteTest {
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
function testTrivialFeatures() {
@ -55,4 +55,4 @@ class FileSubsitesTest extends SapphireTest {
}
}
}

View File

@ -1,6 +1,6 @@
<?php
class GroupSubsitesTest extends SapphireTest {
class GroupSubsitesTest extends BaseSubsiteTest {
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
protected $requireDefaultRecordsFrom = array('GroupSubsites');

View File

@ -2,6 +2,17 @@
class LeftAndMainSubsitesTest extends FunctionalTest {
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
/**
* Avoid subsites filtering on fixture fetching.
*/
function objFromFixture($class, $id) {
Subsite::disable_subsite_filter(true);
$obj = parent::objFromFixture($class, $id);
Subsite::disable_subsite_filter(false);
return $obj;
}
function testAlternateAccessCheck() {
$admin = $this->objFromFixture("Member","admin");

View File

@ -1,6 +1,6 @@
<?php
class SiteConfigSubsitesTest extends SapphireTest {
class SiteConfigSubsitesTest extends BaseSubsiteTest {
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
function testEachSubsiteHasAUniqueSiteConfig() {

View File

@ -1,6 +1,6 @@
<?php
class SiteTreeSubsitesTest extends SapphireTest {
class SiteTreeSubsitesTest extends BaseSubsiteTest {
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
@ -10,8 +10,8 @@ class SiteTreeSubsitesTest extends SapphireTest {
);
function testPagesInDifferentSubsitesCanShareURLSegment() {
$subsiteMain = $this->objFromFixture('Subsite_Template', 'main');
$subsite1 = $this->objFromFixture('Subsite_Template', 'subsite1');
$subsiteMain = $this->objFromFixture('Subsite', 'main');
$subsite1 = $this->objFromFixture('Subsite', 'subsite1');
$pageMain = new SiteTree();
$pageMain->URLSegment = 'testpage';
@ -60,8 +60,8 @@ class SiteTreeSubsitesTest extends SapphireTest {
function testRelatedPages() {
$this->assertTrue(singleton('RelatedPageLink')->getCMSFields() instanceof FieldList);
$importantpage = $this->objFromFixture('SiteTree', 'importantpage');
$contact = $this->objFromFixture('SiteTree', 'contact');
$importantpage = $this->objFromFixture('Page', 'importantpage');
$contact = $this->objFromFixture('Page', 'contact');
$link = new RelatedPageLink();
$link->MasterPageID = $importantpage->ID;
@ -87,11 +87,11 @@ class SiteTreeSubsitesTest extends SapphireTest {
$admin = $this->objFromFixture('Member', 'admin');
$subsite1member = $this->objFromFixture('Member', 'subsite1member');
$subsite2member = $this->objFromFixture('Member', 'subsite2member');
$mainpage = $this->objFromFixture('SiteTree', 'home');
$subsite1page = $this->objFromFixture('SiteTree', 'subsite1_home');
$subsite2page = $this->objFromFixture('SiteTree', 'subsite2_home');
$subsite1 = $this->objFromFixture('Subsite_Template', 'subsite1');
$subsite2 = $this->objFromFixture('Subsite_Template', 'subsite2');
$mainpage = $this->objFromFixture('Page', 'home');
$subsite1page = $this->objFromFixture('Page', 'subsite1_home');
$subsite2page = $this->objFromFixture('Page', 'subsite2_home');
$subsite1 = $this->objFromFixture('Subsite', 'subsite1');
$subsite2 = $this->objFromFixture('Subsite', 'subsite2');
// Cant pass member as arguments to canEdit() because of GroupSubsites
Session::set("loggedInAs", $admin->ID);

View File

@ -17,7 +17,7 @@ class SubsiteAdminFunctionalTest extends FunctionalTest {
$this->get('admin');
$this->assertEquals(Subsite::currentSubsiteID(), '0', 'Can access main site');
$mainSubsite = $this->objFromFixture('Subsite_Template', 'main');
$mainSubsite = $this->objFromFixture('Subsite', 'main');
$this->get("admin/pages?SubsiteID={$mainSubsite->ID}&ajax=1");
$this->get('admin');
$this->assertEquals(Subsite::currentSubsiteID(), $mainSubsite->ID, 'Can access the subsite');
@ -35,7 +35,7 @@ class SubsiteAdminFunctionalTest extends FunctionalTest {
$this->get('admin');
$this->assertEquals(Subsite::currentSubsiteID(), '0', 'Can access main site');
$mainSubsite = $this->objFromFixture('Subsite_Template', 'main');
$mainSubsite = $this->objFromFixture('Subsite', 'main');
$this->get("admin/pages?SubsiteID={$mainSubsite->ID}&ajax=1");
$this->get('admin');
$this->assertEquals(Subsite::currentSubsiteID(), $mainSubsite->ID, 'Can access the subsite');

View File

@ -1,29 +1,29 @@
<?php
class SubsiteAdminTest extends SapphireTest {
class SubsiteAdminTest extends BaseSubsiteTest {
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
function adminLoggedInSession() {
return new Session(array(
'loggedInAs' => $this->idFromFixture('Member', 'admin')
));
}
function adminLoggedInSession() {
return new Session(array(
'loggedInAs' => $this->idFromFixture('Member', 'admin')
));
}
/**
* Test generation of the view
*/
function testBasicView() {
/**
* Test generation of the view
*/
function testBasicView() {
Subsite::$write_hostmap = false;
$subsite1ID = $this->objFromFixture('Subsite','domaintest1')->ID;
// Open the admin area logged in as admin
$response1 = Director::test('admin/subsites/', null, $this->adminLoggedInSession());
// Confirm that this URL gets you the entire page, with the edit form loaded
// Open the admin area logged in as admin
$response1 = Director::test('admin/subsites/', null, $this->adminLoggedInSession());
// Confirm that this URL gets you the entire page, with the edit form loaded
$response2 = Director::test("admin/subsites/Subsite/EditForm/field/Subsite/item/$subsite1ID/edit", null, $this->adminLoggedInSession());
$this->assertTrue(strpos($response2->getBody(), 'id="Form_ItemEditForm_ID"') !== false, "Testing Form_ItemEditForm_ID exists");
$this->assertTrue(strpos($response2->getBody(), '<head') !== false, "Testing <head> exists");
}
$this->assertTrue(strpos($response2->getBody(), '<head') !== false, "Testing <head> exists");
}
/**
* Test searching for an intranet
@ -31,7 +31,7 @@ class SubsiteAdminTest extends SapphireTest {
function XXtestIntranetSearch() {
$cont = new SubsiteAdmin();
$cont->pushCurrent();
$cont->setSession($this->adminLoggedInSession());
$cont->setSession($this->adminLoggedInSession());
// Check that the logged-in member has the correct permissions
$this->assertTrue(Permission::check('ADMIN') ? true : false);
@ -44,49 +44,49 @@ class SubsiteAdminTest extends SapphireTest {
foreach($searches as $search) {
$response = $form->testAjaxSubmission('getResults', $search);
$links = $response->getLinks();
foreach($links as $link) {
$this->assertTrue(preg_match('/^admin\/subsites\/show\/[0-9]+$/', $link['href']) == 1, "Search result links bad.");
}
$links = $response->getLinks();
foreach($links as $link) {
$this->assertTrue(preg_match('/^admin\/subsites\/show\/[0-9]+$/', $link['href']) == 1, "Search result links bad.");
}
}
$cont->popCurrent();
}
/**
* Test the intranet creation form.
*/
function XXtestIntranetCreation() {
$cont = new SubsiteAdmin();
$cont->pushCurrent();
$cont->setSession($this->adminLoggedInSession());
$form = $cont->AddSubsiteForm();
$source = $form->dataFieldByName('TemplateID')->getSource();
$templateIDs = $this->allFixtureIDs('Subsite');
foreach($templateIDs as $templateID) {
$this->assertArrayHasKey($templateID, $source);
}
$templateObj = $this->objFromFixture('Subsite','main');
$this->assertEquals($templateObj->Title, $source[$templateObj->ID], "Template dropdown isn't listing Title values");
/**
* Test the intranet creation form.
*/
function XXtestIntranetCreation() {
$cont = new SubsiteAdmin();
$cont->pushCurrent();
$cont->setSession($this->adminLoggedInSession());
$response = $form->testSubmission('addintranet', array(
'Name' => 'Test Intranet',
'Domain' => 'test.example.com',
'TemplateID' => 1,
'AdminEmail' => '',
'AdminName' => '',
));
$form = $cont->AddSubsiteForm();
$source = $form->dataFieldByName('TemplateID')->getSource();
$templateIDs = $this->allFixtureIDs('Subsite_Template');
foreach($templateIDs as $templateID) {
$this->assertArrayHasKey($templateID, $source);
}
$templateObj = $this->objFromFixture('Subsite_Template','main');
$this->assertEquals($templateObj->Title, $source[$templateObj->ID], "Template dropdown isn't listing Title values");
$response = $form->testSubmission('addintranet', array(
'Name' => 'Test Intranet',
'Domain' => 'test.example.com',
'TemplateID' => 1,
'AdminEmail' => '',
'AdminName' => '',
));
$this->assertTrue(true == preg_match('/admin\/subsites\/show\/([0-9]+)/i', $response->getHeader('Location'), $matches), "Intranet creation dowsn't redirect to new view");
$newIntranet = DataObject::get_by_id("Subsite", $matches[1]);
$this->assertEquals('Test Intranet', $newIntranet->Title, "New intranet not created properly.");
$cont->popCurrent();
}
$this->assertTrue(true == preg_match('/admin\/subsites\/show\/([0-9]+)/i', $response->getHeader('Location'), $matches), "Intranet creation dowsn't redirect to new view");
$newIntranet = DataObject::get_by_id("Subsite", $matches[1]);
$this->assertEquals('Test Intranet', $newIntranet->Title, "New intranet not created properly.");
$cont->popCurrent();
}
/**
@ -100,12 +100,12 @@ class SubsiteAdminTest extends SapphireTest {
$cmsMain = new CMSMain();
foreach($cmsMain->Subsites() as $subsite) {
$ids[$subsite->ID] = true;
}
}
$this->assertArrayHasKey(0, $ids, "Main site accessible");
$this->assertArrayHasKey($this->idFromFixture('Subsite_Template','main'), $ids, "Site with no groups inaccesible");
$this->assertArrayHasKey($this->idFromFixture('Subsite_Template','subsite1'), $ids, "Subsite1 Template inaccessible");
$this->assertArrayHasKey($this->idFromFixture('Subsite_Template','subsite2'), $ids, "Subsite2 Template inaccessible");
$this->assertArrayHasKey($this->idFromFixture('Subsite','main'), $ids, "Site with no groups inaccesible");
$this->assertArrayHasKey($this->idFromFixture('Subsite','subsite1'), $ids, "Subsite1 Template inaccessible");
$this->assertArrayHasKey($this->idFromFixture('Subsite','subsite2'), $ids, "Subsite2 Template inaccessible");
}

View File

@ -1,6 +1,6 @@
<?php
class SubsiteTest extends SapphireTest {
class SubsiteTest extends BaseSubsiteTest {
static $fixture_file = 'subsites/tests/SubsiteTest.yml';
@ -24,12 +24,12 @@ class SubsiteTest extends SapphireTest {
Subsite::$write_hostmap = false;
// Create the instance
$template = $this->objFromFixture('Subsite_Template', 'main');
$template = $this->objFromFixture('Subsite', 'main');
// Test that changeSubsite is working
Subsite::changeSubsite($template->ID);
$tmplHome = DataObject::get_one('SiteTree', "\"URLSegment\" = 'home'");
$tmplStaff = $this->objFromFixture('Page','staff');
$tmplHome = DataObject::get_one('Page', "\"URLSegment\" = 'home'");
// Publish all the pages in the template, testing that DataObject::get only returns pages from the chosen subsite
$pages = DataObject::get("SiteTree");
@ -38,20 +38,17 @@ class SubsiteTest extends SapphireTest {
$this->assertEquals($template->ID, $page->SubsiteID);
$page->publish('Stage', 'Live');
}
// Create a new site
$subsite = $template->createInstance('My Site', 'something.test.com');
$subsite = $template->duplicate();
// Check title
$this->assertEquals($subsite->Title, 'My Site');
$this->assertEquals($subsite->Title, $template->Title);
// Check that domain generation is working
$this->assertEquals('something.test.com', $subsite->domain());
// Another test that changeSubsite is working
$subsite->activate();
$siteHome = DataObject::get_one('SiteTree', "\"URLSegment\" = 'home'");
$siteHome = DataObject::get_one('Page', "\"URLSegment\" = 'home'");
$this->assertNotEquals($siteHome, false, 'Home Page for subsite not found');
$this->assertEquals($subsite->ID, $siteHome->SubsiteID,
'createInstance() copies existing pages retaining the same URLSegment'
@ -59,8 +56,7 @@ class SubsiteTest extends SapphireTest {
$this->assertEquals($siteHome->MasterPageID, $tmplHome->ID, 'Check master page value');
// Check linking of child pages
$tmplStaff = $this->objFromFixture('SiteTree','staff');
$siteStaff = DataObject::get_one('SiteTree', "\"URLSegment\" = '" . Convert::raw2sql($tmplStaff->URLSegment) . "'");
$siteStaff = DataObject::get_one('Page', "\"URLSegment\" = '" . Convert::raw2sql($tmplStaff->URLSegment) . "'");
$this->assertEquals($siteStaff->MasterPageID, $tmplStaff->ID);
Subsite::changeSubsite(0);
@ -282,7 +278,7 @@ class SubsiteTest extends SapphireTest {
sort($member2SiteTitles);
$this->assertEquals('Subsite1 Template', $member2SiteTitles[0], 'Member can get to subsite via a group role');
}
function testhasMainSitePermission() {
$admin = $this->objFromFixture('Member', 'admin');
$subsite1member = $this->objFromFixture('Member', 'subsite1member');
@ -348,4 +344,4 @@ class SubsiteTest extends SapphireTest {
$subsite2->activate();
$this->assertEquals('MyNewAwesomePage', DataObject::get_by_id('Page', $page2->ID)->Title);
}
}
}

View File

@ -1,11 +1,10 @@
Subsite_Template:
Subsite:
main:
Title: Template
subsite1:
Title: Subsite1 Template
subsite2:
Title: Subsite2 Template
Subsite:
domaintest1:
Title: Test 1
domaintest2:
@ -14,10 +13,10 @@ Subsite:
Title: Test 3
SubsiteDomain:
subsite1:
SubsiteID: =>Subsite_Template.subsite1
SubsiteID: =>Subsite.subsite1
Domain: subsite1.*
subsite2:
SubsiteID: =>Subsite_Template.subsite2
SubsiteID: =>Subsite.subsite2
Domain: subsite2.*
dt1a:
SubsiteID: =>Subsite.domaintest1
@ -37,46 +36,45 @@ SubsiteDomain:
SubsiteID: =>Subsite.domaintest3
Domain: three.*
IsPrimary: 1
SiteTree:
Page:
mainSubsitePage:
Title: MainSubsitePage
SubsiteID: 0
home:
Title: Home
SubsiteID: =>Subsite_Template.main
SubsiteID: =>Subsite.main
about:
Title: About
SubsiteID: =>Subsite_Template.main
SubsiteID: =>Subsite.main
linky:
Title: Linky
MetaTitle: Linky
SubsiteID: =>Subsite_Template.main
SubsiteID: =>Subsite.main
staff:
Title: Staff
ParentID: =>SiteTree.about
SubsiteID: =>Subsite_Template.main
ParentID: =>Page.about
SubsiteID: =>Subsite.main
contact:
Title: Contact Us
SubsiteID: =>Subsite_Template.main
SubsiteID: =>Subsite.main
importantpage:
Title: Important Page
SubsiteID: =>Subsite_Template.main
SubsiteID: =>Subsite.main
subsite1_home:
Title: Home
SubsiteID: =>Subsite_Template.subsite1
Title: Home (Subsite 1)
SubsiteID: =>Subsite.subsite1
subsite1_contactus:
Title: Contact Us
SubsiteID: =>Subsite_Template.subsite1
Title: Contact Us (Subsite 1)
SubsiteID: =>Subsite.subsite1
subsite1_staff:
Title: Staff
SubsiteID: =>Subsite_Template.subsite1
SubsiteID: =>Subsite.subsite1
subsite2_home:
Title: Home
SubsiteID: =>Subsite_Template.subsite2
Title: Home (Subsite 2)
SubsiteID: =>Subsite.subsite2
subsite2_contactus:
Title: Contact Us
SubsiteID: =>Subsite_Template.subsite2
Title: Contact Us (Subsite 2)
SubsiteID: =>Subsite.subsite2
PermissionRoleCode:
roleCode1:
@ -98,17 +96,17 @@ Group:
Title: subsite1_group
Code: subsite1_group
AccessAllSubsites: 0
Subsites: =>Subsite_Template.subsite1
Subsites: =>Subsite.subsite1
subsite2_group:
Title: subsite2_group
Code: subsite2_group
AccessAllSubsites: 0
Subsites: =>Subsite_Template.subsite2
Subsites: =>Subsite.subsite2
subsite1admins:
Title: subsite1admins
Code: subsite1admins
AccessAllSubsites: 0
Subsites: =>Subsite_Template.subsite1
Subsites: =>Subsite.subsite1
allsubsitesauthors:
Title: allsubsitesauthors
Code: allsubsitesauthors

View File

@ -1,6 +1,6 @@
<?php
class SubsitesVirtualPageTest extends SapphireTest {
class SubsitesVirtualPageTest extends BaseSubsiteTest {
static $fixture_file = array(
'subsites/tests/SubsiteTest.yml',
'subsites/tests/SubsitesVirtualPageTest.yml',
@ -14,6 +14,7 @@ class SubsitesVirtualPageTest extends SapphireTest {
fwrite($fh, str_repeat('x',1000000));
fclose($fh);
}
function tearDown() {
parent::tearDown();
$testFiles = array(
@ -30,12 +31,12 @@ class SubsitesVirtualPageTest extends SapphireTest {
function testVirtualPageFromAnotherSubsite() {
Subsite::$write_hostmap = false;
$subsite = $this->objFromFixture('Subsite_Template', 'subsite2');
$subsite = $this->objFromFixture('Subsite', 'subsite2');
Subsite::changeSubsite($subsite->ID);
Subsite::$disable_subsite_filter = false;
$linky = $this->objFromFixture('SiteTree', 'linky');
$linky = $this->objFromFixture('Page', 'linky');
$svp = new SubsitesVirtualPage();
$svp->CopyContentFromID = $linky->ID;
@ -55,11 +56,11 @@ class SubsitesVirtualPageTest extends SapphireTest {
function testCustomMetadata() {
Subsite::$write_hostmap = false;
$subsite = $this->objFromFixture('Subsite_Template', 'main');
$subsite = $this->objFromFixture('Subsite', 'main');
Subsite::changeSubsite($subsite->ID);
$orig = $this->objFromFixture('SiteTree', 'linky');
$orig = $this->objFromFixture('Page', 'linky');
$svp = new SubsitesVirtualPage();
$svp->CopyContentFromID = $orig->ID;
@ -86,7 +87,7 @@ class SubsitesVirtualPageTest extends SapphireTest {
touch(Director::baseFolder() . '/assets/testscript-test-file.pdf');
// Publish the source page
$page = $this->objFromFixture('Page', 'page1');
$page = $this->objFromFixture('SiteTree', 'page1');
$this->assertTrue($page->doPublish());
// Create a virtual page from it, and publish that
@ -172,19 +173,19 @@ class SubsitesVirtualPageTest extends SapphireTest {
StaticPublisher::$disable_realtime = true;
// Go to main site, get parent page
$subsite = $this->objFromFixture('Subsite_Template', 'main');
$subsite = $this->objFromFixture('Subsite', 'main');
Subsite::changeSubsite($subsite->ID);
$page = $this->objFromFixture('SiteTree', 'importantpage');
$page = $this->objFromFixture('Page', 'importantpage');
// Create two SVPs on other subsites
$subsite = $this->objFromFixture('Subsite_Template', 'subsite1');
$subsite = $this->objFromFixture('Subsite', 'subsite1');
Subsite::changeSubsite($subsite->ID);
$vp1 = new SubsitesVirtualPage();
$vp1->CopyContentFromID = $page->ID;
$vp1->write();
$vp1->doPublish();
$subsite = $this->objFromFixture('Subsite_Template', 'subsite2');
$subsite = $this->objFromFixture('Subsite', 'subsite2');
Subsite::changeSubsite($subsite->ID);
$vp2 = new SubsitesVirtualPage();
$vp2->CopyContentFromID = $page->ID;
@ -192,16 +193,16 @@ class SubsitesVirtualPageTest extends SapphireTest {
$vp2->doPublish();
// Switch back to main site, unpublish source
$subsite = $this->objFromFixture('Subsite_Template', 'main');
$subsite = $this->objFromFixture('Subsite', 'main');
Subsite::changeSubsite($subsite->ID);
$page = $this->objFromFixture('SiteTree', 'importantpage');
$page = $this->objFromFixture('Page', 'importantpage');
$page->doUnpublish();
Subsite::changeSubsite($vp1->SubsiteID);
$onLive = Versioned::get_one_by_stage('SubsitesVirtualPage', 'Live', "\"SiteTree_Live\".\"ID\" = ".$vp1->ID);
$this->assertNull($onLive, 'SVP has been removed from live');
$subsite = $this->objFromFixture('Subsite_Template', 'subsite2');
$subsite = $this->objFromFixture('Subsite', 'subsite2');
Subsite::changeSubsite($vp2->SubsiteID);
$onLive = Versioned::get_one_by_stage('SubsitesVirtualPage', 'Live', "\"SiteTree_Live\".\"ID\" = ".$vp2->ID);
$this->assertNull($onLive, 'SVP has been removed from live');
@ -213,11 +214,11 @@ class SubsitesVirtualPageTest extends SapphireTest {
*/
function testSubsiteVirtualPageCanHaveSameUrlsegmentAsOtherSubsite() {
Subsite::$write_hostmap = false;
$subsite1 = $this->objFromFixture('Subsite_Template', 'subsite1');
$subsite2 = $this->objFromFixture('Subsite_Template', 'subsite2');
$subsite1 = $this->objFromFixture('Subsite', 'subsite1');
$subsite2 = $this->objFromFixture('Subsite', 'subsite2');
Subsite::changeSubsite($subsite1->ID);
$subsite1Page = $this->objFromFixture('SiteTree', 'subsite1_staff');
$subsite1Page = $this->objFromFixture('Page', 'subsite1_staff');
$subsite1Page->URLSegment = 'staff';
$subsite1Page->write();
@ -256,4 +257,4 @@ class SubsitesVirtualPageTest extends SapphireTest {
}
}
}
}

View File

@ -3,7 +3,7 @@ File:
file1:
Filename: assets/testscript-test-file.pdf
Page:
SiteTree:
page1:
Title: page1
URLSegment: page1