From b7271bc4246f1c578b746b7c66c76f1b6688593a Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Fri, 19 Feb 2021 22:04:04 +0200 Subject: [PATCH] Regression: Fixed enabling/disabling plugin or theme corrupting configuration --- CHANGELOG.md | 2 + classes/plugin/Admin.php | 128 +++++++++++++++++++++++++++-- classes/plugin/AdminController.php | 15 +++- 3 files changed, 134 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4567e8f6..ffb7630e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ 1. [](#improved) * Flex pages admin better uses available space [#2075](https://github.com/getgrav/grav/issues/2075) +1. [](#bugfix) + * Regression: Fixed enabling/disabling plugin or theme corrupting configuration # v1.10.5 ## 02/18/2021 diff --git a/classes/plugin/Admin.php b/classes/plugin/Admin.php index 6a448c9d..02bbacae 100644 --- a/classes/plugin/Admin.php +++ b/classes/plugin/Admin.php @@ -269,7 +269,7 @@ class Admin $name = $file->getBasename('.yaml'); // Check that blueprint exists and is not hidden. - $data = $admin->data('config/'. $name, null); + $data = $admin->getConfigurationData('config/'. $name); if (!is_callable([$data, 'blueprints'])) { continue; } @@ -838,12 +838,12 @@ class Admin * Gets configuration data. * * @param string $type - * @param array|null $post + * @param array $post * - * @return object + * @return mixed * @throws \RuntimeException */ - public function data($type, ?array $post = []) + public function data($type, array $post = []) { static $data = []; @@ -851,11 +851,123 @@ class Admin return $data[$type]; } - if (null !== $post && !$post) { - $post = $this->grav['uri']->post()['data'] ?? null; - if (!is_array($post)) { - $post = []; + if (!$post) { + $post = $this->grav['uri']->post(); + $post = $post['data'] ?? []; + } + + // Check to see if a data type is plugin-provided, before looking into core ones + $event = $this->grav->fireEvent('onAdminData', new Event(['type' => &$type])); + if ($event) { + if (isset($event['data_type'])) { + return $event['data_type']; } + + if (is_string($event['type'])) { + $type = $event['type']; + } + } + + /** @var UniformResourceLocator $locator */ + $locator = $this->grav['locator']; + $filename = $locator->findResource("config://{$type}.yaml", true, true); + $file = CompiledYamlFile::instance($filename); + + if (preg_match('|plugins/|', $type)) { + /** @var Plugins $plugins */ + $plugins = $this->grav['plugins']; + $obj = $plugins->get(preg_replace('|plugins/|', '', $type)); + + if (!$obj) { + return []; + } + + $obj->merge($post); + $obj->file($file); + + $data[$type] = $obj; + } elseif (preg_match('|themes/|', $type)) { + /** @var Themes $themes */ + $themes = $this->grav['themes']; + $obj = $themes->get(preg_replace('|themes/|', '', $type)); + + if (!$obj) { + return []; + } + + $obj->merge($post); + $obj->file($file); + + $data[$type] = $obj; + } elseif (preg_match('|users?/|', $type)) { + /** @var UserCollectionInterface $users */ + $users = $this->grav['accounts']; + + $obj = $users->load(preg_replace('|users?/|', '', $type)); + $obj->update($this->cleanUserPost($post)); + + $data[$type] = $obj; + } elseif (preg_match('|config/|', $type)) { + $type = preg_replace('|config/|', '', $type); + $blueprints = $this->blueprints("config/{$type}"); + $config = $this->grav['config']; + $obj = new Data\Data($config->get($type, []), $blueprints); + $obj->merge($post); + + // FIXME: We shouldn't allow user to change configuration files in system folder! + $filename = $this->grav['locator']->findResource("config://{$type}.yaml") + ?: $this->grav['locator']->findResource("config://{$type}.yaml", true, true); + $file = CompiledYamlFile::instance($filename); + $obj->file($file); + $data[$type] = $obj; + } elseif (preg_match('|media-manager/|', $type)) { + $filename = base64_decode(preg_replace('|media-manager/|', '', $type)); + + $file = File::instance($filename); + + $pages = static::enablePages(); + + $obj = new \stdClass(); + $obj->title = $file->basename(); + $obj->path = $file->filename(); + $obj->file = $file; + $obj->page = $pages->get(dirname($obj->path)); + + $fileInfo = pathinfo($obj->title); + $filename = str_replace(['@3x', '@2x'], '', $fileInfo['filename']); + if (isset($fileInfo['extension'])) { + $filename .= '.' . $fileInfo['extension']; + } + + if ($obj->page && isset($obj->page->media()[$filename])) { + $obj->metadata = new Data\Data($obj->page->media()[$filename]->metadata()); + } + + $data[$type] = $obj; + } else { + throw new \RuntimeException("Data type '{$type}' doesn't exist!"); + } + + return $data[$type]; + } + + /** + * Get configuration data. + * + * Note: If you pass $post, make sure you pass all the fields in the blueprint or data gets lost! + * + * @param string $type + * @param array|null $post + * + * @return object + * @throws \RuntimeException + */ + public function getConfigurationData($type, array $post = null) + { + static $data = []; + + if (isset($data[$type])) { + return $data[$type]; } // Check to see if a data type is plugin-provided, before looking into core ones diff --git a/classes/plugin/AdminController.php b/classes/plugin/AdminController.php index a2b74ee3..a502beb3 100644 --- a/classes/plugin/AdminController.php +++ b/classes/plugin/AdminController.php @@ -158,7 +158,8 @@ class AdminController extends AdminBaseController protected function taskSaveDefault() { // Handle standard data types. - $obj = $this->prepareData((array)$this->data); + $type = $this->getDataType(); + $obj = $this->admin->getConfigurationData($type, $this->data); try { $obj->validate(); @@ -807,7 +808,7 @@ class AdminController extends AdminBaseController $this->grav['themes']->get($name); // Store system configuration. - $system = $this->admin->data('config/system'); + $system = $this->admin->getConfigurationData('config/system'); $system->set('pages.theme', $name); $system->save(); @@ -2686,6 +2687,14 @@ class AdminController extends AdminBaseController return $settings + ['accept' => '*', 'limit' => 1000]; } + /** + * @return string + */ + protected function getDataType() + { + return trim("{$this->view}/{$this->admin->route}", '/'); + } + /** * Gets the configuration data for a given view & post * @@ -2694,7 +2703,7 @@ class AdminController extends AdminBaseController */ protected function prepareData(array $data) { - $type = trim("{$this->view}/{$this->admin->route}", '/'); + $type = $this->getDataType(); return $this->admin->data($type, $data); }