1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-07 07:16:51 +02:00

Add a new $page->cloneable() method that returns true if the user is allowed to clone the page. Or use $page->cloneable(true) if the user is allowed to clone the page and its children together. This moves the logic was was previously in the ProcessPageClone module into a method that can be more widely used where needed. Also updated the ProcessPageClone module to use it.

This commit is contained in:
Ryan Cramer
2024-05-10 11:52:41 -04:00
parent 4e2ef8f8fd
commit d77b23adbb
4 changed files with 72 additions and 22 deletions

View File

@@ -8,7 +8,7 @@
* 1. Providing get/set access to the Page's properties
* 2. Accessing the related hierarchy of pages (i.e. parents, children, sibling pages)
*
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
* #pw-summary Class used by all Page objects in ProcessWire.
@@ -120,6 +120,7 @@
* @method bool addable($pageToAdd = null) Returns true if the current user can add children to the page, false if not. Optionally specify the page to be added for additional access checking. #pw-group-access
* @method bool moveable($newParent = null) Returns true if the current user can move this page. Optionally specify the new parent to check if the page is moveable to that parent. #pw-group-access
* @method bool sortable() Returns true if the current user can change the sort order of the current page (within the same parent). #pw-group-access
* @method bool cloneable($recursive = null) Can current user clone this page? Specify false for $recursive argument to ignore whether children are cloneable. @since 3.0.239 #pw-group-access
* @property bool $viewable #pw-group-access
* @property bool $editable #pw-group-access
* @property bool $publishable #pw-group-access
@@ -130,6 +131,7 @@
* @property bool $moveable #pw-group-access
* @property bool $sortable #pw-group-access
* @property bool $listable #pw-group-access
* @property bool $cloneable @since 3.0.239 #pw-group-access
*
* Methods added by PagePathHistory.module (installed by default)
* --------------------------------------------------------------

View File

@@ -9,7 +9,7 @@
* Except where indicated, please treat these properties as private to the
* Page class.
*
* ProcessWire 3.x, Copyright 2021 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
*/
@@ -75,6 +75,7 @@ abstract class PageProperties {
'addable' => 'm',
'child' => 'm',
'children' => 'm',
'cloneable' => 'm',
'created' => 's',
'createdStr' => '',
'createdUser' => '',

View File

@@ -116,7 +116,8 @@ class PagePermissions extends WireData implements Module {
$this->addHook('Page::restorable', $this, 'restorable');
$this->addHook('Page::addable', $this, 'addable');
$this->addHook('Page::moveable', $this, 'moveable');
$this->addHook('Page::sortable', $this, 'sortable');
$this->addHook('Page::sortable', $this, 'sortable');
$this->addHook('Page::cloneable', $this, 'cloneable');
// $this->addHook('Page::fieldViewable', $this, 'hookFieldViewable');
// $this->addHook('Page::fieldEditable', $this, 'hookFieldEditable');
// $this->addHook('Template::createable', $this, 'createable');
@@ -1107,6 +1108,69 @@ class PagePermissions extends WireData implements Module {
// if we made it here, then page is not publishable
$event->return = false;
}
/**
* Is page cloneable by current user?
*
* Note: If a page has children and current user is not superuser, this method will return
* true only if the user has the `page-clone-tree` permission (from ProcessPageClone module).
*
* ~~~~~
* if($page->cloneable()) {
* // page is cloneable
* }
* if($page->cloneable(false)) {
* // page is cloneable, ignoring if recursive clone of children is allowed
* }
* ~~~~~
*
* @param HookEvent $event
*
*/
public function cloneable($event) {
$page = $event->object; /** @var Page $page */
$recursive = $event->arguments(0); /** @var bool|null $recursive */
$user = $this->wire()->user;
$permissions = $this->wire()->permissions;
$parent = $page->parent();
$parentTemplate = $parent->template;
$pageTemplate = $page->template;
$event->return = false;
if(!$parentTemplate) return;
if($page->hasStatus(Page::statusSystem) || $page->hasStatus(Page::statusSystemID)) return;
if($parentTemplate->noChildren) return;
if($pageTemplate->noParents) return;
if(count($parentTemplate->childTemplates) && !in_array($pageTemplate->id, $parentTemplate->childTemplates)) return;
if(count($pageTemplate->parentTemplates) && !in_array($parentTemplate->id, $pageTemplate->parentTemplates)) return;
if($user->isSuperuser()) {
$event->return = true;
return;
}
if(!$user->hasPermission('page-create', $page)) return;
if(!$parent->addable()) return;
if($permissions->has('page-clone')) {
if(!$user->hasPermission('page-clone', $page)) return;
}
if($recursive === false || !$page->numChildren) {
// call indicates they do not intend to clone children
// or there are no children, so no additional checks necessary
} else {
// check that they have page-clone-tree permission IF the page has children
// recursive cloning is only allowed via ProcessPageClone module
if(!$user->hasPermission('page-clone-tree', $page)) return;
}
$event->return = true;
}
/**
* Returns true if given user has the optional language permission, or false if not

View File

@@ -150,24 +150,7 @@ class ProcessPageClone extends Process implements ConfigurableModule {
*
*/
public function hasPermission(Page $page) {
$user = $this->wire()->user;
$parent = $page->parent();
$parentTemplate = $parent->template;
$pageTemplate = $page->template;
if(!$parentTemplate) return false;
if($page->hasStatus(Page::statusSystem) || $page->hasStatus(Page::statusSystemID)) return false;
if($parentTemplate->noChildren) return false;
if($pageTemplate->noParents) return false;
if(count($parentTemplate->childTemplates) && !in_array($pageTemplate->id, $parentTemplate->childTemplates)) return false;
if(count($pageTemplate->parentTemplates) && !in_array($parentTemplate->id, $pageTemplate->parentTemplates)) return false;
if($user->isSuperuser()) return true;
if($user->hasPermission('page-create', $page) && $user->hasPermission('page-clone', $page) && $parent->addable()) return true;
return false;
return $page->cloneable(false);
}
/**
@@ -378,7 +361,7 @@ class ProcessPageClone extends Process implements ConfigurableModule {
$titleField = $form->get('clone_page_title');
$nameField = $form->get('clone_page_name');
$cloneTree = $input->post('clone_page_tree') && $this->wire()->user->hasPermission('page-clone-tree', $this->page);
$cloneTree = $input->post('clone_page_tree') && $this->page->cloneable(true);
if($input->post('clone_page_unpublished')) {
$page->addStatus(Page::statusUnpublished);