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

Update ProcessPageList to have module configuration setting as to whether or not Trash and Restore is available to non-superusers. Plus add new Restore tab to ProcessPageEdit that appears when editing a page in the trash. Previously you could only restore by using the PageList "restore" action.

This commit is contained in:
Ryan Cramer
2018-06-29 12:27:01 -04:00
parent bf62fbb897
commit 30bc99cfd7
6 changed files with 140 additions and 85 deletions

View File

@@ -607,44 +607,36 @@ class PagePermissions extends WireData implements Module {
*/
public function trashListable($page = null) {
/** @var User $user */
static $showTrashUsers = array();
$user = $this->wire('user');
// trash and anything in it always visible to superuser
if($user->isSuperuser()) return true;
if(isset($showTrashUsers[$user->id])) {
$showTrash = $showTrashUsers[$user->id];
// determine if system has page-edit-trash-created permission installed
$petc = 'page-edit-trash-created';
if(!$this->wire('permissions')->has($petc)) $petc = false;
if($user->hasPermission('page-delete')) {
// has page-delete globally
} else if($petc && $user->hasPermission($petc)) {
// has page-edit-trash-created globally
} else if($user->hasPermission('page-delete', true)) {
// has page-delete added specifically at a template
} else if($petc && $user->hasPermission($petc, true)) {
// has page-edit-trash-created added specifically at a template
} else {
$petc = 'page-edit-trash-created';
if(!$this->wire('permissions')->has($petc)) $petc = false;
if($user->isSuperuser()) {
// superuser
$showTrash = true;
} else if($user->hasPermission('page-delete')) {
// has page-delete globally
$showTrash = true;
} else if($petc && $user->hasPermission($petc)) {
// has page-edit-trash-created globally
$showTrash = true;
} else if($user->hasPermission('page-delete', true)) {
// has page-delete added specifically at a template
$showTrash = true;
} else if($petc && $user->hasPermission($petc, true)) {
// has page-edit-trash-created added specifically at a template
$showTrash = true;
} else {
$showTrash = false;
}
$showTrashUsers[$user->id] = $showTrash;
// user does not have any of the permissions above, so trash is not listable
return false;
}
if(!$showTrash) return false;
if($page === null || !$page->id) return $showTrash;
$trashPageID = $this->wire('config')->trashPageID;
if($page->id == $trashPageID) return $showTrash;
// if request not asking about specific page, return general "trash is listable?" request
if($page === null || !$page->id) return true;
$listable = $this->pageEditable($page);
return $listable;
// if request is for the actual Trash page, consider this to be a general request
if($page->id == $this->wire('config')->trashPageID) return true;
// page is listable in the trash only if it is also editable
return $this->pageEditable($page);
}
/**
@@ -859,14 +851,24 @@ class PagePermissions extends WireData implements Module {
*/
public function moveable($event) {
/** @var Page $page */
$page = $event->object;
$moveable = $page->editable('parent');
if($moveable && count($event->arguments) && $event->arguments[0] instanceof Page) {
/** @var Page $parent */
$parent = $event->arguments[0];
$moveable = $parent->addable($page);
$page = $event->object;
/** @var Page|null $parent */
$parent = $event->arguments(0);
if(!$parent || !$parent instanceof Page || !$parent->id) $parent = null;
if($page->id == 1) {
$moveable = false;
} else {
$moveable = $page->editable('parent');
}
if($page->id == 1) $moveable = false;
if($moveable && $parent) {
$moveable = $parent->addable($page);
} else if($parent && $parent->isTrash() && $parent->id == $this->wire('config')->trashPageID) {
$moveable = $page->deletable();
}
$event->return = $moveable;
}

View File

@@ -893,7 +893,11 @@ class ProcessPageEdit extends Process implements WirePageEditor, ConfigurableMod
if($this->page->addable() || $this->page->numChildren) $form->append($this->buildFormChildren());
if(!$this->page->template->noSettings && $this->useSettings) $form->append($this->buildFormSettings());
if($this->isTrash) $this->message($this->_("This page is in the Trash"));
if($this->isTrash && !$this->isPost) {
$this->message($this->_("This page is in the Trash"));
$tabRestore = $this->buildFormRestore();
if($tabRestore) $form->append($tabRestore);
}
$tabDelete = $this->buildFormDelete();
if($tabDelete->children()->count()) $form->append($tabDelete);
if($this->page->viewable() && !$this->requestModal) $this->buildFormView($this->getViewUrl());
@@ -1427,6 +1431,47 @@ class ProcessPageEdit extends Process implements WirePageEditor, ConfigurableMod
return $wrapper;
}
/**
* Build the 'restore' tab shown for pages in the trash
*
* Returns boolean false if restore not possible.
*
* @return InputfieldWrapper|bool
*
*/
protected function buildFormRestore() {
if(!$this->page->isTrash()) return false;
/** @var InputfieldWrapper $wrapper */
$wrapper = $this->wire(new InputfieldWrapper());
$id = $this->className() . 'Restore';
$restoreLabel = $this->_('Restore'); // Tab Label: Restore
$restoreLabel2 = $this->_('Move out of trash and restore to original location');
$wrapper->attr('id', $id);
$wrapper->attr('title', $restoreLabel);
$this->addTab($id, $restoreLabel);
if(!preg_match('/^(\d+)\.(\d+)\.(\d+)_(.+)$/', $this->page->name, $matches)) return false;
$parentID = (int) $matches[2];
$parent = $parentID ? $this->wire('pages')->get($parentID) : null;
if(!$parent || !$parent->id) return false;
/** @var InputfieldCheckbox $field */
$field = $this->modules->get('InputfieldCheckbox');
$field->attr('id+name', 'restore_page');
$field->attr('value', $this->page->id);
$field->icon = 'trash-o';
$field->label = $restoreLabel2;
$field->description = $this->_('Check the box to confirm that you want to restore this page.'); // Restore page confirmation instruction
$field->notes = sprintf($this->_('The page will be restored into parent: **%s**'), $parent->get('path'));
$field->label2 = $restoreLabel;
$wrapper->append($field);
return $wrapper;
}
/**
* Build the 'view' tab on the Page Edit form
*
@@ -1632,6 +1677,16 @@ class ProcessPageEdit extends Process implements WirePageEditor, ConfigurableMod
$message .= ' - ' . $this->_('Cannot be published until errors are corrected');
}
}
if($this->input->post('restore_page') && $this->page->isTrash() && $this->page->restorable()) {
if($formErrors) {
$this->warning($this->_('Page cannot be restored while errors are present'));
} else if($this->wire('pages')->restore($this->page, false)) {
$message = sprintf($this->_('Restored Page: %s'), '{path}') . $numChanges;
} else {
$this->warning($this->_('Error restoring page'));
}
}
$this->wire('pages')->save($this->page, $options);
$message = str_replace('{path}', $this->page->path, $message);
@@ -1942,14 +1997,15 @@ class ProcessPageEdit extends Process implements WirePageEditor, ConfigurableMod
$afterDeleteRedirect = $this->config->urls->admin . "page/?open={$this->parent->id}";
if($this->wire('page')->process != $this->className()) $afterDeleteRedirect = "../";
$pagePath = $this->page->path();
if(($this->isTrash || $this->page->template->noTrash) && $this->page->deleteable()) {
$this->session->message(sprintf($this->_('Deleted page: %s'), $this->page->url)); // Page deleted message
$this->session->message(sprintf($this->_('Deleted page: %s'), $pagePath)); // Page deleted message
$this->pages->delete($this->page, true);
$this->session->redirect($afterDeleteRedirect);
} else if($this->pages->trash($this->page)) {
$this->session->message(sprintf($this->_('Moved page to trash: %s'), $this->page->url)); // Page moved to trash message
$this->session->message(sprintf($this->_('Moved page to trash: %s'), $pagePath)); // Page moved to trash message
$this->session->redirect($afterDeleteRedirect);
} else {

View File

@@ -19,6 +19,7 @@
* @property int $hoverActionDelay Milliseconds delay between hover and showing of actions.
* @property int $hoverActionFade Milliseconds to spend fading in or out actions.
* @property bool|int $useBookmarks Allow use of PageList bookmarks?
* @property bool|int $useTrash Allow non-superusers to use Trash?
*
* @method string ajaxAction($action)
* @method PageArray find($selectorString, Page $page)
@@ -37,7 +38,7 @@ class ProcessPageList extends Process implements ConfigurableModule {
return array(
'title' => 'Page List',
'summary' => 'List pages in a hierarchal tree structure',
'version' => 120,
'version' => 121,
'permanent' => true,
'permission' => 'page-edit',
'icon' => 'sitemap',
@@ -113,6 +114,7 @@ class ProcessPageList extends Process implements ConfigurableModule {
$this->set('limit', self::defaultLimit);
$this->set('useHoverActions', false);
$this->set('useBookmarks', false);
$this->set('useTrash', false);
$this->set('bookmarks', array());
parent::__construct();
@@ -349,6 +351,7 @@ class ProcessPageList extends Process implements ConfigurableModule {
$renderer->setLimit($limit);
$renderer->setPageLabelField($this->getPageLabelField());
$renderer->setLabel('trash', $this->trashLabel);
$renderer->setUseTrash($this->useTrash || $this->wire('user')->isSuperuser());
return $renderer;
}
@@ -634,6 +637,17 @@ class ProcessPageList extends Process implements ConfigurableModule {
$fields = $this->wire(new InputfieldWrapper());
/** @var Modules $modules */
$modules = $this->wire('modules');
/** @var InputfieldCheckbox $field */
$field = $modules->get('InputfieldCheckbox');
$field->attr('name', 'useTrash');
$field->label = $this->_('Allow non-superuser editors to use Trash?');
$field->icon = 'trash-o';
$field->description =
$this->_('When checked, users will be able to see pages in the trash (only pages they have access to).') . ' ' .
$this->_('This will also enable the “Trash” and “Restore” actions, where access control allows.');
if(!empty($data['useTrash'])) $field->attr('checked', 'checked');
$fields->append($field);
/** @var InputfieldText $field */
$field = $modules->get("InputfieldText");

View File

@@ -1,8 +1,15 @@
<?php namespace ProcessWire;
/**
* ProcessPageListActions
*
* @method array getExtraActions(Page $page)
*
*/
class ProcessPageListActions extends Wire {
protected $superuser = false;
protected $useTrash = false;
protected $actionLabels = array(
'edit' => 'Edit',
@@ -33,6 +40,10 @@ class ProcessPageListActions extends Wire {
$this->actionLabels = array_merge($this->actionLabels, $actionLabels);
}
public function setUseTrash($useTrash) {
$this->useTrash = (bool) $useTrash;
}
/**
* Get an array of available Page actions, indexed by $label => $url
*
@@ -167,7 +178,7 @@ class ProcessPageListActions extends Wire {
}
}
$trashable = $page->trashable();
$trashable = $this->useTrash && $page->trashable();
$trashIcon = "<i class='fa fa-trash-o'></i>&nbsp;";
if($trashable && !$user->isSuperuser()) {
// do not allow non-superuser ability to trash branches of pages, only individual pages

View File

@@ -19,6 +19,7 @@ abstract class ProcessPageListRender extends Wire {
protected $superuser = false;
protected $actions = null;
protected $options = array();
protected $useTrash = false;
public function __construct(Page $page, PageArray $children) {
$this->page = $page;
@@ -66,6 +67,11 @@ abstract class ProcessPageListRender extends Wire {
public function setLabel($key, $value) {
$this->actionLabels[$key] = $value;
}
public function setUseTrash($useTrash) {
$this->useTrash = (bool) $useTrash;
$this->actions->setUseTrash($this->getUseTrash());
}
public function setPageLabelField($pageLabelField) {
$this->pageLabelField = $pageLabelField;
@@ -201,6 +207,10 @@ abstract class ProcessPageListRender extends Wire {
public function getChildren() {
return $this->children;
}
public function getUseTrash() {
return $this->useTrash;
}
}

View File

@@ -10,8 +10,6 @@ class ProcessPageListRenderJSON extends ProcessPageListRender {
protected $systemIDs = array();
protected $allowTrash = null;
public function __construct(Page $page, PageArray $children) {
parent::__construct($page, $children);
@@ -24,44 +22,6 @@ class ProcessPageListRenderJSON extends ProcessPageListRender {
);
}
/**
* Are we allowed to display the Trash page?
*
* @return bool
*
*/
protected function allowTrash() {
if($this->allowTrash !== null) return $this->allowTrash;
/** @var User $user */
$user = $this->wire('user');
$petc = 'page-edit-trash-created';
if(!$this->wire('permissions')->has($petc)) $petc = false;
if($user->isSuperuser()) {
// superuser
$this->allowTrash = true;
} else if($user->hasPermission('page-delete')) {
// has page-delete globally
$this->allowTrash = true;
} else if($petc && $user->hasPermission($petc)) {
// has page-edit-trash-created globally
$this->allowTrash = true;
} else if($user->hasPermission('page-delete', true)) {
// has page-delete added specifically at a template
$this->allowTrash = true;
} else if($petc && $user->hasPermission($petc, true)) {
// has page-edit-trash-created added specifically at a template
$this->allowTrash = true;
} else {
$this->allowTrash = false;
}
return $this->allowTrash;
}
public function renderChild(Page $page) {
$outputFormatting = $page->outputFormatting;
@@ -173,7 +133,9 @@ class ProcessPageListRenderJSON extends ProcessPageListRender {
if(!$this->superuser && $page404 && $page404->parent_id == 1 && !isset($extraPages[$idTrash])) {
$pageTrash = $this->wire('pages')->get($idTrash);
if($pageTrash->id && $pageTrash->listable()) $extraPages[$pageTrash->id] = $pageTrash;
if($pageTrash->id && $this->getUseTrash() && $pageTrash->listable()) {
$extraPages[$pageTrash->id] = $pageTrash;
}
}
foreach($extraPages as $page) {