From 047ae7b033ed190255dfaab3094c3e0fe452e818 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Fri, 12 Mar 2021 12:45:41 +0200 Subject: [PATCH 01/11] Fixed `Uncaught ValueError: Path cannot be empty` when failing to upload a file [#3265] --- CHANGELOG.md | 1 + composer.json | 2 +- composer.lock | 126 ++++++++++--------- system/src/Grav/Console/Cli/CleanCommand.php | 5 +- 4 files changed, 72 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca5b8a473..0023af0b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ * Fixed `Uri::isValidExtension()` returning false positives * Fixed `page.html` returning duplicated content with `system.pages.redirect_default_route` turned on [#3130](https://github.com/getgrav/grav/issues/3130) * Fixed site redirect with redirect code failing when redirecting to sub-pages [#3035](https://github.com/getgrav/grav/pull/3035/files) + * Fixed `Uncaught ValueError: Path cannot be empty` when failing to upload a file [#3265](https://github.com/getgrav/grav/issues/3265) # v1.7.7 ## 02/23/2021 diff --git a/composer.json b/composer.json index 76ffffb5a..34d1e7e09 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "psr/http-message": "^1.0", "psr/http-server-middleware": "^1.0", "psr/container": "~1.0.0", - "kodus/psr7-server": "*", + "nyholm/psr7-server": "^1.0", "nyholm/psr7": "^1.3", "twig/twig": "~1.44", "erusev/parsedown": "^1.7", diff --git a/composer.lock b/composer.lock index 2e9801b52..cd3939a2d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0db8500b7a3f92a2b194df17ee416022", + "content-hash": "4ae6fc7274c018b1bb34bb1b80bd62c5", "packages": [ { "name": "antoligy/dom-string-iterators", @@ -954,64 +954,6 @@ ], "time": "2020-12-27T00:18:25+00:00" }, - { - "name": "kodus/psr7-server", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/kodus/psr7-server.git", - "reference": "dcfd0116451b0f0e7c6b23b831757ed288347278" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kodus/psr7-server/zipball/dcfd0116451b0f0e7c6b23b831757ed288347278", - "reference": "dcfd0116451b0f0e7c6b23b831757ed288347278", - "shasum": "" - }, - "require": { - "php": "^7.1", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0" - }, - "replace": { - "nyholm/psr7-server": "^0.3" - }, - "require-dev": { - "nyholm/nsa": "^1.1", - "nyholm/psr7": "^1.0", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Nyholm\\Psr7Server\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - }, - { - "name": "Martijn van der Ven", - "email": "martijn@vanderven.se" - } - ], - "description": "Helper classes to handle PSR-7 server requests", - "homepage": "http://tnyholm.se", - "keywords": [ - "psr-17", - "psr-7" - ], - "support": { - "source": "https://github.com/kodus/psr7-server/tree/master" - }, - "time": "2019-06-17T10:48:13+00:00" - }, { "name": "league/climate", "version": "3.7.0", @@ -1496,6 +1438,72 @@ ], "time": "2021-02-18T15:41:32+00:00" }, + { + "name": "nyholm/psr7-server", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7-server.git", + "reference": "5c134aeb5dd6521c7978798663470dabf0528c96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7-server/zipball/5c134aeb5dd6521c7978798663470dabf0528c96", + "reference": "5c134aeb5dd6521c7978798663470dabf0528c96", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "nyholm/nsa": "^1.1", + "nyholm/psr7": "^1.3", + "phpunit/phpunit": "^7.0 || ^8.5 || ^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nyholm\\Psr7Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "Helper classes to handle PSR-7 server requests", + "homepage": "http://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/Nyholm/psr7-server/issues", + "source": "https://github.com/Nyholm/psr7-server/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/Zegnat", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2020-11-15T15:26:20+00:00" + }, { "name": "phive/twig-extensions-deferred", "version": "v1.0.2", diff --git a/system/src/Grav/Console/Cli/CleanCommand.php b/system/src/Grav/Console/Cli/CleanCommand.php index 8aa019ccb..b0c949900 100644 --- a/system/src/Grav/Console/Cli/CleanCommand.php +++ b/system/src/Grav/Console/Cli/CleanCommand.php @@ -154,8 +154,6 @@ class CleanCommand extends Command 'vendor/itsgoingd/clockwork/.gitattributes', 'vendor/itsgoingd/clockwork/CHANGELOG.md', 'vendor/itsgoingd/clockwork/composer.json', - 'vendor/kodus/psr7-server/composer.json', - 'vendor/kodus/psr7-server/CHANGELOG.md', 'vendor/league/climate/composer.json', 'vendor/league/climate/CHANGELOG.md', 'vendor/league/climate/CONTRIBUTING.md', @@ -197,6 +195,9 @@ class CleanCommand extends Command 'vendor/nyholm/psr7/phpstan.neon.dist', 'vendor/nyholm/psr7/CHANGELOG.md', 'vendor/nyholm/psr7/psalm.xml', + 'vendor/nyholm/psr7-server/.github', + 'vendor/nyholm/psr7-server/composer.json', + 'vendor/nyholm/psr7-server/CHANGELOG.md', 'vendor/phive/twig-extensions-deferred/.gitignore', 'vendor/phive/twig-extensions-deferred/.travis.yml', 'vendor/phive/twig-extensions-deferred/composer.json', From dfcda956429b717db426e16f7067e3d6448db884 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Mon, 15 Mar 2021 18:50:28 +0200 Subject: [PATCH 02/11] Fixed `Path cannot be empty` when viewing non-existent log file [#3270] --- CHANGELOG.md | 3 ++- system/src/Grav/Common/Helpers/LogViewer.php | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0023af0b4..9176ad7a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,12 +17,13 @@ * Fixed Grav using blueprints and form fields from disabled plugins * Fixed `FlexIndex::sortBy(['key' => 'ASC'])` having no effect * Fixed default Flex Pages collection ordering to order by filesystem path - * Fixed disappearing pages on save if `pages://` stream resolves to multiple folders where the preferred folder doesn't exist + * Fixed disappearing pages on save if `pages://` stream resolves to multiple folders where the preferred folder doesn't exist * Fixed Markdown image attribute `loading` [#3251](https://github.com/getgrav/grav/pull/3251) * Fixed `Uri::isValidExtension()` returning false positives * Fixed `page.html` returning duplicated content with `system.pages.redirect_default_route` turned on [#3130](https://github.com/getgrav/grav/issues/3130) * Fixed site redirect with redirect code failing when redirecting to sub-pages [#3035](https://github.com/getgrav/grav/pull/3035/files) * Fixed `Uncaught ValueError: Path cannot be empty` when failing to upload a file [#3265](https://github.com/getgrav/grav/issues/3265) + * Fixed `Path cannot be empty` when viewing non-existent log file [#3270](https://github.com/getgrav/grav/issues/3270) # v1.7.7 ## 02/23/2021 diff --git a/system/src/Grav/Common/Helpers/LogViewer.php b/system/src/Grav/Common/Helpers/LogViewer.php index 1e3e8d2f7..a03fde810 100644 --- a/system/src/Grav/Common/Helpers/LogViewer.php +++ b/system/src/Grav/Common/Helpers/LogViewer.php @@ -34,7 +34,7 @@ class LogViewer public function objectTail($filepath, $lines = 1, $desc = true) { $data = $this->tail($filepath, $lines); - $tailed_log = explode(PHP_EOL, $data); + $tailed_log = $data ? explode(PHP_EOL, $data) : []; $line_objects = []; foreach ($tailed_log as $line) { @@ -54,13 +54,13 @@ public function objectTail($filepath, $lines = 1, $desc = true) public function tail($filepath, $lines = 1) { - $f = @fopen($filepath, "rb"); + $f = $filepath ? @fopen($filepath, 'rb') : false; if ($f === false) { return false; - } else { - $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096)); } + $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096)); + fseek($f, -1, SEEK_END); if (fread($f, 1) != "\n") { $lines -= 1; From 7a0ec5f51cfbe79577fb4b8780f34b5020412a78 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Mon, 15 Mar 2021 19:05:33 +0200 Subject: [PATCH 03/11] Composer update --- composer.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/composer.lock b/composer.lock index cd3939a2d..6ea862f92 100644 --- a/composer.lock +++ b/composer.lock @@ -763,18 +763,18 @@ "source": { "type": "git", "url": "https://github.com/getgrav/Image.git", - "reference": "70afaa75ea19856813124142c51f5fb2e9f1a285" + "reference": "ea23859700f32447a85e79d96f331e3d6c8897a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getgrav/Image/zipball/70afaa75ea19856813124142c51f5fb2e9f1a285", - "reference": "70afaa75ea19856813124142c51f5fb2e9f1a285", + "url": "https://api.github.com/repos/getgrav/Image/zipball/ea23859700f32447a85e79d96f331e3d6c8897a8", + "reference": "ea23859700f32447a85e79d96f331e3d6c8897a8", "shasum": "" }, "require": { "ext-gd": "*", "gregwar/cache": "dev-php8", - "php": "^5.3 || ^7.0 || ^8.0" + "php": "^5.6 || ^7.0 || ^8.0" }, "require-dev": { "sllh/php-cs-fixer-styleci-bridge": "~1.0", @@ -808,7 +808,7 @@ "support": { "source": "https://github.com/getgrav/Image/tree/php8" }, - "time": "2020-12-02T14:04:28+00:00" + "time": "2021-03-15T17:03:52+00:00" }, { "name": "guzzlehttp/psr7", @@ -887,16 +887,16 @@ }, { "name": "itsgoingd/clockwork", - "version": "v5.0.6", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/itsgoingd/clockwork.git", - "reference": "1de3f9f9fc22217aa024f79ecbdf0fde418fc0a1" + "reference": "e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/1de3f9f9fc22217aa024f79ecbdf0fde418fc0a1", - "reference": "1de3f9f9fc22217aa024f79ecbdf0fde418fc0a1", + "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4", + "reference": "e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4", "shasum": "" }, "require": { @@ -944,7 +944,7 @@ ], "support": { "issues": "https://github.com/itsgoingd/clockwork/issues", - "source": "https://github.com/itsgoingd/clockwork/tree/v5.0.6" + "source": "https://github.com/itsgoingd/clockwork/tree/v5.0.7" }, "funding": [ { @@ -952,7 +952,7 @@ "type": "github" } ], - "time": "2020-12-27T00:18:25+00:00" + "time": "2021-03-14T16:29:40+00:00" }, { "name": "league/climate", From f5e6a1f3deed0ff252479b830422975b99760b27 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Mon, 15 Mar 2021 19:12:14 +0200 Subject: [PATCH 04/11] Fixed `onAdminSave` original page having empty header [#3259] --- CHANGELOG.md | 1 + .../Common/Flex/Types/Pages/PageObject.php | 5 ++- system/src/Grav/Framework/Flex/FlexObject.php | 8 ++++ .../Framework/Flex/Pages/FlexPageObject.php | 41 ++++++++++++++++++- .../Flex/Pages/Traits/PageLegacyTrait.php | 16 ++------ 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9176ad7a3..7d18512ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ * Fixed site redirect with redirect code failing when redirecting to sub-pages [#3035](https://github.com/getgrav/grav/pull/3035/files) * Fixed `Uncaught ValueError: Path cannot be empty` when failing to upload a file [#3265](https://github.com/getgrav/grav/issues/3265) * Fixed `Path cannot be empty` when viewing non-existent log file [#3270](https://github.com/getgrav/grav/issues/3270) + * Fixed `onAdminSave` original page having empty header [#3259](https://github.com/getgrav/grav/issues/3259) # v1.7.7 ## 02/23/2021 diff --git a/system/src/Grav/Common/Flex/Types/Pages/PageObject.php b/system/src/Grav/Common/Flex/Types/Pages/PageObject.php index cc9473061..2d45b910b 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/PageObject.php +++ b/system/src/Grav/Common/Flex/Types/Pages/PageObject.php @@ -62,7 +62,6 @@ class PageObject extends FlexPageObject /** @var string Language code, eg: 'en' */ protected $language; - /** @var string File format, eg. 'md' */ protected $format; @@ -295,6 +294,9 @@ public function save($reorder = true) $grav->fireEvent('onAdminAfterSave', new Event(['type' => 'flex', 'directory' => $this->getFlexDirectory(), 'object' => $this])); } + // Reset original after save events have all been called. + $this->_original = null; + return $instance; } @@ -314,6 +316,7 @@ public function move(PageInterface $parent) $this->_reorder = []; $this->setProperty('parent_key', $parent->getStorageKey()); + $this->storeOriginal(); return $this; } diff --git a/system/src/Grav/Framework/Flex/FlexObject.php b/system/src/Grav/Framework/Flex/FlexObject.php index 9011745ad..09c563825 100644 --- a/system/src/Grav/Framework/Flex/FlexObject.php +++ b/system/src/Grav/Framework/Flex/FlexObject.php @@ -885,6 +885,14 @@ public function __debugInfo() ]; } + /** + * Clone object. + */ + public function __clone() + { + // Allows future compatibility as parent::__clone() works. + } + protected function markAsCopy(): void { $meta = $this->getMetaData(); diff --git a/system/src/Grav/Framework/Flex/Pages/FlexPageObject.php b/system/src/Grav/Framework/Flex/Pages/FlexPageObject.php index 39ac0c423..621dae046 100644 --- a/system/src/Grav/Framework/Flex/Pages/FlexPageObject.php +++ b/system/src/Grav/Framework/Flex/Pages/FlexPageObject.php @@ -16,7 +16,6 @@ use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Page\Traits\PageFormTrait; use Grav\Common\User\Interfaces\UserCollectionInterface; -use Grav\Framework\File\Formatter\YamlFormatter; use Grav\Framework\Flex\FlexObject; use Grav\Framework\Flex\Interfaces\FlexObjectInterface; use Grav\Framework\Flex\Interfaces\FlexTranslateInterface; @@ -50,6 +49,20 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI /** @var array|null */ protected $_reorder; + /** @var FlexPageObject|null */ + protected $_original; + + /** + * Clone page. + */ + public function __clone() + { + parent::__clone(); + + if (isset($this->header)) { + $this->header = clone($this->header); + } + } /** * @return array @@ -242,6 +255,32 @@ public function save($reorder = true) return parent::save(); } + /** + * Gets the Page Unmodified (original) version of the page. + * + * Assumes that object has been cloned before modifying it. + * + * @return FlexPageObject|null The original version of the page. + */ + public function getOriginal() + { + return $this->_original; + } + + /** + * Store the Page Unmodified (original) version of the page. + * + * Can be called multiple times, only the first call matters. + * + * @return void + */ + public function storeOriginal(): void + { + if (null === $this->_original) { + $this->_original = clone $this; + } + } + /** * Get display order for the associated media. * diff --git a/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php b/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php index 7320f053b..1c32bf566 100644 --- a/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php +++ b/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php @@ -277,6 +277,8 @@ public function move(PageInterface $parent) throw new RuntimeException('Failed: Cannot set page parent to a child of current page'); } + $this->storeOriginal(); + // TODO: throw new RuntimeException(__METHOD__ . '(): Not Implemented'); } @@ -292,6 +294,8 @@ public function move(PageInterface $parent) */ public function copy(PageInterface $parent = null) { + $this->storeOriginal(); + $filesystem = Filesystem::getInstance(false); $parentStorageKey = ltrim($filesystem->dirname("/{$this->getMasterKey()}"), '/'); @@ -1087,18 +1091,6 @@ public function folderExists(): bool return $this->exists() || is_dir($this->getStorageFolder() ?? ''); } - /** - * Gets the Page Unmodified (original) version of the page. - * - * Assumes that object has been cloned before modifying it. - * - * @return PageInterface|null The original version of the page. - */ - public function getOriginal() - { - return $this->getFlexDirectory()->getObject($this->getKey()); - } - /** * Gets the action. * From 8697a79df0779b6cbff24ccab28530af67e10292 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Wed, 17 Mar 2021 11:44:31 -0600 Subject: [PATCH 05/11] prepare for release --- CHANGELOG.md | 2 +- system/defines.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d18512ec..5fcd4bf0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # v1.7.8 -## mm/dd/2021 +## 03/17/2021 1. [](#new) * Added `ControllerResponseTrait::createDownloadResponse()` method diff --git a/system/defines.php b/system/defines.php index d0fd87357..6c4b8124f 100644 --- a/system/defines.php +++ b/system/defines.php @@ -8,7 +8,7 @@ // Some standard defines define('GRAV', true); -define('GRAV_VERSION', '1.7.7'); +define('GRAV_VERSION', '1.7.8'); define('GRAV_SCHEMA', '1.7.0_2020-11-20_1'); define('GRAV_TESTING', false); From 4ae9c42cc6034c5076d39cbf4bf083b66b274da8 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Wed, 17 Mar 2021 21:12:15 +0200 Subject: [PATCH 06/11] Composer update --- composer.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/composer.lock b/composer.lock index 6ea862f92..13fa1823e 100644 --- a/composer.lock +++ b/composer.lock @@ -381,16 +381,16 @@ }, { "name": "donatj/phpuseragentparser", - "version": "v1.3.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/donatj/PhpUserAgent.git", - "reference": "f9a521726b2ce4c5173281ceaab5a02c05b691ef" + "reference": "246c1cf0a44f07168c702203bf30d5f48f17bab0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/f9a521726b2ce4c5173281ceaab5a02c05b691ef", - "reference": "f9a521726b2ce4c5173281ceaab5a02c05b691ef", + "url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/246c1cf0a44f07168c702203bf30d5f48f17bab0", + "reference": "246c1cf0a44f07168c702203bf30d5f48f17bab0", "shasum": "" }, "require": { @@ -433,7 +433,7 @@ ], "support": { "issues": "https://github.com/donatj/PhpUserAgent/issues", - "source": "https://github.com/donatj/PhpUserAgent/tree/v1.3.0" + "source": "https://github.com/donatj/PhpUserAgent/tree/v1.4.0" }, "funding": [ { @@ -445,7 +445,7 @@ "type": "github" } ], - "time": "2021-02-18T04:30:49+00:00" + "time": "2021-03-16T16:25:14+00:00" }, { "name": "dragonmantank/cron-expression", @@ -642,16 +642,16 @@ }, { "name": "filp/whoops", - "version": "2.9.2", + "version": "2.10.0", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "df7933820090489623ce0be5e85c7e693638e536" + "reference": "6ecda5217bf048088b891f7403b262906be5a957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/df7933820090489623ce0be5e85c7e693638e536", - "reference": "df7933820090489623ce0be5e85c7e693638e536", + "url": "https://api.github.com/repos/filp/whoops/zipball/6ecda5217bf048088b891f7403b262906be5a957", + "reference": "6ecda5217bf048088b891f7403b262906be5a957", "shasum": "" }, "require": { @@ -701,7 +701,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.9.2" + "source": "https://github.com/filp/whoops/tree/2.10.0" }, "funding": [ { @@ -709,7 +709,7 @@ "type": "github" } ], - "time": "2021-01-24T12:00:00+00:00" + "time": "2021-03-16T12:00:00+00:00" }, { "name": "gregwar/cache", @@ -4929,16 +4929,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.2", + "version": "9.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f661659747f2f87f9e72095bb207bceb0f151cb4" + "reference": "27241ac75fc37ecf862b6e002bf713b6566cbe41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f661659747f2f87f9e72095bb207bceb0f151cb4", - "reference": "f661659747f2f87f9e72095bb207bceb0f151cb4", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/27241ac75fc37ecf862b6e002bf713b6566cbe41", + "reference": "27241ac75fc37ecf862b6e002bf713b6566cbe41", "shasum": "" }, "require": { @@ -5016,7 +5016,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.2" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.3" }, "funding": [ { @@ -5028,7 +5028,7 @@ "type": "github" } ], - "time": "2021-02-02T14:45:58+00:00" + "time": "2021-03-17T07:30:34+00:00" }, { "name": "psr/http-client", From dabb4402a77fa05a718c2810472464a9ed65a3d7 Mon Sep 17 00:00:00 2001 From: Djamil Legato Date: Wed, 17 Mar 2021 12:27:19 -0700 Subject: [PATCH 07/11] Handle skeletons rebuild manually only --- .github/workflows/trigger-skeletons.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/trigger-skeletons.yml b/.github/workflows/trigger-skeletons.yml index 08c6d636f..bc4f1a0c1 100644 --- a/.github/workflows/trigger-skeletons.yml +++ b/.github/workflows/trigger-skeletons.yml @@ -1,8 +1,6 @@ name: Trigger Skeletons Build on: - release: - types: [ published ] workflow_dispatch: inputs: version: From 62ff25f96d36d1d7381837b326e42a087c0be34a Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Wed, 17 Mar 2021 21:33:57 +0200 Subject: [PATCH 08/11] Fixed `onAdminSave` original page having empty header [#3259] --- CHANGELOG.md | 6 ++++++ system/src/Grav/Common/Page/Medium/AbstractMedia.php | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fcd4bf0a..cafc90bc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v1.7.9 +## mm/dd/2021 + +1. [](#new) + * Added `Media::hide()` method to hide files from media + # v1.7.8 ## 03/17/2021 diff --git a/system/src/Grav/Common/Page/Medium/AbstractMedia.php b/system/src/Grav/Common/Page/Medium/AbstractMedia.php index 06b44a77c..db81ddd4a 100644 --- a/system/src/Grav/Common/Page/Medium/AbstractMedia.php +++ b/system/src/Grav/Common/Page/Medium/AbstractMedia.php @@ -198,6 +198,17 @@ public function add($name, $file) } } + /** + * @param string $name + * @return void + */ + public function hide($name) + { + $this->offsetUnset($name); + + unset($this->images[$name], $this->videos[$name], $this->audios[$name], $this->files[$name]); + } + /** * Create Medium from a file. * From 644a54e441779f8dceb688e3f4d1c79a2107a369 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Wed, 17 Mar 2021 21:54:26 +0200 Subject: [PATCH 09/11] Added `Utils::getPathFromToken()` method which works also with `Flex Objects` --- CHANGELOG.md | 3 + system/src/Grav/Common/Utils.php | 145 +++++++++++++++++++++------ tests/unit/Grav/Common/UtilsTest.php | 6 ++ 3 files changed, 121 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cafc90bc0..6bdef605a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ 1. [](#new) * Added `Media::hide()` method to hide files from media + * Added `Utils::getPathFromToken()` method which works also with `Flex Objects` +1. [](#improved) + * Method `Utils::getPagePathFromToken()` now calls the more generic `Utils::getPathFromToken()` # v1.7.8 ## 03/17/2021 diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index a076f0aaa..dac5cf7a4 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -12,11 +12,15 @@ use DateTime; use DateTimeZone; use Exception; +use Grav\Common\Flex\Types\Pages\PageObject; use Grav\Common\Helpers\Truncator; use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Markdown\Parsedown; use Grav\Common\Markdown\ParsedownExtra; use Grav\Common\Page\Markdown\Excerpts; +use Grav\Common\Page\Pages; +use Grav\Framework\Flex\Flex; +use Grav\Framework\Flex\Interfaces\FlexObjectInterface; use InvalidArgumentException; use Negotiation\Accept; use Negotiation\Negotiator; @@ -1520,7 +1524,7 @@ public static function sortArrayByKey($array, $array_key, $direction = SORT_DESC } /** - * Get path based on a token + * Get relative page path based on a token. * * @param string $path * @param PageInterface|null $page @@ -1529,47 +1533,122 @@ public static function sortArrayByKey($array, $array_key, $direction = SORT_DESC */ public static function getPagePathFromToken($path, PageInterface $page = null) { - $path_parts = pathinfo($path); - $grav = Grav::instance(); + return static::getPathFromToken($path, $page); + } - $basename = ''; - if (isset($path_parts['extension'])) { - $basename = '/' . $path_parts['basename']; - $path = rtrim($path_parts['dirname'], ':'); + /** + * Get relative path based on a token. + * + * Path supports following syntaxes: + * + * 'self@', 'self@/path' + * 'page@:/route', 'page@:/route/filename.ext' + * 'theme@:', 'theme@:/path' + * + * @param string $path + * @param FlexObjectInterface|PageInterface|null $object + * @return string + * @throws RuntimeException + */ + public static function getPathFromToken($path, $object = null) + { + $matches = static::resolveTokenPath($path); + if (null === $matches) { + return $path; } - $regex = '/(@self|self@)|((?:@page|page@):(?:.*))|((?:@theme|theme@):(?:.*))/'; - preg_match($regex, $path, $matches); + $grav = Grav::instance(); - if ($matches) { - if ($matches[1]) { - if (null === $page) { - throw new RuntimeException('Page not available for this self@ reference'); + switch ($matches[0]) { + case 'self': + if (null === $object) { + throw new RuntimeException(sprintf('Page not available for self@ reference: %s', $path)); } - } elseif ($matches[2]) { - // page@ - $parts = explode(':', $path); - $route = $parts[1]; - $page = $grav['page']->find($route); - } elseif ($matches[3]) { - // theme@ - $parts = explode(':', $path); - $route = $parts[1]; - $theme = str_replace(ROOT_DIR, '', $grav['locator']->findResource('theme://')); - - return $theme . $route . $basename; - } - } else { - return $path . $basename; - } - if (!$page) { - throw new RuntimeException('Page route not found: ' . $path); + if ($matches[2] === '') { + if ($object->exists()) { + $route = '/' . $matches[1]; + + if ($object instanceof PageInterface) { + return trim($object->relativePagePath() . $route, '/'); + } + + $folder = $object->getMediaFolder(); + if ($folder) { + return trim($folder . $route, '/'); + } + } else { + return ''; + } + } + + break; + case 'page': + if ($matches[1] === '') { + $route = '/' . $matches[2]; + + // Exclude filename from the page lookup. + if (pathinfo($route, PATHINFO_EXTENSION)) { + $basename = '/' . basename($route); + $route = \dirname($route); + } else { + $basename = ''; + } + + $key = trim($route === '/' ? $grav['config']->get('system.home.alias') : $route, '/'); + if ($object instanceof PageObject) { + $object = $object->getFlexDirectory()->getObject($key); + } elseif (static::isAdminPlugin()) { + /** @var Flex|null $flex */ + $flex = $grav['flex'] ?? null; + $object = $flex ? $flex->getObject($key, 'pages') : null; + } else { + /** @var Pages $pages */ + $pages = $grav['pages']; + $object = $pages->find($route); + } + + if ($object instanceof PageInterface) { + return trim($object->relativePagePath() . $basename, '/'); + } + } + + break; + case 'theme': + if ($matches[1] === '') { + $route = '/' . $matches[2]; + $theme = $grav['locator']->findResource('theme://', false); + if (false !== $theme) { + return trim($theme . $route, '/'); + } + } + + break; } - $path = str_replace($matches[0], rtrim($page->relativePagePath(), '/'), $path); + throw new RuntimeException(sprintf('Token path not found: %s', $path)); + } + + /** + * Returns [token, route, path] from '@token/route:/path'. Route and path are optional. If pattern does not match, return null. + * + * @param string $path + * @return string[]|null + */ + private static function resolveTokenPath(string $path): ?array + { + if (strpos($path, '@') !== false) { + $regex = '/^(@\w+|\w+@|@\w+@)([^:]*)(.*)$/u'; + if (preg_match($regex, $path, $matches)) { + return [ + trim($matches[1], '@'), + trim($matches[2], '/'), + trim($matches[3], ':/') + ]; + } + } - return $path . $basename; + return null; } /** diff --git a/tests/unit/Grav/Common/UtilsTest.php b/tests/unit/Grav/Common/UtilsTest.php index 4329a454e..32fd84ce1 100644 --- a/tests/unit/Grav/Common/UtilsTest.php +++ b/tests/unit/Grav/Common/UtilsTest.php @@ -395,6 +395,12 @@ public function testVerifyNonce(): void self::assertTrue(Utils::verifyNonce(Utils::getNonce('test-action'), 'test-action')); } + public function testGetPagePathFromToken(): void + { + self::assertEquals('', Utils::getPagePathFromToken('')); + self::assertEquals('/test/path', Utils::getPagePathFromToken('/test/path')); + } + public function testUrl(): void { $this->uri->initializeWithUrl('http://testing.dev/path1/path2')->init(); From 0ab7d3ca637c2584e24d84862f106325afc08da4 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Wed, 17 Mar 2021 22:07:48 +0200 Subject: [PATCH 10/11] Fixed broken media upload in `Flex` with `@self/path`, `@page` and `@theme` destinations [#3275] --- CHANGELOG.md | 4 + .../Framework/Flex/Traits/FlexMediaTrait.php | 82 ++++++++++++++++--- 2 files changed, 73 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bdef605a..e2f8c0da0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,12 @@ 1. [](#new) * Added `Media::hide()` method to hide files from media * Added `Utils::getPathFromToken()` method which works also with `Flex Objects` + * Added `FlexMediaTrait::getMediaField()`, which can be used to access custom media set in the blueprint fields + * Added `FlexMediaTrait::getFieldSettings()`, which can be used to get media field settings 1. [](#improved) * Method `Utils::getPagePathFromToken()` now calls the more generic `Utils::getPathFromToken()` + * Fixed broken media upload in `Flex` with `@self/path`, `@page` and `@theme` destinations [#3275](https://github.com/getgrav/grav/issues/3275) + * Fixed media fields excluding newly deleted files before saving the object # v1.7.8 ## 03/17/2021 diff --git a/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php b/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php index c03a23de0..c9ae58057 100644 --- a/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php +++ b/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php @@ -14,8 +14,10 @@ use Grav\Common\Media\Interfaces\MediaCollectionInterface; use Grav\Common\Media\Interfaces\MediaUploadInterface; use Grav\Common\Media\Traits\MediaTrait; +use Grav\Common\Page\Media; use Grav\Common\Page\Medium\Medium; use Grav\Common\Page\Medium\MediumFactory; +use Grav\Common\Utils; use Grav\Framework\Cache\CacheInterface; use Grav\Framework\Filesystem\Filesystem; use Grav\Framework\Flex\FlexDirectory; @@ -23,6 +25,7 @@ use Psr\Http\Message\UploadedFileInterface; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use RuntimeException; +use function array_key_exists; use function in_array; use function is_array; use function is_callable; @@ -75,11 +78,40 @@ public function getMedia() return $media; } + /** + * @param string $field + * @return MediaCollectionInterface|null + */ + public function getMediaField(string $field): ?MediaCollectionInterface + { + // Field specific media. + $settings = $this->getFieldSettings($field); + if (!empty($settings['media_field'])) { + $var = 'destination'; + } elseif (!empty($settings['media_picker_field'])) { + $var = 'folder'; + } + + if (empty($var)) { + // Not a media field. + $media = null; + } elseif ($settings['self']) { + // Uses main media. + $media = $this->getMedia(); + } else { + // Uses custom media. + $media = new Media($settings[$var]); + $this->addUpdatedMedia($media); + } + + return $media; + } + /** * @param string $field * @return array|null */ - protected function getFieldSettings(string $field): ?array + public function getFieldSettings(string $field): ?array { if ($field === '') { return null; @@ -88,14 +120,32 @@ protected function getFieldSettings(string $field): ?array // Load settings for the field. $schema = $this->getBlueprint()->schema(); $settings = $field && is_object($schema) ? (array)$schema->getProperty($field) : null; + if (!isset($settings) || !is_array($settings)) { + return null; + } - if (isset($settings['type']) && (in_array($settings['type'], ['avatar', 'file', 'pagemedia']) || !empty($settings['destination']))) { - // Set destination folder. + $type = $settings['type'] ?? ''; + + // Media field. + if (!empty($settings['media_field']) || array_key_exists('destination', $settings) || in_array($type, ['avatar', 'file', 'pagemedia'], true)) { $settings['media_field'] = true; - if (empty($settings['destination']) || in_array($settings['destination'], ['@self', 'self@', '@self@'], true)) { - $settings['destination'] = $this->getMediaFolder(); + $var = 'destination'; + } + + // Media picker field. + if (!empty($settings['media_picker_field']) || in_array($type, ['filepicker', 'pagemediaselect'], true)) { + $settings['media_picker_field'] = true; + $var = 'folder'; + } + + // Set media folder for media fields. + if (isset($var)) { + $folder = $settings[$var] ?? ''; + if (in_array(rtrim($folder, '/'), ['', '@self', 'self@', '@self@'], true)) { + $settings[$var] = $this->getMediaFolder(); $settings['self'] = true; } else { + $settings[$var] = Utils::getPathFromToken($folder, $this); $settings['self'] = false; } } @@ -115,7 +165,6 @@ protected function getMediaFieldSettings(string $field): array return $settings + ['accept' => '*', 'limit' => 1000, 'self' => true]; } - protected function getMediaFields(): array { // Load settings for the field. @@ -206,12 +255,13 @@ public function checkUploadedMediaFile(UploadedFileInterface $uploadedFile, stri */ public function uploadMediaFile(UploadedFileInterface $uploadedFile, string $filename = null, string $field = null): void { - $media = $this->getMedia(); + $settings = $this->getMediaFieldSettings($field ?? ''); + + $media = $field ? $this->getMediaField($field) : $this->getMedia(); if (!$media instanceof MediaUploadInterface) { throw new RuntimeException("Media for {$this->getFlexDirectory()->getFlexType()} doesn't support file uploads."); } - $settings = $this->getMediaFieldSettings($field ?? ''); $filename = $media->checkUploadedFile($uploadedFile, $filename, $settings); $media->copyUploadedFile($uploadedFile, $filename, $settings); $this->clearMediaCache(); @@ -322,13 +372,20 @@ protected function addUpdatedMedia(MediaCollectionInterface $media): void foreach ($this->getUpdatedMedia() as $filename => $upload) { if (is_array($upload)) { // Uses new format with [UploadedFileInterface, array]. - $upload = $upload[0]; + $settings = $upload[1]; + if ($settings['destination'] === $media->getPath()) { + $upload = $upload[0]; + } else { + $upload = false; + } } - if ($upload) { - $medium = MediumFactory::fromUploadedFile($upload); + if (false !== $upload) { + $medium = $upload ? MediumFactory::fromUploadedFile($upload) : null; + $updated = true; if ($medium) { - $updated = true; $media->add($filename, $medium); + } else { + $media->hide($filename); } } } @@ -356,7 +413,6 @@ protected function saveUpdatedMedia(): void return; } - // Upload/delete altered files. /** * @var string $filename From 86169bbf7c1bb942e401ff9666f3b881bda57916 Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Wed, 17 Mar 2021 22:20:35 +0200 Subject: [PATCH 11/11] Changelog update --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2f8c0da0..633fbe070 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * Added `FlexMediaTrait::getFieldSettings()`, which can be used to get media field settings 1. [](#improved) * Method `Utils::getPagePathFromToken()` now calls the more generic `Utils::getPathFromToken()` +1. [](#bugfix) * Fixed broken media upload in `Flex` with `@self/path`, `@page` and `@theme` destinations [#3275](https://github.com/getgrav/grav/issues/3275) * Fixed media fields excluding newly deleted files before saving the object