diff --git a/README.md b/README.md index c547ed1..f4ec18f 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/code/SubsiteAdmin.php b/code/SubsiteAdmin.php index cbe566e..62e67fc 100644 --- a/code/SubsiteAdmin.php +++ b/code/SubsiteAdmin.php @@ -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; } } diff --git a/code/extensions/LeftAndMainSubsites.php b/code/extensions/LeftAndMainSubsites.php index 22cf963..07f6704 100644 --- a/code/extensions/LeftAndMainSubsites.php +++ b/code/extensions/LeftAndMainSubsites.php @@ -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"; - } + } $output .= ''; @@ -103,7 +113,7 @@ class LeftAndMainSubsites extends Extension { return $output; }else { return ''.$list->First()->Title.''; - } + } } } @@ -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)); + } +} \ No newline at end of file diff --git a/code/extensions/SiteTreeSubsites.php b/code/extensions/SiteTreeSubsites.php index 65f3299..5db49e8 100644 --- a/code/extensions/SiteTreeSubsites.php +++ b/code/extensions/SiteTreeSubsites.php @@ -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', + '

This page\'s content is copied from the %s master page (edit)

' + ), + $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; } } -} +} \ No newline at end of file diff --git a/code/forms/GridFieldSubsiteDetailForm.php b/code/forms/GridFieldSubsiteDetailForm.php index df61917..eabc89f 100644 --- a/code/forms/GridFieldSubsiteDetailForm.php +++ b/code/forms/GridFieldSubsiteDetailForm.php @@ -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(); } } diff --git a/code/model/Subsite.php b/code/model/Subsite.php index 77d9780..34317d7 100644 --- a/code/model/Subsite.php +++ b/code/model/Subsite.php @@ -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(); } } diff --git a/code/tasks/SubsiteCopyPagesTask.php b/code/tasks/SubsiteCopyPagesTask.php new file mode 100644 index 0000000..8448bec --- /dev/null +++ b/code/tasks/SubsiteCopyPagesTask.php @@ -0,0 +1,67 @@ + to= + */ +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"; + } +} \ No newline at end of file diff --git a/javascript/LeftAndMain_Subsites.js b/javascript/LeftAndMain_Subsites.js index 5473b4f..a06caf2 100644 --- a/javascript/LeftAndMain_Subsites.js +++ b/javascript/LeftAndMain_Subsites.js @@ -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); \ No newline at end of file diff --git a/javascript/SubsitesTreeDropdownField.js b/javascript/SubsitesTreeDropdownField.js index 7d5c9f1..dfd645d 100644 --- a/javascript/SubsitesTreeDropdownField.js +++ b/javascript/SubsitesTreeDropdownField.js @@ -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); diff --git a/tests/BaseSubsiteTest.php b/tests/BaseSubsiteTest.php new file mode 100644 index 0000000..5eb58cb --- /dev/null +++ b/tests/BaseSubsiteTest.php @@ -0,0 +1,13 @@ +objFromFixture("Member","admin"); diff --git a/tests/SiteConfigSubsitesTest.php b/tests/SiteConfigSubsitesTest.php index 0727081..075eff1 100644 --- a/tests/SiteConfigSubsitesTest.php +++ b/tests/SiteConfigSubsitesTest.php @@ -1,6 +1,6 @@ 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); diff --git a/tests/SubsiteAdminFunctionalTest.php b/tests/SubsiteAdminFunctionalTest.php index a1e9f8b..0b3a656 100644 --- a/tests/SubsiteAdminFunctionalTest.php +++ b/tests/SubsiteAdminFunctionalTest.php @@ -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'); diff --git a/tests/SubsiteAdminTest.php b/tests/SubsiteAdminTest.php index fc39f3a..d6f0ca0 100644 --- a/tests/SubsiteAdminTest.php +++ b/tests/SubsiteAdminTest.php @@ -1,29 +1,29 @@ $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(), ' exists"); - } + $this->assertTrue(strpos($response2->getBody(), ' 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"); } diff --git a/tests/SubsiteTest.php b/tests/SubsiteTest.php index 875a852..47c7a62 100644 --- a/tests/SubsiteTest.php +++ b/tests/SubsiteTest.php @@ -1,6 +1,6 @@ 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); } -} +} \ No newline at end of file diff --git a/tests/SubsiteTest.yml b/tests/SubsiteTest.yml index 363ccb8..adcd7e1 100644 --- a/tests/SubsiteTest.yml +++ b/tests/SubsiteTest.yml @@ -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 diff --git a/tests/SubsitesVirtualPageTest.php b/tests/SubsitesVirtualPageTest.php index 244a416..1d51277 100644 --- a/tests/SubsitesVirtualPageTest.php +++ b/tests/SubsitesVirtualPageTest.php @@ -1,6 +1,6 @@ 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 { } } -} +} \ No newline at end of file diff --git a/tests/SubsitesVirtualPageTest.yml b/tests/SubsitesVirtualPageTest.yml index 45906ae..4708448 100644 --- a/tests/SubsitesVirtualPageTest.yml +++ b/tests/SubsitesVirtualPageTest.yml @@ -3,7 +3,7 @@ File: file1: Filename: assets/testscript-test-file.pdf -Page: +SiteTree: page1: Title: page1 URLSegment: page1