From 8952afbddbc9ed4f85eb8baa3b0b46acdaa4fa6f Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Fri, 1 Mar 2019 11:36:52 -0500 Subject: [PATCH] Fix issue processwire/processwire-issues#183 allow for front-end editing of fields in repeater items, individually per-field by non-superusers with edit access to the page the owns the repeater field. --- .../FieldtypeRepeater.module | 57 +++++++++++++------ .../Page/PageFrontEdit/PageFrontEdit.module | 16 +++++- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/wire/modules/Fieldtype/FieldtypeRepeater/FieldtypeRepeater.module b/wire/modules/Fieldtype/FieldtypeRepeater/FieldtypeRepeater.module index 1b167c11..be2d7e65 100644 --- a/wire/modules/Fieldtype/FieldtypeRepeater/FieldtypeRepeater.module +++ b/wire/modules/Fieldtype/FieldtypeRepeater/FieldtypeRepeater.module @@ -119,29 +119,54 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule { $template->set('pageClass', $class); $template->save(); } + + /** @var Page $page */ + $page = $this->wire('page'); - $process = $this->wire('page')->process; + /** @var Process|null $process */ + $process = $page->process; + + /** @var User $user */ + $user = $this->wire('user'); - if($process == 'ProcessPageEdit' || $process == 'ProcessProfile') { - + /** @var Config $config */ + $config = $this->wire('config'); + + /** @var WireInput $input */ + $input = $this->wire('input'); + + $inEditor = $process == 'ProcessPageEdit' || $process == 'ProcessProfile'; + $isSuperuser = $user->isSuperuser(); + + if($inEditor) { + // ProcessPageEdit or ProcessProfile $this->addHookBefore('ProcessPageEdit::ajaxSave', $this, 'hookProcessPageEditAjaxSave'); - - if($this->wire('config')->ajax) { - // handle scenario of repeater within repeater field - $fieldName = $this->wire('input')->get('field'); - $pageID = (int) $this->wire('input')->get('id'); - if($pageID && strpos($fieldName, '_repeater') && preg_match('/^(.+)_repeater\d+$/', $fieldName, $matches)) { - $editPage = $this->wire('pages')->get($pageID); - if($editPage->id && strpos($editPage->template->name, self::templateNamePrefix) === 0) { - // update field name to exclude the _repeater1234 part at the end, so that PageEdit recognizes it - $this->wire('input')->get->field = $matches[1]; - } + } + + if($inEditor && $config->ajax) { + // handle scenario of repeater within repeater field + $fieldName = $input->get('field'); + $pageID = (int) $input->get('id'); + if($pageID && strpos($fieldName, '_repeater') && preg_match('/^(.+)_repeater\d+$/', $fieldName, $matches)) { + $editPage = $this->wire('pages')->get($pageID); + if($editPage->id && strpos($editPage->template->name, self::templateNamePrefix) === 0) { + // update field name to exclude the _repeater1234 part at the end, so that PageEdit recognizes it + $input->get->__set('field', $matches[1]); } } - if(!$this->wire('user')->isSuperuser()) { - $this->addHookAfter('PagePermissions::pageEditable', $this, 'hookPagePermissionsPageEditableAjax'); + } + + if(!$inEditor && !$user->isGuest() && !$isSuperuser && $user->hasPermission('page-edit')) { + // allow for front-end editor to also trigger an inEditor=true condition + if(strpos($page->url, $config->urls->admin) === false && $page->editable()) { + if($this->wire('modules')->isInstalled('PageFrontEdit')) $inEditor = true; } } + + if($inEditor && !$isSuperuser) { + // need an extra hook to handle permissions + $this->addHookAfter('PagePermissions::pageEditable', $this, 'hookPagePermissionsPageEditableAjax'); + } $this->addHookBefore('PageFinder::getQuery', $this, 'hookPageFinderGetQuery'); diff --git a/wire/modules/Page/PageFrontEdit/PageFrontEdit.module b/wire/modules/Page/PageFrontEdit/PageFrontEdit.module index 8c778b7d..56638cd7 100644 --- a/wire/modules/Page/PageFrontEdit/PageFrontEdit.module +++ b/wire/modules/Page/PageFrontEdit/PageFrontEdit.module @@ -223,7 +223,17 @@ class PageFrontEdit extends WireData implements Module { if(!$this->editorAllowed) return false; if(!$this->inlineSupported($field)) return false; // if(!in_array($field->id, $this->inlineEditFields) && $field->id != $this->inlineEditField) return false; - if(!$this->wire('user')->hasPermission('page-edit-front', $page)) return false; + /** @var User $user */ + $user = $this->wire('user'); + if($page->className() != 'Page' && wireInstanceOf($page, 'RepeaterPage')) { + /** @var RepeaterPage $page */ + $forPage = $page->getForPage(); + $forField = $page->getForField(); + if(!$user->hasPermission('page-edit-front', $forPage)) return false; + if(!$forPage->editable($forField)) return false; + } else { + if(!$user->hasPermission('page-edit-front', $page)) return false; + } if(!$page->editable($field)) return false; return true; } @@ -964,7 +974,9 @@ class PageFrontEdit extends WireData implements Module { } else { // okay to make edits try { - $this->wire('session')->CSRF->validate(); + /** @var Session $session */ + $session = $this->wire('session'); + $session->CSRF->validate(); $data = $this->inlineProcessSaveEdits($fields, $data); } catch(WireCSRFException $e) { $data['error'] = "Failed CSRF check";