Skip to content

Commit

Permalink
API CHANGE Replaced LeftAndMain->ajaxupdatesort() and LeftAndMain->aj…
Browse files Browse the repository at this point in the history
…axupdateparent() with a combined LeftAndMain->savetreenode() (and a changed request parameter signature)
  • Loading branch information
chillu committed Mar 22, 2011
1 parent 564038b commit fd3ae91
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 74 deletions.
136 changes: 62 additions & 74 deletions code/LeftAndMain.php
Expand Up @@ -45,8 +45,7 @@ class LeftAndMain extends Controller {

static $allowed_actions = array(
'index',
'ajaxupdateparent',
'ajaxupdatesort',
'savetreenode',
'getitem',
'getsubtree',
'myprofile',
Expand Down Expand Up @@ -614,9 +613,18 @@ public function save($data, $form) {
}

/**
* Ajax handler for updating the parent of a tree node
* Update the position and parent of a tree node.
* Only saves the node if changes were made.
*
* Required data:
* - 'ID': The moved node
* - 'ParentID': New parent relation of the moved node (0 for root)
* - 'SiblingIDs': Array of all sibling nodes to the moved node (incl. the node itself).
* In case of a 'ParentID' change, relates to the new siblings under the new parent.
*
* @return SS_HTTPResponse JSON string with a
*/
public function ajaxupdateparent($request) {
public function savetreenode($request) {
if (!Permission::check('SITETREE_REORGANISE') && !Permission::check('ADMIN')) {
$this->response->setStatusCode(
403,
Expand All @@ -625,88 +633,68 @@ public function ajaxupdateparent($request) {
return;
}

$className = $this->stat('tree_class');
$statusUpdates = array('modified'=>array());
$id = $request->requestVar('ID');
$parentID = $request->requestVar('ParentID');
$siblingIDs = $request->requestVar('SiblingIDs');
$statusUpdates = array('modified'=>array());

if(is_numeric($id) && is_numeric($parentID) && $id != $parentID) {
$node = DataObject::get_by_id($this->stat('tree_class'), $id);
if($node){
if($node && !$node->canEdit()) return Security::permissionFailure($this);

$node->ParentID = $parentID;
$node->write();

$statusUpdates['modified'][$node->ID] = array(
'TreeTitle'=>$node->TreeTitle
);

// Update all dependent pages
if($virtualPages = DataObject::get("VirtualPage", "\"CopyContentFromID\" = $node->ID")) {
foreach($virtualPages as $virtualPage) {
$statusUpdates['modified'][$virtualPage->ID] = array(
'TreeTitle' => $virtualPage->TreeTitle()
);
}
}

$this->response->addHeader(
'X-Status',
_t('LeftAndMain.SAVED','saved')
);
}else{
$this->response->setStatusCode(
500,
_t(
'LeftAndMain.PLEASESAVE',
"Please Save Page: This page could not be upated because it hasn't been saved yet."
)
);
}
}
if(!is_numeric($id) || !is_numeric($parentID)) throw new InvalidArgumentException();

return Convert::raw2json($statusUpdates);
}

/**
* Ajax handler for updating the order of a number of tree nodes
* $_GET[ID]: An array of node ids in the correct order
* $_GET[MovedNodeID]: The node that actually got moved
*/
public function ajaxupdatesort($request) {
if (!Permission::check('SITETREE_REORGANISE') && !Permission::check('ADMIN')) {
$node = DataObject::get_by_id($className, $id);
if($node && !$node->canEdit()) return Security::permissionFailure($this);

if(!$node) {
$this->response->setStatusCode(
403,
_t('LeftAndMain.CANT_REORGANISE',"You do not have permission to rearange the site tree. Your change was not saved.")
500,
_t(
'LeftAndMain.PLEASESAVE',
"Please Save Page: This page could not be upated because it hasn't been saved yet."
)
);
return;
}

$className = $this->stat('tree_class');
$counter = 0;
$statusUpdates = array('modified'=>array());
// Update hierarchy (only if ParentID changed)
if($node->ParentID != $parentID) {
$node->ParentID = (int)$parentID;
$node->write();

$statusUpdates['modified'][$node->ID] = array(
'TreeTitle'=>$node->TreeTitle
);

// Update all dependent pages
if($virtualPages = DataObject::get("VirtualPage", "\"CopyContentFromID\" = $node->ID")) {
foreach($virtualPages as $virtualPage) {
$statusUpdates['modified'][$virtualPage->ID] = array(
'TreeTitle' => $virtualPage->TreeTitle()
);
}
}

if(!is_array($request->requestVar('ID'))) return false;

//Sorting root
if($request->requestVar('MovedNodeID')==0){
$movedNode = DataObject::get($className, "\"ParentID\"=0");
}else{
$movedNode = DataObject::get_by_id($className, $request->requestVar('MovedNodeID'));
$this->response->addHeader('X-Status', _t('LeftAndMain.SAVED','saved'));
}
foreach($request->requestVar('ID') as $id) {
if($id == $movedNode->ID) {
$movedNode->Sort = ++$counter;
$movedNode->write();
$statusUpdates['modified'][$movedNode->ID] = array(
'TreeTitle'=>$movedNode->TreeTitle
);
} else if(is_numeric($id)) {
// Nodes that weren't "actually moved" shouldn't be registered as
// having been edited; do a direct SQL update instead
++$counter;
DB::query("UPDATE \"$className\" SET \"Sort\" = $counter WHERE \"ID\" = '$id'");

// Update sorting
if(is_array($siblingIDs)) {
$counter = 0;
foreach($siblingIDs as $id) {
if($id == $node->ID) {
$node->Sort = ++$counter;
$node->write();
$statusUpdates['modified'][$node->ID] = array(
'TreeTitle' => $node->TreeTitle
);
} else if(is_numeric($id)) {
// Nodes that weren't "actually moved" shouldn't be registered as
// having been edited; do a direct SQL update instead
++$counter;
DB::query(sprintf("UPDATE \"%s\" SET \"Sort\" = %d WHERE \"ID\" = '%d'", $className, $counter, $id));
}
}

$this->response->addHeader('X-Status', _t('LeftAndMain.SAVED','saved'));
}

return Convert::raw2json($statusUpdates);
Expand Down
29 changes: 29 additions & 0 deletions tests/CMSMainTest.yml
@@ -1,65 +1,94 @@
Page:
page1:
Title: Page 1
Sort: 1
page2:
Title: Page 2
Sort: 2
page3:
Title: Page 3
Sort: 3
page31:
Title: Page 3.1
Parent: =>Page.page3
Sort: 1
page32:
Title: Page 3.2
Parent: =>Page.page3
Sort: 2
page4:
Title: Page 4
Sort: 4
page5:
Title: Page 5
Sort: 5
page6:
Title: Page 6
Sort: 6
page7:
Title: Page 7
Sort: 7
page8:
Title: Page 8
Sort: 8
page9:
Title: Page 9
Sort: 9
page10:
Title: Page 10
Sort: 10
page11:
Title: Page 11
Sort: 11
page12:
Title: Page 12
Sort: 12
page13:
Title: Page 13
Sort: 13
page14:
Title: Page 14
Sort: 14
page15:
Title: Page 15
Sort: 15
page16:
Title: Page 16
Sort: 16
page17:
Title: Page 17
Sort: 17
page18:
Title: Page 18
Sort: 18
page19:
Title: Page 19
Sort: 19
page20:
Title: Page 20
Sort: 20
page21:
Title: Page 21
Sort: 21
page22:
Title: Page 22
Sort: 22
page23:
Title: Page 23
Sort: 23
page24:
Title: Page 24
Sort: 24
page25:
Title: Page 25
Sort: 25
page26:
Title: Page 26
Sort: 26
home:
Title: Home
URLSegment: home
Sort: 27
Group:
admin:
Title: Administrators
Expand Down
61 changes: 61 additions & 0 deletions tests/LeftAndMainTest.php
Expand Up @@ -14,6 +14,67 @@ function setUp() {
CMSMenu::populate_menu();
}

public function testSaveTreeNodeSorting() {
$this->loginWithPermission('ADMIN');

$rootPages = DataObject::get('SiteTree', '"ParentID" = 0'); // implicitly sorted
$siblingIDs = $rootPages->column('ID');
$page1 = $rootPages->offsetGet(0);
$page2 = $rootPages->offsetGet(1);
$page3 = $rootPages->offsetGet(2);

// Move page2 before page1
$siblingIDs[0] = $page2->ID;
$siblingIDs[1] = $page1->ID;
$data = array(
'SiblingIDs' => $siblingIDs,
'ID' => $page2->ID,
'ParentID' => 0
);

$response = $this->post('admin/savetreenode', $data);
$this->assertEquals(200, $response->getStatusCode());
$page1 = DataObject::get_by_id('SiteTree', $page1->ID, false);
$page2 = DataObject::get_by_id('SiteTree', $page2->ID, false);
$page3 = DataObject::get_by_id('SiteTree', $page3->ID, false);

$this->assertEquals(2, $page1->Sort, 'Page1 is sorted after Page2');
$this->assertEquals(1, $page2->Sort, 'Page2 is sorted before Page1');
$this->assertEquals(3, $page3->Sort, 'Sort order for other pages is unaffected');
}

public function testSaveTreeNodeParentID() {
$this->loginWithPermission('ADMIN');

$page1 = $this->objFromFixture('Page', 'page1');
$page2 = $this->objFromFixture('Page', 'page2');
$page3 = $this->objFromFixture('Page', 'page3');
$page31 = $this->objFromFixture('Page', 'page31');
$page32 = $this->objFromFixture('Page', 'page32');

// Move page2 into page3, between page3.1 and page 3.2
$siblingIDs = array(
$page31->ID,
$page2->ID,
$page32->ID
);
$data = array(
'SiblingIDs' => $siblingIDs,
'ID' => $page2->ID,
'ParentID' => $page3->ID
);
$response = $this->post('admin/savetreenode', $data);
$this->assertEquals(200, $response->getStatusCode());
$page2 = DataObject::get_by_id('SiteTree', $page2->ID, false);
$page31 = DataObject::get_by_id('SiteTree', $page31->ID, false);
$page32 = DataObject::get_by_id('SiteTree', $page32->ID, false);

$this->assertEquals($page3->ID, $page2->ParentID, 'Moved page gets new parent');
$this->assertEquals(1, $page31->Sort, 'Children pages before insertaion are unaffected');
$this->assertEquals(2, $page2->Sort, 'Moved page is correctly sorted');
$this->assertEquals(3, $page32->Sort, 'Children pages after insertion are resorted');
}

/**
* Test that CMS versions can be interpreted appropriately
*/
Expand Down

0 comments on commit fd3ae91

Please sign in to comment.