1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-11 09:14:58 +02:00

Fix issue processwire/processwire-issues#1561 - non-superuser when uploading image in repeater was producing a "no access" error

This commit is contained in:
Ryan Cramer
2022-04-29 11:27:32 -04:00
parent e0b43606b3
commit 01223be0dc

View File

@@ -33,7 +33,7 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
return array(
'title' => __('Repeater', __FILE__), // Module Title
'summary' => __('Maintains a collection of fields that are repeated for any number of times.', __FILE__), // Module Summary
'version' => 111,
'version' => 112,
'autoload' => true,
'installs' => 'InputfieldRepeater'
);
@@ -54,7 +54,7 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
const loadingOff = 2;
/**
* Field names used by repeaters in format [ PW_instanceNum => [ 'field_name', 'field_name2' ] ];
* Field names used by repeaters in format [ PW_instanceID => [ 'field_name', 'field_name2' ] ];
*
* @var array
*
@@ -62,7 +62,7 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
static protected $fieldsUsedInRepeaters = array();
/**
* Template IDs used by repeaters in format [ PW_instanceNum => [ 123, 456, 789 ] ]
* Template IDs used by repeaters in format [ PW_instanceID => [ 123, 456, 789 ] ]
*
* @var array
*
@@ -70,12 +70,28 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
static protected $templatesUsedByRepeaters = array();
/**
* Has ready method been called? [ PW_instanceNum => true | false ]
* Has ready method been called? [ PW_instanceID => true | false ]
*
* @var bool
*
*/
static protected $isReady = array();
/**
* Fields that are initialized [ PW_instanceID => [ 'field_id' => true ] ]
*
* @var bool
*
*/
static protected $initFields = array();
/**
* ProcessWire instance ID
*
* @var int
*
*/
protected $instanceID = 0;
/**
* When non-zero, a deletePageField function call occurred and we shouldn't re-create any repeater parents
@@ -117,6 +133,8 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
require_once(dirname(__FILE__) . '/RepeaterPageArray.php');
$this->set('repeatersRootPageID', 0);
parent::__construct();
}
/**
@@ -124,6 +142,8 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
*
*/
public function init() {
$this->instanceID = $this->wire()->getProcessWireInstanceID();
self::$initFields[$this->instanceID] = array();
$this->wire()->pages->addHookAfter('deleteReady', $this, 'hookPagesDelete');
$this->useLazy = $this->wire()->config->useLazyLoading;
parent::init();
@@ -136,34 +156,21 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
public function ready() {
parent::ready();
$instanceNum = $this->wire()->getInstanceNum();
if(!empty(self::$isReady[$instanceNum])) return; // ensures everything below only runs only once (for extending types)
self::$isReady[$instanceNum] = true;
if(!$this->useLazy) {
// make sure that all templates used by repeater pages enforce a Page type of RepeaterPage
// this was necessary when lazy loading option was disabled
$this->useLazy = true;
$repeaterFields = $this->wire()->fields->findByType('FieldtypeRepeater', array(
'inherit' => true,
'valueType' => 'field',
'indexType' => '',
));
foreach($repeaterFields as $field) {
$this->initField($field);
}
$this->useLazy = false;
}
if(!empty(self::$isReady[$this->instanceID])) return; // ensures everything below only runs only once (for extending types)
self::$isReady[$this->instanceID] = true;
$page = $this->wire()->page;
$process = $page->process; /** @var Process|null $process */
$user = $this->wire()->user;
$config = $this->wire()->config;
$input = $this->wire()->input;
$inEditor = $process == 'ProcessPageEdit' || $process == 'ProcessProfile';
$isSuperuser = $user->isSuperuser();
// make sure that all templates used by repeater pages enforce a Page type of RepeaterPage
// this was necessary when lazy loading option was disabled
if(!$this->useLazy) $this->initAllFields();
if($inEditor) {
// ProcessPageEdit or ProcessProfile
$this->addHookBefore('ProcessPageEdit::ajaxSave', $this, 'hookProcessPageEditAjaxSave');
@@ -174,12 +181,18 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
$fieldName = (string) $input->get('field');
$pageID = (int) $input->get('id');
if($pageID && strpos($fieldName, '_repeater') && preg_match('/^(.+)_repeater\d+$/', $fieldName, $matches)) {
$this->initAllFields();
$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]);
$input->get->__set('field', $this->wire()->sanitizer->fieldName($matches[1]));
}
}
// handle scenario of file upload or other ajax saved field
if(isset($_SERVER['HTTP_X_FIELDNAME'])) {
// initialize all repeater fields so RepeaterPage class names are active for access control
if(strpos($_SERVER['HTTP_X_FIELDNAME'], '_repeater')) $this->initAllFields();
}
}
if(!$inEditor && !$user->isGuest() && !$isSuperuser && $user->hasPermission('page-edit')) {
@@ -207,8 +220,10 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
*
*/
public function initField(Field $field) {
if(!$this->useLazy) return;
if(!empty(self::$initFields[$this->instanceID][$field->id])) return;
parent::initField($field);
if(!$this->useLazy) return;
self::$initFields[$this->instanceID][$field->id] = true;
/** @var FieldtypeRepeater $fieldtype */
$fieldtype = $field->type;
if(!$fieldtype instanceof FieldtypeRepeater) return;
@@ -222,6 +237,29 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
$template->save();
}
/**
* Force initialize of all repeater fields, confirming their configuration settings are correct
*
* @since 3.0.199
*
*/
public function initAllFields() {
if(!empty(self::$initFields['*'])) return;
self::$initFields['*'] = true;
$repeaterFields = $this->wire()->fields->findByType('FieldtypeRepeater', array(
'inherit' => true,
'valueType' => 'field',
'indexType' => '',
));
$useLazy = $this->useLazy;
$this->useLazy = true;
foreach($repeaterFields as $field) {
$this->initField($field);
}
$this->useLazy = $useLazy;
}
/**
* Get class name to use Field objects of this type (must be class that extends Field class)
*
@@ -342,10 +380,9 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
/** @var PageFinder $pageFinder */
$pageFinder = $event->object;
$pageFinderOptions = $pageFinder->getOptions();
$instanceNum = $this->wire()->getInstanceNum();
// determine which fields are used in repeaters
if(!isset(self::$fieldsUsedInRepeaters[$instanceNum])) {
if(!isset(self::$fieldsUsedInRepeaters[$this->instanceID])) {
$fieldNames = array('title' => 'title'); // title used by admin template (repeater parents)
$templates = $this->wire()->templates;
$templateIds = array();
@@ -358,12 +395,12 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
$fieldNames[$fieldName] = $fieldName;
}
}
self::$fieldsUsedInRepeaters[$instanceNum] = array_values($fieldNames);
self::$templatesUsedByRepeaters[$instanceNum] = array_values($templateIds);
self::$fieldsUsedInRepeaters[$this->instanceID] = array_values($fieldNames);
self::$templatesUsedByRepeaters[$this->instanceID] = array_values($templateIds);
}
$fieldsUsedInRepeaters = self::$fieldsUsedInRepeaters[$instanceNum];
$templatesUsedByRepeaters = self::$templatesUsedByRepeaters[$instanceNum];
$fieldsUsedInRepeaters = self::$fieldsUsedInRepeaters[$this->instanceID];
$templatesUsedByRepeaters = self::$templatesUsedByRepeaters[$this->instanceID];
// did we find a field used by a repeater in the selector?
$found = false;
@@ -2228,6 +2265,7 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
*/
protected function ___saveConfigInputfields(Field $field, Template $template, Page $parent) {
if($parent) {} // ignore
$this->initAllFields();
$helper = $this->getRepeaterConfigHelper($field);
$helper->saveConfigInputfields($template);
}