Merge pull request #168 from creative-commoners/issue/150

FIX document and documentset permissions
This commit is contained in:
Robbie Averill 2017-06-14 11:59:17 +12:00 committed by GitHub
commit d57fc88bfa
9 changed files with 290 additions and 39 deletions

View File

@ -316,4 +316,29 @@ class DMSDocumentAddController extends LeftAndMain
)
);
}
/**
* Overrides the parent method to allow users with access to DMS admin to access this controller
*
* @param Member $member
* @return bool
*/
public function canView($member = null)
{
if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
$member = Member::currentUser();
}
if ($member &&
Permission::checkMember(
$member,
array(
'CMS_ACCESS_DMSDocumentAdmin',
)
)
) {
return true;
}
return parent::canView($member);
}
}

View File

@ -18,7 +18,6 @@ class DMSDocumentAdmin extends ModelAdmin
parent::init();
Requirements::javascript(DMS_DIR . '/javascript/DMSGridField.js');
}
/**
* Remove the default "add" button and replace it with a customised version for DMS
*
@ -45,6 +44,9 @@ class DMSDocumentAdmin extends ModelAdmin
{
$gridFieldConfig = $gridField->getConfig();
$gridFieldConfig->removeComponentsByType('GridFieldEditButton');
$gridFieldConfig->addComponent(new DMSGridFieldEditButton(), 'GridFieldDeleteAction');
if ($this->modelClass === 'DMSDocument') {
$gridFieldConfig->removeComponentsByType('GridFieldAddNewButton');
$gridFieldConfig->addComponent(

View File

@ -0,0 +1,26 @@
<?php
class DMSGridFieldEditButton extends GridFieldEditButton implements GridField_ColumnProvider
{
/**
* Overriding the parent method to change the template that the DMS edit button will be rendered with based on
* whether or not the user has edit permissions.
*
* @param GridField $gridField
* @param DataObject $record
* @param string $columnName
*
* @return string - the HTML for the column
*/
public function getColumnContent($gridField, $record, $columnName)
{
$data = new ArrayData(array(
'Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit')
));
$template = $record->canEdit() ? 'GridFieldEditButton' : 'GridFieldViewButton';
return $data->renderWith($template);
}
}

View File

@ -16,6 +16,15 @@ class DMSSiteTreeExtension extends DataExtension
return;
}
// Hides the DocumentSets tab if the user has no permisions
if (!Permission::checkMember(
Member::currentUser(),
array('ADMIN', 'CMS_ACCESS_DMSDocumentAdmin')
)
) {
return;
}
$gridField = GridField::create(
'Document Sets',
false,

View File

@ -116,7 +116,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
if (!$this->CanViewType || $this->CanViewType == 'Anyone') {
return true;
}
if ($member && Permission::checkMember($member, array(
'ADMIN',
'SITETREE_EDIT_ALL',
@ -198,6 +197,13 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
}
}
// Do early admin check
if ($member &&
Permission::checkMember($member, array('CMS_ACCESS_DMSDocumentAdmin'))
) {
return true;
}
return $this->canEdit($member);
}
@ -220,7 +226,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
}
}
return $this->canView();
return $this->canEdit($member);
}
/**
@ -838,8 +844,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
$this->addActionPanelTask('find-versions', 'Versions');
}
$fields->add(LiteralField::create('BottomTaskSelection', $this->getActionTaskHtml()));
$embargoValue = 'None';
if ($this->EmbargoedIndefinitely) {
$embargoValue = 'Indefinitely';
@ -894,12 +898,19 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
FieldGroup::create($uploadField)->addExtraClass('replace'),
FieldGroup::create($pagesGrid)->addExtraClass('find-usage'),
FieldGroup::create($referencesGrid)->addExtraClass('find-references'),
FieldGroup::create($versionsGrid)->addExtraClass('find-versions'),
FieldGroup::create($this->getRelatedDocumentsGridField())->addExtraClass('find-relateddocuments'),
FieldGroup::create($this->getPermissionsActionPanel())->addExtraClass('permissions')
);
$actionsPanel->setName("ActionsPanel");
if ($this->canEdit()) {
$actionsPanel->push(FieldGroup::create($versionsGrid)->addExtraClass('find-versions'));
$actionsPanel->push(
FieldGroup::create($this->getRelatedDocumentsGridField())->addExtraClass('find-relateddocuments')
);
} else {
$this->removeActionPanelTask('find-relateddocuments')->removeActionPanelTask('find-versions');
}
$fields->add(LiteralField::create('BottomTaskSelection', $this->getActionTaskHtml()));
$actionsPanel->setName('ActionsPanel');
$actionsPanel->addExtraClass('dmsdocument-actionspanel');
$fields->push($actionsPanel);
@ -1204,6 +1215,10 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
new GridFieldConfig_RelationEditor
);
$gridFieldConfig = $gridField->getConfig();
$gridFieldConfig->removeComponentsByType('GridFieldEditButton');
$gridFieldConfig->addComponent(new DMSGridFieldEditButton(), 'GridFieldDeleteAction');
$gridField->getConfig()->removeComponentsByType('GridFieldAddNewButton');
// Move the autocompleter to the left
$gridField->getConfig()->removeComponentsByType('GridFieldAddExistingAutocompleter');
@ -1219,7 +1234,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
$addExisting->setResultsFormat('$Filename');
$this->extend('updateRelatedDocumentsGridField', $gridField);
return $gridField;
}
@ -1323,4 +1337,18 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
return $html;
}
/**
* Removes an "action panel" tasks
*
* @param string $panelKey
* @return $this
*/
public function removeActionPanelTask($panelKey)
{
if (array_key_exists($panelKey, $this->actionTasks)) {
unset($this->actionTasks[$panelKey]);
}
return $this;
}
}

View File

@ -97,7 +97,7 @@ class DMSDocumentSet extends DataObject
new GridFieldFilterHeader(),
new GridFieldSortableHeader(),
new GridFieldDataColumns(),
new GridFieldEditButton(),
new DMSGridFieldEditButton(),
// Special delete dialog to handle custom behaviour of unlinking and deleting
new GridFieldDeleteAction(true),
new GridFieldDetailForm()
@ -121,6 +121,13 @@ class DMSDocumentSet extends DataObject
$fields->fieldByName('Root.Main.PageID')->setTitle(_t('DMSDocumentSet.SHOWONPAGE', 'Show on page'));
}
// Don't show which page this is if we're already editing within a page context
if (Controller::curr() instanceof CMSPageEditController) {
$fields->removeByName('PageID');
} else {
$fields->fieldByName('Root.Main.PageID')->setTitle(_t('DMSDocumentSet.SHOWONPAGE', 'Show on page'));
}
$gridFieldConfig->getComponentByType('GridFieldDataColumns')
->setDisplayFields($self->getDocumentDisplayFields())
->setFieldCasting(array('LastEdited' => 'Datetime->Ago'))
@ -348,4 +355,63 @@ class DMSDocumentSet extends DataObject
}
return $result;
}
public function canView($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->getGlobalPermission($member);
}
public function canCreate($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->getGlobalPermission($member);
}
public function canEdit($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->getGlobalPermission($member);
}
public function canDelete($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->getGlobalPermission($member);
}
/**
* Checks if a then given (or logged in) member is either an ADMIN, SITETREE_EDIT_ALL or has access
* to the DMSDocumentAdmin module, in which case permissions is granted.
*
* @param Member $member
* @return bool
*/
public function getGlobalPermission(Member $member = null)
{
if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
$member = Member::currentUser();
}
$result = ($member &&
Permission::checkMember(
$member,
array('ADMIN', 'SITETREE_EDIT_ALL', 'CMS_ACCESS_DMSDocumentAdmin')
)
);
return (bool) $result;
}
}

View File

@ -244,4 +244,27 @@ class DMSDocumentSetTest extends SapphireTest
$fields = $set->getCMSFields();
$this->assertNull($fields->fieldByName('Root.Main.PageID'));
}
/**
* Tests all crud permissions
*/
public function testPermissions()
{
if ($member = Member::currentUser()) {
$member->logout();
}
$set = $this->objFromFixture('DMSDocumentSet', 'ds1');
$this->assertFalse($set->canCreate());
$this->assertFalse($set->canDelete());
$this->assertFalse($set->canEdit());
$this->assertFalse($set->canView());
$this->logInWithPermission('CMS_ACCESS_DMSDocumentAdmin');
$this->assertTrue($set->canCreate());
$this->assertTrue($set->canDelete());
$this->assertTrue($set->canEdit());
$this->assertTrue($set->canView());
}
}

View File

@ -49,7 +49,9 @@ class DMSDocumentTest extends SapphireTest
public function testDocumentHasCmsFieldForManagingRelatedDocuments()
{
$document = $this->objFromFixture('DMSDocument', 'document_with_relations');
$gridField = $this->getGridFieldFromDocument($document);
$gridField = $this->getRelatedDocumentsGridField($document);
$this->assertInstanceOf('GridField', $gridField);
$gridFieldConfig = $gridField->getConfig();
$this->assertNotNull(
@ -64,13 +66,25 @@ class DMSDocumentTest extends SapphireTest
);
}
/**
* Ensures that the DMS Document CMS Related and Versions fields are removed if user can't edit
*/
public function testDocumentHasNoCMSFieldsForManagingRelatedDocumentsIfCantEdit()
{
$this->logInWithPermission('another-user');
$document = $this->objFromFixture('DMSDocument', 'doc-only-these-users');
$gridField = $this->getRelatedDocumentsGridField($document);
$this->assertNull($gridField);
}
/**
* Ensure that the related documents list does not include the current document itself
*/
public function testGetRelatedDocumentsForAutocompleter()
{
$document = $this->objFromFixture('DMSDocument', 'd1');
$gridField = $this->getGridFieldFromDocument($document);
$gridField = $this->getRelatedDocumentsGridField($document);
$this->assertInstanceOf('GridField', $gridField);
$config = $gridField->getConfig();
@ -90,7 +104,7 @@ class DMSDocumentTest extends SapphireTest
/**
* @return GridField
*/
protected function getGridFieldFromDocument(DMSDocument $document)
protected function getRelatedDocumentsGridField(DMSDocument $document)
{
$documentFields = $document->getCMSFields();
/** @var FieldGroup $actions */
@ -103,7 +117,6 @@ class DMSDocumentTest extends SapphireTest
break;
}
}
$this->assertInstanceOf('GridField', $gridField);
return $gridField;
}
@ -121,6 +134,19 @@ class DMSDocumentTest extends SapphireTest
$this->assertContains('<li class="ss-ui-button dmsdocument-action" data-panel="', $result);
$this->assertContains('permission', $result);
$this->assertContains('Example', $result);
$actions = array('example', 'embargo','find-usage');
foreach ($actions as $action) {
// Test remove with string
$document->removeActionPanelTask($action);
}
$result = $document->getActionTaskHtml();
$this->assertNotContains('Example', $result);
$this->assertNotContains('embargo', $result);
$this->assertNotContains('find-usage', $result);
// Positive test to see some action still remains
$this->assertContains('find-references', $result);
}
/*
@ -142,11 +168,7 @@ class DMSDocumentTest extends SapphireTest
{
/** @var DMSDocument $document */
$document = $this->objFromFixture('DMSDocument', 'doc-logged-in-users');
// Make sure user is logged out
if ($member = Member::currentUser()) {
$member->logOut();
}
$this->logoutMember();
// Logged out user test
$this->assertFalse($document->canView());
@ -178,10 +200,7 @@ class DMSDocumentTest extends SapphireTest
*/
public function testCanEdit()
{
// Make sure user is logged out
if ($member = Member::currentUser()) {
$member->logOut();
}
$this->logoutMember();
/** @var DMSDocument $document1 */
$document1 = $this->objFromFixture('DMSDocument', 'doc-logged-in-users');
@ -204,6 +223,50 @@ class DMSDocumentTest extends SapphireTest
$this->assertTrue($document2->canEdit($cableGuy));
}
/**
* Tests delete permissions
*/
public function testCanDelete()
{
$this->logoutMember();
$document1 = $this->objFromFixture('DMSDocument', 'doc-logged-in-users');
// Logged out user test
$this->assertFalse($document1->canDelete());
// Test editors can delete
$contentAuthor = $this->objFromFixture('Member', 'editor');
$this->assertTrue($document1->canDelete($contentAuthor));
}
/**
* Tests create permission
*/
public function testCanCreate()
{
$this->logoutMember();
$document1 = $this->objFromFixture('DMSDocument', 'doc-logged-in-users');
$this->logInWithPermission('CMS_ACCESS_DMSDocumentAdmin');
// Test CMS access can create
$this->assertTrue($document1->canCreate());
$this->logoutMember();
// Test editors can create
$contentAuthor = $this->objFromFixture('Member', 'editor');
$this->assertTrue($document1->canCreate($contentAuthor));
}
/**
* Logs out any active member
*/
protected function logoutMember()
{
if ($member = Member::currentUser()) {
$member->logOut();
}
}
/**
* Test permission denied reasons for documents
*/

View File

@ -12,9 +12,9 @@ class DMSDocumentAdminTest extends FunctionalTest
}
/**
* Check that the default "add new" button is gone, and replaced with our customised version of it
* Check that the default "add new" and "edit" buttons are gone, and replaced with our customised version of it
*/
public function testGridFieldHasCustomisedAddNewButton()
public function testGridFieldHasCustomisedButtons()
{
$modelAdmin = new DMSDocumentAdmin;
$modelAdmin->init();
@ -22,23 +22,32 @@ class DMSDocumentAdminTest extends FunctionalTest
$form = $modelAdmin->getEditForm();
$gridFieldConfig = $form->Fields()->first()->getConfig();
// Our button is an instance of the original, so is returned when asking for the original
$addNewButtons = $gridFieldConfig->getComponentsByType('GridFieldAddNewButton');
foreach ($addNewButtons as $key => $addNewButton) {
if ($addNewButton instanceof DMSGridFieldAddNewButton) {
// Remove our version for testing's sake
$addNewButtons->remove($addNewButton);
}
}
$this->assertCount(0, $addNewButtons, 'Original add new button is removed');
$this->assertInstanceOf(
'DMSGridFieldAddNewButton',
$gridFieldConfig->getComponentByType('DMSGridFieldAddNewButton'),
'Model admin for documents contains customised DMS add new button'
$replacements = array(
'GridFieldAddNewButton'=>'DMSGridFieldAddNewButton',
'GridFieldEditButton'=>'DMSGridFieldEditButton'
);
foreach ($replacements as $oldClass => $newClass) {
// Our button is an instance of the original, so is returned when asking for the original
$newButtons = $gridFieldConfig->getComponentsByType($oldClass);
foreach ($newButtons as $key => $newButton) {
if ($newButton instanceof $newClass) {
// Remove our version for testing's sake
$newButtons->remove($newButton);
}
}
$this->assertCount(0, $newButtons, 'Original button is removed');
$this->assertInstanceOf(
$newClass,
$gridFieldConfig->getComponentByType($newClass),
"Model admin for documents contains customised {$newClass} button"
);
}
}
/**
* Quick check to ensure that the ModelAdmin endpoint is working
*/