Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH Add permission methods based on owner #134

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/Models/Link.php
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,67 @@ public function Owner(): ?DataObject
return $owner;
}

public function canView($member = null)
{
return $this->canPerformAction(__FUNCTION__, $member);
}

public function canEdit($member = null)
{
return $this->canPerformAction(__FUNCTION__, $member);
}

public function canDelete($member = null)
{
return $this->canPerformAction(__FUNCTION__, $member);
}

public function canCreate($member = null, $context = [])
{
// Allow extensions to override permission checks
$results = $this->extendedCan(__FUNCTION__, $member, $context);
if (isset($results)) {
return $results;
}

// Assume anyone can create a link by default - there's no way to determine
// what the "owner" record is going to be ahead of time, but if the user
// can't edit the owner then the linkfield will be read-only anyway, so we
// can rely on that to determine who can create links.
return true;
}

public function can($perm, $member = null, $context = [])
{
$check = ucfirst(strtolower($perm));
return match ($check) {
'View', 'Create', 'Edit', 'Delete' => $this->{"can$check"}($member, $context),
default => parent::can($perm, $member, $context)
};
}

private function canPerformAction(string $canMethod, $member, $context = [])
{
// Allow extensions to override permission checks
$results = $this->extendedCan($canMethod, $member, $context);
if (isset($results)) {
return $results;
}

// If we have an owner, rely on it to tell us what we can and can't do
$owner = $this->Owner();
if ($owner && $owner->exists()) {
// Can delete or create links if you can edit its owner.
if ($canMethod === 'canCreate' || $canMethod === 'canDelete') {
$canMethod = 'canEdit';
}
return $owner->$canMethod($member, $context);
}

// Default to DataObject's permission checks
return parent::$canMethod($member, $context);
}

/**
* Get all link types except the generic one
*
Expand Down
46 changes: 46 additions & 0 deletions tests/php/Models/LinkTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -515,4 +515,50 @@ public function testOwnerHasOne()
$link->flushCache(false);
$this->assertSame($owner->ID, $link->Owner()?->ID);
}

/**
* @dataProvider provideCanPermissions
*/
public function testCanPermissions(string $linkPermission, string $ownerPermission)
{
$link = $this->objFromFixture(SiteTreeLink::class, 'page-link-page-only');
$owner = $link->Owner();
$permissionName = substr($linkPermission, 3);

$this->assertTrue($owner?->exists());

$owner->$ownerPermission = true;
$this->assertTrue($link->$linkPermission());
$this->assertTrue($link->can($permissionName));

$owner->$ownerPermission = false;
$this->assertFalse($link->$linkPermission());
$this->assertFalse($link->can($permissionName));
}

public function provideCanPermissions()
{
return [
'canView' => [
'linkPermission' => 'canView',
'ownerPermission' => 'canView',
],
'canEdit' => [
'linkPermission' => 'canEdit',
'ownerPermission' => 'canEdit',
],
'canDelete' => [
'linkPermission' => 'canDelete',
'ownerPermission' => 'canEdit',
],
];
}

public function testCanCreate()
{
$link = $this->objFromFixture(SiteTreeLink::class, 'page-link-page-only');
$this->logOut();
$this->assertTrue($link->canCreate());
$this->assertTrue($link->can('Create'));
}
}
14 changes: 14 additions & 0 deletions tests/php/Models/LinkTest/LinkOwner.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,18 @@ class LinkOwner extends DataObject implements TestOnly
private static array $has_many = [
'LinkList' => Link::class . '.Owner',
];

// Allows us to toggle permissions easily within a unit test
public bool $canView = true;
public bool $canEdit = true;

public function canView($member = null)
{
return $this->canView;
}

public function canEdit($member = null)
{
return $this->canEdit;
}
}