diff --git a/forms/gridfield/GridField.php b/forms/gridfield/GridField.php index 3de4eb5c0..f58e37108 100755 --- a/forms/gridfield/GridField.php +++ b/forms/gridfield/GridField.php @@ -384,8 +384,11 @@ class GridField extends FormField { if($total > 0) { $rows = array(); foreach($list as $idx => $record) { + if(!$record->canView()) { + continue; + } $rowContent = ''; - foreach($columns as $column) { + foreach($this->getColumns() as $column) { $colContent = $this->getColumnContent($record, $column); // A return value of null means this columns should be skipped altogether. if($colContent === null) continue; @@ -409,8 +412,10 @@ class GridField extends FormField { $rows[] = $row; } $content['body'] = implode("\n", $rows); - - } else { //display a message when the grid field is empty + } + + // Display a message when the grid field is empty + if(!(isset($content['body']) && $content['body'])) { $content['body'] = $this->createTag( 'tr', array("class" => 'ss-gridfield-item ss-gridfield-no-items'), diff --git a/forms/gridfield/GridFieldDeleteAction.php b/forms/gridfield/GridFieldDeleteAction.php index f51ec62f8..f2837fed4 100644 --- a/forms/gridfield/GridFieldDeleteAction.php +++ b/forms/gridfield/GridFieldDeleteAction.php @@ -69,6 +69,9 @@ class GridFieldDeleteAction implements GridField_ColumnProvider, GridField_Actio * @return string - the HTML for the column */ public function getColumnContent($gridField, $record, $columnName) { + if(!$record->canDelete()) { + return; + } $field = Object::create('GridField_FormAction', $gridField, 'DeleteRecord'.$record->ID, @@ -96,6 +99,9 @@ class GridFieldDeleteAction implements GridField_ColumnProvider, GridField_Actio $id = $arguments['RecordID']; // Always deletes a record. Use GridFieldRelationDelete to detach it from the current relationship. $item = $gridField->getList()->byID($id); + if(!$item->canDelete()) { + throw new ValidationException(_t('GridFieldAction_Delete.DeletePermissionsFailure',"No delete permissions"),0); + } if(!$item) return; $item->delete(); } diff --git a/forms/gridfield/GridFieldEditAction.php b/forms/gridfield/GridFieldEditAction.php index af4dbb597..0425f4f51 100644 --- a/forms/gridfield/GridFieldEditAction.php +++ b/forms/gridfield/GridFieldEditAction.php @@ -72,6 +72,9 @@ class GridFieldEditAction implements GridField_ColumnProvider { * @return string - the HTML for the column */ public function getColumnContent($gridField, $record, $columnName) { + if(!$record->canEdit()){ + return; + } $data = new ArrayData(array( 'Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit') )); diff --git a/forms/gridfield/GridFieldTitle.php b/forms/gridfield/GridFieldTitle.php index 8eac6ea9f..31bceb52d 100644 --- a/forms/gridfield/GridFieldTitle.php +++ b/forms/gridfield/GridFieldTitle.php @@ -16,9 +16,20 @@ */ class GridFieldTitle implements GridField_HTMLProvider { + /** + * + * @var bool + */ protected $newEnabled = true; + + /** + * + * @var type + */ + protected $gridField = null; - function getHTMLFragments($gridField) { + public function getHTMLFragments( $gridField) { + $this->gridField = $gridField; return array( 'header' => $gridField->customise(array( 'NewLink' => Controller::join_links($gridField->Link('item'), 'new'), @@ -31,7 +42,14 @@ class GridFieldTitle implements GridField_HTMLProvider { * Returns whether or not the "add new" button will appear when rendering this DataGrid title * @return bool */ - function getNewEnabled() { + public function getNewEnabled() { + if($this->gridField) { + $model = singleton($this->gridField->getModelClass()); + if(!$model->canCreate()) { + return false; + } + } + return $this->newEnabled; } @@ -39,9 +57,7 @@ class GridFieldTitle implements GridField_HTMLProvider { * Enable or disable the "add new" button to add new DataGrid object instances * @param $enabled */ - function setNewEnabled($enabled) { + public function setNewEnabled($enabled) { $this->newEnabled = $enabled; } } - -?> \ No newline at end of file diff --git a/tests/forms/GridFieldTest.php b/tests/forms/GridFieldTest.php index 24d0543e3..5617bda17 100644 --- a/tests/forms/GridFieldTest.php +++ b/tests/forms/GridFieldTest.php @@ -417,6 +417,34 @@ class GridFieldTest extends SapphireTest { $this->setExpectedException('LogicException'); $field->FieldHolder(); } + + /** + * @covers GridField::FieldHolder + */ + public function testCanViewOnlyOddIDs() { + $this->logInWithPermission(); + $list = new ArrayList(array( + new GridFieldTest_Permissions(array("ID" => 1, "Email" => "ongi.schwimmer@example.org", 'Name' => 'Ongi Schwimmer')), + new GridFieldTest_Permissions(array("ID" => 2, "Email" => "klaus.lozenge@example.org", 'Name' => 'Klaus Lozenge')), + new GridFieldTest_Permissions(array("ID" => 3, "Email" => "otto.fischer@example.org", 'Name' => 'Otto Fischer')) + )); + + $config = new GridFieldConfig(); + $config->addComponent(new GridFieldDefaultColumns()); + $obj = new GridField('testfield', 'testfield', $list, $config); + $form = new Form(new Controller(), 'mockform', new FieldList(array($obj)), new FieldList()); + $content = new CSSContentParser($obj->FieldHolder()); + + $members = $content->getBySelector('.ss-gridfield-item tr'); + + $this->assertEquals(2, count($members)); + + $this->assertEquals((string)$members[0]->td[0], 'Ongi Schwimmer', 'First object Name should be Ongi Schwimmer'); + $this->assertEquals((string)$members[0]->td[1], 'ongi.schwimmer@example.org', 'First object Email should be ongi.schwimmer@example.org'); + + $this->assertEquals((string)$members[1]->td[0], 'Otto Fischer', 'Second object Name should be Otto Fischer'); + $this->assertEquals((string)$members[1]->td[1], 'otto.fischer@example.org', 'Second object Email should be otto.fischer@example.org'); + } } class GridFieldTest_Component implements GridField_ColumnProvider, GridField_ActionProvider, TestOnly{ @@ -473,7 +501,6 @@ class GridFieldTest_Player extends DataObject implements TestOnly { static $belongs_many_many = array('Teams' => 'GridFieldTest_Team'); } - class GridFieldTest_HTMLFragments implements GridField_HTMLProvider, TestOnly{ function __construct($fragments) { $this->fragments = $fragments; @@ -482,4 +509,22 @@ class GridFieldTest_HTMLFragments implements GridField_HTMLProvider, TestOnly{ function getHTMLFragments($gridField) { return $this->fragments; } +} + +class GridFieldTest_Permissions extends DataObject implements TestOnly { + public static $db = array( + 'Name' => 'Varchar', + 'Email' => 'Varchar', + ); + + public static $summary_fields = array( + 'Name', + 'Email' + ); + + public function canView($member = null) { + // Only records with odd numbers are viewable + if(!($this->ID % 2)){ return false; } + return true; + } } \ No newline at end of file diff --git a/tests/forms/gridfield/GridFieldActionTest.yml b/tests/forms/gridfield/GridFieldActionTest.yml new file mode 100644 index 000000000..20736a164 --- /dev/null +++ b/tests/forms/gridfield/GridFieldActionTest.yml @@ -0,0 +1,18 @@ +GridFieldAction_Delete_Team: + team1: + Name: Team 1 + City: Cologne + team2: + Name: Team 2 + City: Wellington + team3: + Name: Team 3 + City: Auckland + +GridFieldAction_Edit_Team: + team1: + Name: Team 1 + City: Cologne + team2: + Name: Team 2 + City: Wellington \ No newline at end of file diff --git a/tests/forms/gridfield/GridFieldDeleteActionTest.php b/tests/forms/gridfield/GridFieldDeleteActionTest.php new file mode 100644 index 000000000..750123207 --- /dev/null +++ b/tests/forms/gridfield/GridFieldDeleteActionTest.php @@ -0,0 +1,78 @@ +list = new DataList('GridFieldAction_Delete_Team'); + $config = GridFieldConfig::create()->addComponent(new GridFieldDeleteAction()); + $this->gridField = new GridField('testfield', 'testfield', $this->list, $config); + $this->form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList()); + } + + public function testDontShowDeleteButtons() { + if(Member::currentUser()) { Member::currentUser()->logOut(); } + $content = new CSSContentParser($this->gridField->FieldHolder()); + // Check that there are content + $this->assertEquals(4, count($content->getBySelector('.ss-gridfield-item'))); + // Make sure that there are no delete buttons + $this->assertEmpty($content->getBySelector('.gridfield-button-delete'), 'Delete buttons should not show when not logged in.'); + } + + public function testShowDeleteButtonsWithAdminPermission() { + $this->logInWithPermission('ADMIN'); + $content = new CSSContentParser($this->gridField->FieldHolder()); + $deleteButtons = $content->getBySelector('.gridfield-button-delete'); + $this->assertEquals(3, count($deleteButtons), 'Delete buttons should show when logged in.'); + } + + public function testDeleteActionWithoutCorrectPermission() { + if(Member::currentUser()) { Member::currentUser()->logOut(); } + $this->setExpectedException('ValidationException'); + + $stateID = 'testGridStateActionField'; + Session::set($stateID, array('grid'=>'', 'actionName'=>'deleterecord','args'=>array('RecordID'=>1))); + $request = new SS_HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID='.$stateID=>true)); + $this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request); + $this->assertEquals(3, $this->list->count(), 'User should\'t be able to delete records without correct permissions.'); + } + + public function testDeleteActionWithAdminPermission() { + $this->logInWithPermission('ADMIN'); + $stateID = 'testGridStateActionField'; + Session::set($stateID, array('grid'=>'', 'actionName'=>'deleterecord','args'=>array('RecordID'=>1))); + $request = new SS_HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID='.$stateID=>true)); + $this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request); + $this->assertEquals(2, $this->list->count(), 'User should be able to delete records with ADMIN permission.'); + } +} + +class GridFieldAction_Delete_Team extends DataObject implements TestOnly { + static $db = array( + 'Name' => 'Varchar', + 'City' => 'Varchar' + ); + + public function canView($member = null) { + return true; + } + + public function canDelete($member = null) { + return parent::canDelete($member); + } +} \ No newline at end of file diff --git a/tests/forms/gridfield/GridFieldEditActionTest.php b/tests/forms/gridfield/GridFieldEditActionTest.php new file mode 100644 index 000000000..07ef784b4 --- /dev/null +++ b/tests/forms/gridfield/GridFieldEditActionTest.php @@ -0,0 +1,55 @@ +list = new DataList('GridFieldAction_Edit_Team'); + $config = GridFieldConfig::create()->addComponent(new GridFieldEditAction()); + $this->gridField = new GridField('testfield', 'testfield', $this->list, $config); + $this->form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList()); + } + + public function testDontShowEditLinks() { + if(Member::currentUser()) { Member::currentUser()->logOut(); } + + $content = new CSSContentParser($this->gridField->FieldHolder()); + // Check that there are content + $this->assertEquals(3, count($content->getBySelector('.ss-gridfield-item'))); + // Make sure that there are no edit links + $this->assertEmpty($content->getBySelector('.edit-link'), 'Edit links should not show when not logged in.'); + } + + public function testShowEditLinksWithAdminPermission() { + $this->logInWithPermission('ADMIN'); + $content = new CSSContentParser($this->gridField->FieldHolder()); + $editLinks = $content->getBySelector('.edit-link'); + $this->assertEquals(2, count($editLinks), 'Edit links should show when logged in.'); + } +} + +class GridFieldAction_Edit_Team extends DataObject implements TestOnly { + static $db = array( + 'Name' => 'Varchar', + 'City' => 'Varchar' + ); + + public function canView($member = null) { + return true; + } +} \ No newline at end of file diff --git a/tests/forms/gridfield/GridFieldPopupFormsTest.php b/tests/forms/gridfield/GridFieldPopupFormsTest.php index b3dd04dad..c603f24a4 100644 --- a/tests/forms/gridfield/GridFieldPopupFormsTest.php +++ b/tests/forms/gridfield/GridFieldPopupFormsTest.php @@ -10,6 +10,7 @@ class GridFieldPopupFormsTest extends FunctionalTest { function testAddForm() { + $this->logInWithPermission('ADMIN'); $group = DataList::create('GridFieldPopupFormsTest_PeopleGroup') ->filter('Name', 'My Group') ->First(); @@ -45,6 +46,7 @@ class GridFieldPopupFormsTest extends FunctionalTest { } function testEditForm() { + $this->logInWithPermission('ADMIN'); $group = DataList::create('GridFieldPopupFormsTest_PeopleGroup') ->filter('Name', 'My Group') ->First(); diff --git a/tests/forms/gridfield/GridFieldRelationAddTest.php b/tests/forms/gridfield/GridFieldRelationAddTest.php index 618fde08b..82d6fbc7e 100644 --- a/tests/forms/gridfield/GridFieldRelationAddTest.php +++ b/tests/forms/gridfield/GridFieldRelationAddTest.php @@ -37,6 +37,7 @@ class GridFieldRelationAddTest extends FunctionalTest { } function testAdd() { + $this->logInWithPermission('ADMIN'); $team1 = $this->objFromFixture('GridFieldTest_Team', 'team1'); $team2 = $this->objFromFixture('GridFieldTest_Team', 'team2'); diff --git a/tests/forms/gridfield/GridFieldTitleTest.php b/tests/forms/gridfield/GridFieldTitleTest.php index bf9015ee9..11ab670d2 100644 --- a/tests/forms/gridfield/GridFieldTitleTest.php +++ b/tests/forms/gridfield/GridFieldTitleTest.php @@ -3,6 +3,7 @@ class GridFieldTitleTest extends SapphireTest { public function testGridTitleAddNewEnabled() { + $this->logInWithPermission('ADMIN'); //construct a fake form field to render out the grid field within it $config = new GridFieldConfig(); $config->addComponent($titleField = new GridFieldTitle()); @@ -17,6 +18,7 @@ class GridFieldTitleTest extends SapphireTest { } public function testGridTitleAddNewDisabled() { + $this->logInWithPermission('ADMIN'); //construct a fake form field to render out the grid field within it $config = new GridFieldConfig(); $config->addComponent($titleField = new GridFieldTitle()); @@ -29,5 +31,16 @@ class GridFieldTitleTest extends SapphireTest { $html = $form->forTemplate(); $this->assertNotContains('data-icon="add"', $html,"HTML does not contain the 'add new' button"); } -} -?> \ No newline at end of file + + public function testGridTitleAddNewWithoutPermission() { + if(Member::currentUser()) { Member::currentUser()->logOut(); } + $config = new GridFieldConfig(); + $config->addComponent($titleField = new GridFieldTitle()); + $grid = new GridField('TestField', 'Test Field', new DataList('Company'),$config); + $fields = new FieldList(new TabSet("Root",$tabMain = new Tab('Main',$grid))); + $form = new Form(Controller::curr(), "TestForm", $fields, new FieldList()); + + $html = $form->forTemplate(); + $this->assertNotContains('data-icon="add"', $html, "HTML should not contain the 'add new' button"); + } +} \ No newline at end of file