From 5e9b67216f1191c0e19f5dda75ba6e685cd5335f Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Thu, 16 Aug 2007 06:38:29 +0000 Subject: [PATCH] Initial alpha version of the subsites module --- _config.php | 22 ++ code/GroupSubsites.php | 38 +++ code/LeftAndMainSubsites.php | 95 +++++++ code/SiteTreeSubsites.php | 128 ++++++++++ code/Subsite.php | 307 +++++++++++++++++++++++ code/SubsiteAdmin.php | 115 +++++++++ css/LeftAndMain_Subsites.css | 46 ++++ javascript/LeftAndMain_Subsites.js | 70 ++++++ templates/Includes/CMSTopMenu.ss | 13 + templates/Includes/SubsiteAdmin_left.ss | 17 ++ templates/Includes/SubsiteAdmin_right.ss | 17 ++ tests/SubsiteAdminTest.php | 19 ++ tests/SubsiteTest.php | 75 ++++++ tests/SubsiteTest.yml | 37 +++ 14 files changed, 999 insertions(+) create mode 100644 _config.php create mode 100644 code/GroupSubsites.php create mode 100644 code/LeftAndMainSubsites.php create mode 100644 code/SiteTreeSubsites.php create mode 100644 code/Subsite.php create mode 100644 code/SubsiteAdmin.php create mode 100644 css/LeftAndMain_Subsites.css create mode 100644 javascript/LeftAndMain_Subsites.js create mode 100644 templates/Includes/CMSTopMenu.ss create mode 100644 templates/Includes/SubsiteAdmin_left.ss create mode 100644 templates/Includes/SubsiteAdmin_right.ss create mode 100644 tests/SubsiteAdminTest.php create mode 100644 tests/SubsiteTest.php create mode 100644 tests/SubsiteTest.yml diff --git a/_config.php b/_config.php new file mode 100644 index 0000000..c58d0e2 --- /dev/null +++ b/_config.php @@ -0,0 +1,22 @@ + 'SubsiteAdmin', +)); +Object::addStaticVars( 'LeftAndMain', array( 'extra_menu_items' => array( + 'Sub-sites' => array("intranets", "admin/subsites/") +))); + +?> diff --git a/code/GroupSubsites.php b/code/GroupSubsites.php new file mode 100644 index 0000000..2d2b768 --- /dev/null +++ b/code/GroupSubsites.php @@ -0,0 +1,38 @@ +class == 'SiteTree') { + return array( + 'has_one' => array( + 'Subsite' => 'Subsite', + ), + ); + } + } + + + /** + * Update any requests to limit the results to the current site + */ + function augmentSQL(SQLQuery &$query) { + return; + // The foreach is an ugly way of getting the first key :-) + foreach($query->from as $tableName => $info) { + $query->where[] = "`$tableName`.SubsiteID = " . Subsite::currentSubsiteID(); + break; + } + + } + + function augmentBeforeWrite() { + if(!is_numeric($this->owner->ID)) $this->owner->SubsiteID = Subsite::currentSubsiteID(); + } +} + +?> \ No newline at end of file diff --git a/code/LeftAndMainSubsites.php b/code/LeftAndMainSubsites.php new file mode 100644 index 0000000..c3b8f3b --- /dev/null +++ b/code/LeftAndMainSubsites.php @@ -0,0 +1,95 @@ +Title : 'Site Content'; + } + + + public function changesubsite() { + $id = $_REQUEST['ID']; + + Subsite::changeSubsite($id); + + if(Director::is_ajax()) { + $tree = $this->owner->SiteTreeAsUL(); + $tree = ereg_replace('^[ \t\r\n]*]*>','', $tree); + $tree = ereg_replace(']*>[ \t\r\n]*$','', $tree); + return $tree; + } else + return array(); + } + + public function addsubsite() { + $name = $_REQUEST['Name']; + $newSubsite = Subsite::create($name); + + $subsites = $this->Subsites(); + + if(Director::is_ajax()) { + /*$output = "var option = null; for(var i = 0; i < \$('SubsitesSelect').size; i++) {\$('SubsitesSelect').remove(i);}\n"; + + if($subsites) { + foreach($subsites as $subsite) { + $output .= "option = document.createElement('option');\n option.title = '$subsite->Title';\n option.value = $subsite->ID;\$('SubsitesSelect').add(option);\n"; + } + } + + return $output;*/ + + return $this->SubsiteList(); + } else + return array(); + } + + public function Subsites() { + $subsites = Subsite::getSubsitesForMember(Member::currentUser(), array('CMS_ACCESS_CMSMain', 'ADMIN')); + + $siteList = new DataObjectSet(); + + if(Subsite::hasMainSitePermission(Member::currentUser(), array('CMS_ACCESS_CMSMain', 'ADMIN'))) + $siteList->push(new ArrayData(array('Title' => 'Main site', 'ID' => 0))); + + if($subsites) + $siteList->append($subsites); + + return $siteList; + } + + public function SubsiteList() { + $list = $this->Subsites(); + + if($list->Count() > 1) { + $output = ''; + + return $output; + } else { + return $list->First()->Title; + } + } + + public function CanAddSubsites() { + return Permission::check("ADMIN", "any", null, "all"); + }} + +?> \ No newline at end of file diff --git a/code/SiteTreeSubsites.php b/code/SiteTreeSubsites.php new file mode 100644 index 0000000..033b1b2 --- /dev/null +++ b/code/SiteTreeSubsites.php @@ -0,0 +1,128 @@ + 'Title' + ); + + protected 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; + } + + + function extraDBFields() { + // This is hard-coded to be applied to SiteTree, unfortunately + if($this->owner->class == 'SiteTree') { + return array( + 'has_one' => array( + 'Subsite' => 'Subsite', // The subsite that this page belongs to + 'MasterPage' => 'SiteTree', // Optional; the page that is the content master + 'CustomContent' => 'Boolean', // On a page that has a content master, set this to true to + ), + ); + } + } + + /** + * Update any requests to limit the results to the current site + */ + function augmentSQL(SQLQuery &$query) { + // If you're querying by ID, ignore the sub-site - this is a bit ugly... + if(strpos($query->where[0], ".`ID` = ") === false && strpos($query->where[0], ".ID = ") === false) { + + if($context = DataObject::context_obj()) { $subsiteID = $context->SubsiteID; } + else $subsiteID = Subsite::currentSubsiteID(); + + // The foreach is an ugly way of getting the first key :-) + foreach($query->from as $tableName => $info) { + $query->where[] = "`$tableName`.SubsiteID IN (0, $subsiteID)"; + break; + } + } + } + + function augmentBeforeWrite() { + if(!is_numeric($this->owner->ID) && !$this->owner->SubsiteID) $this->owner->SubsiteID = Subsite::currentSubsiteID(); + + // If the content has been changed, then the page should be marked as 'custom content' + if(!$this->owner->CustomContent) { + foreach(self::$template_fields as $field) { + if($this->owner->original[$field] != $this->owner->record[$field]) { + $this->owner->CustomContent = true; + FormResponse::add("$('Form_EditForm_CustomContent').checked = true;"); + break; + } + } + } + } + + function updateCMSFields(&$fields) { + if($this->owner->MasterPageID) { + $fields->insertFirst(new HeaderField('This page\'s content is copied from a master page: ' . $this->owner->MasterPage()->Title, 2)); + } + } + + /** + * Create a duplicate of this page and save it to another subsite + */ + public function duplicateToSubsite($subsiteID = null, $stage = 'Live') { + if(is_object($subsiteID)) { + $subsite = $subsiteID; + $subsiteID = $subsite->ID; + } else { + $subsite = DataObject::get_by_id('Subsite', $subsiteID); + } + + $page = $this->owner->duplicate(false); + + $page->CheckedPublicationDifferences = $page->AddedToStage = true; + $subsiteID = ($subsiteID ? $subsiteID : Subsite::currentSubsiteID()); + $page->SubsiteID = $subsiteID; + $page->MasterPageID = $this->owner->ID; + + foreach(self::$template_fields as $field) { + foreach(self::$template_variables as $variable => $intranetField) { + $page->$field = str_ireplace($variable, $subsite->$intranetField, $page->$field); + } + } + + $page->write(); + + return $page; + } + + /** + * Called by ContentController::init(); + */ + static function contentcontrollerInit($controller) { + // Need to set the SubsiteID to null incase we've been in the CMS + Session::set('SubsiteID', null); + } + + /** + * Called by ModelAsController::init(); + */ + static function modelascontrollerInit($controller) { + // Need to set the SubsiteID to null incase we've been in the CMS + Session::set('SubsiteID', null); + } +} + +?> \ No newline at end of file diff --git a/code/Subsite.php b/code/Subsite.php new file mode 100644 index 0000000..9efee11 --- /dev/null +++ b/code/Subsite.php @@ -0,0 +1,307 @@ + 'Varchar', + 'Title' => 'Varchar(255)', + 'RedirectURL' => 'Varchar(255)', + 'DefaultSite' => 'Boolean', + 'Theme' => 'Varchar', + 'Domain' => 'Varchar', + 'IsPublic' => 'Boolean' + ); + + static $indexes = array( + 'Subdomain' => true, + 'Domain' => true + ); + + static $base_domain, $default_subdomain; + + static $cached_subsite = null; + + /** + * Return the base domain for this set of subsites. + * You can set this by setting Subsite::$Base_domain, otherwise it defaults to HTTP_HOST + */ + static function base_domain() { + if(self::$base_domain) return self::$base_domain; + else return $_SERVER['HTTP_HOST']; + } + + /** + * Return the default domain of this set of subsites. Generally this will be the base domain, + * but hyou can also set Subsite::$default_subdomain to add a default prefix to this + */ + static function default_domain() { + if(self::$default_subdomain) return self::$default_subdomain . '.' . self::base_domain(); + else return self::base_domain(); + } + + /** + * Return the domain of this site + */ + function domain() { + $base = $this->Domain ? $this->Domain : self::base_domain(); + $sub = $this->Subdomain ? $this->Subdomain : self::$default_subdomain; + + if($sub) return "$sub.$base"; + else return $base; + } + + // Show the configuration fields for each subsite + function getCMSFields() { + $fields = new FieldSet( + new TabSet('Root', + new Tab('Configuration', + new HeaderField($this->getClassName() . ' configuration', 2), + new TextField('Title', 'Name of subsite:', $this->Title), + $this->domainField(), + // new TextField('RedirectURL', 'Redirect to URL', $this->RedirectURL), + new CheckboxField('DefaultSite', 'Use this subsite as the default site', $this->DefaultSite), + new CheckboxField('IsPublic', 'Can access this subsite publicly?', $this->IsPublic) + ) + ), + new HiddenField('ID', '', $this->ID), + new HiddenField('IsSubsite', '', 1) + ); + +// This code needs to be updated to reference the new SS 2.0.3 theme system +/* if($themes = SSViewer::getThemes(false)) + $fields->addFieldsToTab('Root.Configuration', new DropdownField('Theme', 'Theme:', $themes, $this->Theme)); +*/ + return $fields; + } + + function domainField() { + return new FieldGroup('Subsite domain', + new TextField('Subdomain',"", $this->Subdomain), + new TextField('Domain','.', $this->Domain) + ); + } + + function getClassName() { + return $this->class; + } + + function getCMSActions() { + return new FieldSet( + new FormAction('savesubsite', 'Save') + ); + } + + static function currentSubsite() { + if(!self::$cached_subsite) self::$cached_subsite = DataObject::get_by_id('Subsite', self::currentSubsiteID()); + return self::$cached_subsite; + } + + /** + * This function gets the current subsite ID from the session. It used in the backend so Ajax requests + * use the correct subsite. The frontend handles subsites differently. It calls getSubsiteIDForDomain + * directly from ModelAsController::getNestedController. + */ + static function currentSubsiteID() { + $id = Session::get('SubsiteID'); + + if($id === null) Session::set('SubsiteID', $id = self::getSubsiteIDForDomain()); + + return (int)$id; + } + + static function create($name) { + $newSubsite = Object::create('Subsite'); + $newSubsite->Title = $name; + $newSubsite->Subdomain = str_replace(' ', '-', preg_replace('/[^0-9A-Za-z\s]/', '', strtolower(trim($name)))); + $newSubsite->write(); + $newSubsite->createInitialRecords(); + return $newSubsite; + } + + /** + * Switch to another subsite + * @param $subsite Either the ID of the subsite, or the subsite object itself + */ + static function changeSubsite($subsite) { + + // Debug::backtrace(); + + if(!$subsite) { + Session::set('SubsiteID', 0); + return; + } + + if(is_object($subsite)) + $subsite = $subsite->ID; + + Session::set('SubsiteID', $subsite); + + /*if(!is_object($subsite) && is_numeric($subsite)) + $subsite = DataObject::get_by_id('Subsite', $subsite); + + if($subsite) + Session::set('SubsiteID', $subsite->ID);*/ + + } + + function canEdit() { + return true; + } + + static function getSubsiteIDForDomain() { + $domainNameParts = explode('.', $_SERVER['HTTP_HOST']); + + if($domainNameParts[0] == 'www') return 0; + + $SQL_subdomain = Convert::raw2sql(array_shift($domainNameParts)); + $SQL_domain = join('.', Convert::raw2sql($domainNameParts)); + // $_REQUEST['showqueries'] = 1; + if(self::$use_domain) { + $subsite = DataObject::get_one('Subsite',"`Subdomain` = '$SQL_subdomain' AND `Domain`='$SQL_domain' AND `IsPublic`=1"); + } else { + $subsite = DataObject::get_one('Subsite',"`Subdomain` = '$SQL_subdomain' AND `IsPublic`=1"); + } + + if($subsite) { + // This will need to be updated to use the current theme system + // SSViewer::setCurrentTheme($subsite->Theme); + return $subsite->ID; + } + } + + function getMembersByPermission($permissionCodes = array('ADMIN')){ + if(!is_array($permissionCodes)) + user_error('Permissions must be passed to Subsite::getMembersByPermission as an array', E_USER_ERROR); + $SQL_permissionCodes = Convert::raw2sql($permissionCodes); + + $SQL_permissionCodes = join("','", $SQL_permissionCodes); + + $join = <<ID AND `Permission`.`Code` IN ('$SQL_permissionCodes')", '', $join); + } + + static function getSubsitesForMember( $member = null, $permissionCodes = array('ADMIN')) { + if(!is_array($permissionCodes)) + user_error('Permissions must be passed to Subsite::getSubsitesForMember as an array', E_USER_ERROR); + + if(!$member) + $member = Member::currentMember(); + + $memberID = (int)$member->ID; + + $SQLa_permissionCodes = Convert::raw2sql($permissionCodes); + + $SQLa_permissionCodes = join("','", $SQLa_permissionCodes); + + if(self::hasMainSitePermission($member, $permissionCodes)) + return DataObject::get('Subsite'); + else + return DataObject::get('Subsite', "`MemberID` = {$memberID}" . ($permissionCodes ? " AND `Permission`.`Code` IN ('$SQLa_permissionCodes')" : ''), '', "LEFT JOIN `Group` ON `Subsite`.`ID` = `SubsiteID` LEFT JOIN `Permission` ON `Group`.`ID` = `Permission`.`GroupID` LEFT JOIN `Group_Members` ON `Group`.`ID` = `Group_Members`.`GroupID`"); + } + + static function hasMainSitePermission($member = null, $permissionCodes = array('ADMIN')) { + + if(!is_array($permissionCodes)) + user_error('Permissions must be passed to Subsite::hasMainSitePermission as an array', E_USER_ERROR); + + if(!$member) + $member = Member::currentMember(); + + $SQLa_perm = Convert::raw2sql($permissionCodes); + $SQL_perms = join("','", $SQLa_perm); + $memberID = (int)$member->ID; + + return DB::query("SELECT COUNT(`Permission`.`ID`) FROM `Permission` LEFT JOIN `Group` ON `Group`.`ID` = `Permission`.`GroupID` LEFT JOIN `Group_Members` USING(`GroupID`) WHERE `Permission`.`Code` IN ('$SQL_perms') AND `SubsiteID` = 0 AND `MemberID` = {$memberID}")->value(); + } + + function createInitialRecords() { + + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // CMS ADMINISTRATION HELPERS + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Return the FieldSet that will build the search form in the CMS + */ + function adminSearchFields() { + return new FieldSet( + new TextField('Name', 'Sub-site name') + ); + } + +} + +/** + * An instance of subsite that can be duplicated to provide a quick way to create new subsites. + */ +class Subsite_Template extends Subsite { + + function duplicate($args = null) { + if(!$args) + $args = array(); + + // create the subsite + $subsite = Subsite::create(''); + + // Apply arguments to field values + + $subsite->write(); + } + + + /** + * Create an instance of this template, with the given title & subdomain + */ + function createInstance($title, $subdomain) { + $intranet = Object::create('Subsite'); + $intranet->Title = $title; + $intranet->Domain = $this->Domain; + $intranet->Subdomain = $subdomain; + $intranet->TemplateID = $this->ID; + $intranet->write(); + + + $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. + * 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('Page', 'Live', "`ParentID`=$sourceParentID", ''); + + if($children) { + foreach($children as $child) { + $childClone = $child->duplicateToSubsite($intranet, 'Stage'); + $childClone->ParentID = $destParentID; + $childClone->writeToStage('Stage'); + $childClone->publish('Stage', 'Live'); + array_push($stack, array($child->ID, $childClone->ID)); + } + } + } + + self::changeSubsite($oldSubsiteID); + + return $intranet; + } +} +?> diff --git a/code/SubsiteAdmin.php b/code/SubsiteAdmin.php new file mode 100644 index 0000000..306b990 --- /dev/null +++ b/code/SubsiteAdmin.php @@ -0,0 +1,115 @@ +adminSearchFields(); + } + + function getLink() { + return 'admin/intranets/'; + } + + function Link() { + return $this->getLink(); + } + + function Results() { + $where = ''; + + if(isset($_REQUEST['action_getResults']) && $_REQUEST['action_getResults']) { + $SQL_name = Convert::raw2sql($_REQUEST['Name']); + $where = "`Title` LIKE '%$SQL_name%'"; + } + + $intranets = DataObject::get('Intranet', $where); + if(!$intranets) + return null; + + $html = ""; + + $numIntranets = 0; + foreach($intranets as $intranet) { + $numIntranets++; + $evenOdd = ($numIntranets % 2) ? 'odd':'even'; + $html .= ""; + } + $html .= "
NameDomain
ID}\">{$intranet->Title}{$intranet->Subdomain}.{$intranet->Domain}
"; + return $html; + } + + function AddSubsiteForm() { + $templates = $this->getIntranetTemplates(); + + if($templates) { + $templateArray = $templates->map('ID', 'Domain'); + } + + return new Form($this, 'AddIntranetForm', new FieldSet( + new TextField('Name', 'Name:'), + new TextField('Subdomain', 'Subdomain:'), + new DropdownField('TemplateID', 'Use template:', $templateArray), + new TextField('AdminName', 'Admin name:'), + new EmailField('AdminEmail', 'Admin email:') + ), + new FieldSet( + new FormAction('addintranet', 'Add') + )); + } + + public function getIntranetTemplates() { + return DataObject::get('Subsite_Template', '', 'Domain DESC'); + } + + function addintranet($data, $form) { + + $SQL_email = Convert::raw2sql($data['AdminEmail']); + $member = DataObject::get_one('Member', "`Email`='$SQL_email'"); + + if(!$member) { + $member = Object::create('Member'); + $nameParts = explode(' ', $data['AdminName']); + $member->FirstName = array_shift($nameParts); + $member->Surname = join(' ', $nameParts); + $member->Email = $data['AdminEmail']; + $member->write(); + } + + // Create intranet from existing template + // TODO Change template based on the domain selected. + $intranet = Intranet::createFromTemplate($data['Name'], $data['Subdomain'], $data['TemplateID']); + + $groupObjects = array(); + + // create Staff, Management and Administrator groups + $groups = array( + 'Administrators' => array('CL_ADMIN', 'CMS_ACCESS_CMSMain', 'CMS_ACCESS_AssetAdmin', 'CMS_ACCESS_SecurityAdmin', 'CMS_ACCESS_IntranetAdmin'), + 'Management' => array('CL_MGMT'), + 'Staff' => array('CL_STAFF') + ); + foreach($groups as $name => $perms) { + $group = new Group(); + $group->SubsiteID = $intranet->ID; + $group->Title = $name; + $group->write(); + + foreach($perms as $perm) { + Permission::grant($group->ID, $perm); + } + + $groupObjects[$name] = $group; + } + + $member->Groups()->add($groupObjects['Administrators']); + + Director::redirect('admin/intranets/show/' . $intranet->ID); + } +} +?> diff --git a/css/LeftAndMain_Subsites.css b/css/LeftAndMain_Subsites.css new file mode 100644 index 0000000..1eb3ea9 --- /dev/null +++ b/css/LeftAndMain_Subsites.css @@ -0,0 +1,46 @@ +/** + * Styling for the subsite actions section in the CMS + */ +#SubsiteActions{ + position: absolute; + padding : 0px; + margin : 0px; + right: 0px; + top: 0px; + width: 250px; +} + +#SubsiteActions fieldset { + background-color : #a5aab0; + padding : 3px; + border : 1px solid #65686e; + border-top : none; + border-right : none; + margin-top : 1px; + background: 30%; +} + +#SubsiteActions fieldset #SubsitesSelect{ + font-size : 12px; + width: 240px; +} + +#SubsiteActions { + height : 51px; + border-bottom: 3px solid #d4d0c8; + background: url(../images/mainmenu/top-bg.gif) top left repeat-x; + color: #FFF; +} + +#top { + position: relative; +} +#top #MainMenu #Menu-help { + margin-right: 260px; +} + +#AddSubsiteLink { + display: block; + font-size: 80%; + margin-left: 3px; +} \ No newline at end of file diff --git a/javascript/LeftAndMain_Subsites.js b/javascript/LeftAndMain_Subsites.js new file mode 100644 index 0000000..9a0635a --- /dev/null +++ b/javascript/LeftAndMain_Subsites.js @@ -0,0 +1,70 @@ +Behaviour.register({ + '#SubsiteActions select' : { + onchange: function() { + var request = new Ajax.Request('admin/changesubsite?ID=' + this.value + '&ajax=1', { + onSuccess: function(response) { + $('sitetree').innerHTML = response.responseText; + SiteTree.applyTo($('sitetree')); + $('sitetree').getTreeNodeByIdx(0).onselect(); + }, + + onFailure: function(response) { + errorMessage('Could not change subsite', response); + } + }); + } + }, + + '#SubsiteActions a' : { + onclick: function() { + var subsiteName = prompt('Enter the name of the new site',''); + if(subsiteName && subsiteName != '') { + var request = new Ajax.Request(this.href + '?Name=' + encodeURIComponent(subsiteName) + '&ajax=1', { + onSuccess: function(response) { + var origSelect = $('SubsitesSelect'); + var div = document.createElement('div'); + div.innerHTML = response.responseText; + var newSelect = div.firstChild; + + while(origSelect.length > 0) + origSelect.remove(0); + + for(var j = 0; j < newSelect.length; j++) { + var opt = newSelect.options.item(j).cloneNode(true); + var newOption = document.createElement('option'); + + /*if(opt.text) + newOption.text = opt.text;*/ + if(opt.firstChild) + newOption.text = opt.firstChild.nodeValue; + + newOption.value = opt.value; + //console.log(newOption.text + ' ' + newOption.value); + try { + origSelect.add(newOption, null); + } catch(ex) { + origSelect.add(newOption); + } + } + + statusMessage('Created ' + subsiteName, 'good'); + }, + onFailure: function(response) { + errorMessage('Could not create new subsite', response); + } + }); + } + + return false; + } + } +}); + +// Add an item to fieldsToIgnore +Behaviour.register({ + '#Form_EditForm' : { + initialize: function () { + this.changeDetection_fieldsToIgnore.IsSubsite = true; + } + } +}); diff --git a/templates/Includes/CMSTopMenu.ss b/templates/Includes/CMSTopMenu.ss new file mode 100644 index 0000000..381d1a9 --- /dev/null +++ b/templates/Includes/CMSTopMenu.ss @@ -0,0 +1,13 @@ + +
+
+ $ApplicationLogoText + <% if CanAddSubsites %>Add a site <% end_if %> + $SubsiteList + +
+
diff --git a/templates/Includes/SubsiteAdmin_left.ss b/templates/Includes/SubsiteAdmin_left.ss new file mode 100644 index 0000000..331ca0e --- /dev/null +++ b/templates/Includes/SubsiteAdmin_left.ss @@ -0,0 +1,17 @@ +
+
My +Site
+
+ +
+

Create Intranet

+
+$AddSubsiteForm +
+

Search for Intranets

+
+$SearchForm +
+
+$Results
+
\ No newline at end of file diff --git a/templates/Includes/SubsiteAdmin_right.ss b/templates/Includes/SubsiteAdmin_right.ss new file mode 100644 index 0000000..971dab2 --- /dev/null +++ b/templates/Includes/SubsiteAdmin_right.ss @@ -0,0 +1,17 @@ +
+
Edit +Page
+
+<% include Editor_toolbar %> <% if EditForm %> $EditForm <% else %> +
+

$ApplicationName

+ +

Welcome to $ApplicationName! Please choose click on one of the +entries on the left pane.

+ +
+<% end_if %> + + + diff --git a/tests/SubsiteAdminTest.php b/tests/SubsiteAdminTest.php new file mode 100644 index 0000000..53c02dd --- /dev/null +++ b/tests/SubsiteAdminTest.php @@ -0,0 +1,19 @@ +getIntranetTemplates(); + + $templateIDs = $this->allFixtureIDs('Subsite_Template'); + $this->assertTrue($templates->onlyContainsIDs($templateIDs)); + } + +} + +?> \ No newline at end of file diff --git a/tests/SubsiteTest.php b/tests/SubsiteTest.php new file mode 100644 index 0000000..5f52548 --- /dev/null +++ b/tests/SubsiteTest.php @@ -0,0 +1,75 @@ +objFromFixture('Subsite_Template', 'main'); + + // Test that changeSubsite is working + Subsite::changeSubsite($template->ID); + + $tmplHome = DataObject::get_one('SiteTree', "URLSegment = 'home'"); + + // Publish all the pages in the template, testing that DataObject::get only returns pages from the chosen subsite + $pages = DataObject::get("SiteTree"); + $totalPages = $pages->TotalItems(); + foreach($pages as $page) { + $this->assertEquals($template->ID, $page->SubsiteID); + $page->publish('Stage', 'Live'); + } + + // Create a new site + $subsite = $template->createInstance('My Site', 'something'); + + // Check title + $this->assertEquals($subsite->Title, 'My Site'); + + // Check that domain generation is working + $this->assertEquals($subsite->domain(), 'something.test.com'); + + // Another test that changeSubsite is working + Subsite::changeSubsite($subsite->ID); + $pages = DataObject::get("SiteTree"); + + $siteHome = DataObject::get_one('SiteTree', "URLSegment = 'home'"); + $this->assertEquals($subsite->ID, $siteHome->SubsiteID); + + // Check master page value + $this->assertEquals($siteHome->MasterPageID, $tmplHome->ID); + + // Check linking of child pages + $tmplStaff = $this->objFromFixture('Page','staff'); + $siteStaff = DataObject::get_one('SiteTree', "URLSegment = '" . Convert::raw2sql($tmplStaff->URLSegment) . "'"); + $this->assertEquals($siteStaff->MasterPageID, $tmplStaff->ID); + + } + + /** + * Only the published content from the template should publish. + */ + function testUnpublishedPagesDontCopy() { + + } + + /** + * Publish a change on a master page of a newly created sub-site, and verify that the change has been propagated. + * Verify that if CustomContent is set, then the changes aren't propagated. + */ + + /** + * Reorganise a couple of pages on the master site and verify that the changes are propagated, whether or not CustomContent + * is set. + */ + + /** + * Edit a subsite's content and verify that CustomContent is set on the page. + * Edit a page without actually making any changes and verify that CustomContent isn't set. + */ + + +} \ No newline at end of file diff --git a/tests/SubsiteTest.yml b/tests/SubsiteTest.yml new file mode 100644 index 0000000..b002995 --- /dev/null +++ b/tests/SubsiteTest.yml @@ -0,0 +1,37 @@ +Subsite_Template: + main: + Title: Template + Domain: test.com + other: + Title: Other Template + Domain: other.com + +Page: + home: + Title: Home + SubsiteID: =>Subsite_Template.main + about: + Title: About + SubsiteID: =>Subsite_Template.main + staff: + Title: Staff + ParentID: =>Page.about + SubsiteID: =>Subsite_Template.main + contact: + Title: Contact Us + SubsiteID: =>Subsite_Template.main + +# Pages from the other template - added here as a control group :-) + home2: + Title: Home + SubsiteID: =>Subsite_Template.other + contact2: + Title: Contact Us + SubsiteID: =>Subsite_Template.other + +#ErrorPage: +# 404: +# Title: Page not Found +# ErrorCode: 404 +# SubsiteID: =>Subsite_Template.main + \ No newline at end of file