diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2996b161..955c87d34 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,54 @@
+# v1.2.0
+## 03/31/2017
+
+1. [](#new)
+ * Added file upload for user avatar in user/admin blueprint
+1. [](#improved)
+ * Analysis fixes
+ * Switched to stable composer lib versions
+
+# v1.2.0-rc.3
+## 03/22/2017
+
+1. [](#new)
+ * Refactored Page re-ordering to handle all siblings at once
+ * Added `language_codes` to Twig init to allow for easy language name/code/native-name lookup
+1. [](#improved)
+ * Added an _Admin Overrides_ section with option to choose the order of children in Pages Management
+1. [](#bugfix)
+ * Fixed loading issues with improperly named themes (use old broken method first) [#1373](https://github.com/getgrav/grav/issues/1373)
+ * Simplified modular/twig processing logic and fixed an issue with system process config [#1351](https://github.com/getgrav/grav/issues/1351)
+ * Cleanup package files via GPM install to make them more windows-friendly [#1361](https://github.com/getgrav/grav/pull/1361)
+ * Fix for page-level debugger override changing the option site-wide
+ * Allow `url()` twig function to pass-through external links
+
+# v1.2.0-rc.2
+## 03/17/2017
+
+1. [](#improved)
+ * Updated vendor libraries to latest
+ * Added the ability to disable debugger on a per-page basis with `debugger: false` in page frontmatter
+1. [](#bugfix)
+ * Fixed an issue with theme inheritance and hyphenated base themes [#1353](https://github.com/getgrav/grav/issues/1353)
+ * Fixed an issue when trying to use an `@2x` derivative on a non-image media file [#1341](https://github.com/getgrav/grav/issues/1341)
+
+# v1.2.0-rc.1
+## 03/13/2017
+
+1. [](#new)
+ * Added default setting to only allow `direct-installs` from official GPM. Can be configured in `system.yaml`
+ * Added a new `Utils::isValidUrl()` method
+ * Added optional parameter to `|markdown(false)` filter to toggle block/line processing (default|true = `block`)
+ * Added new `Page::folderExists()` method
+1. [](#improved)
+ * `Twig::evaluate()` now takes current environment and context into account
+ * Genericized `direct-install` so it can be called via Admin plugin
+1. [](#bugfix)
+ * Fixed a minor bug in Number validation [#1329](https://github.com/getgrav/grav/issues/1329)
+ * Fixed exception when trying to find user account and there is no `user://accounts` folder
+ * Fixed issue when setting `Page::expires(0)` [Admin #1009](https://github.com/getgrav/grav-plugin-admin/issues/1009)
+ * Removed ID from `nonce_field()` Twig function causing validation errors [Form #115](https://github.com/getgrav/grav-plugin-form/issues/115)
+
# v1.1.17
## 02/17/2017
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5d5c52774..22362c8a5 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -110,7 +110,7 @@ Good pull requests - patches, improvements, new features - are a fantastic
help. They should remain focused in scope and avoid containing unrelated
commits.
-**Please ask first** in Gitter or in the Forum before embarking on any significant pull request (e.g.
+**Please ask first** in [Slack](https://getgrav.org/slack) or in the Forum before embarking on any significant pull request (e.g.
implementing features, refactoring code..),
otherwise you risk spending a lot of time working on something that the
project's developers might not want to merge into the project.
diff --git a/composer.json b/composer.json
index 832587378..d1e846396 100644
--- a/composer.json
+++ b/composer.json
@@ -8,7 +8,7 @@
"require": {
"php": ">=5.5.9",
"twig/twig": "~1.24",
- "erusev/parsedown": "dev-master as 1.6.0",
+ "erusev/parsedown": "~1.6",
"erusev/parsedown-extra": "~0.7",
"symfony/yaml": "~2.8",
"symfony/console": "~2.8",
@@ -19,7 +19,7 @@
"filp/whoops": "~2.0",
"matthiasmullie/minify": "^1.3",
"monolog/monolog": "~1.0",
- "gregwar/image": "dev-master#72568cfbeb77515278f2ccb386fc344e874b7ae8",
+ "gregwar/image": "~2.0",
"donatj/phpuseragentparser": "~0.3",
"pimple/pimple": "~3.0",
"rockettheme/toolbox": "~1.0",
diff --git a/composer.lock b/composer.lock
index 5b083f85d..1066c3520 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "4e5b9333d3ac2de823c68c9c8e0f2017",
+ "content-hash": "e981b23b44354d081ec1e1ac214656a1",
"packages": [
{
"name": "antoligy/dom-string-iterators",
@@ -122,16 +122,16 @@
},
{
"name": "donatj/phpuseragentparser",
- "version": "v0.6.0",
+ "version": "v0.7.0",
"source": {
"type": "git",
"url": "https://github.com/donatj/PhpUserAgent.git",
- "reference": "a4f515619c8d9697f34dd8da2eb353bb4c57c5dc"
+ "reference": "73c819d4c7de034f1bfb7c7a36259192d7d7472a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/a4f515619c8d9697f34dd8da2eb353bb4c57c5dc",
- "reference": "a4f515619c8d9697f34dd8da2eb353bb4c57c5dc",
+ "url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/73c819d4c7de034f1bfb7c7a36259192d7d7472a",
+ "reference": "73c819d4c7de034f1bfb7c7a36259192d7d7472a",
"shasum": ""
},
"require": {
@@ -169,20 +169,20 @@
"user agent",
"useragent"
],
- "time": "2017-01-23T19:32:09+00:00"
+ "time": "2017-03-01T22:19:13+00:00"
},
{
"name": "erusev/parsedown",
- "version": "dev-master",
+ "version": "1.6.2",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
- "reference": "4b6493999acfa7792efa3cb252d90168e6f266b9"
+ "reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/erusev/parsedown/zipball/4b6493999acfa7792efa3cb252d90168e6f266b9",
- "reference": "4b6493999acfa7792efa3cb252d90168e6f266b9",
+ "url": "https://api.github.com/repos/erusev/parsedown/zipball/1bf24f7334fe16c88bf9d467863309ceaf285b01",
+ "reference": "1bf24f7334fe16c88bf9d467863309ceaf285b01",
"shasum": ""
},
"require": {
@@ -211,7 +211,7 @@
"markdown",
"parser"
],
- "time": "2017-01-23 07:45:19"
+ "time": "2017-03-29T16:04:15+00:00"
},
{
"name": "erusev/parsedown-extra",
@@ -259,20 +259,21 @@
},
{
"name": "filp/whoops",
- "version": "2.1.5",
+ "version": "2.1.8",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
- "reference": "2abce9d956589122c6443d6265f01cf7e9388e3c"
+ "reference": "f2950be7da8b8d6c4e77821b6c9d486e36cdc4f3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/filp/whoops/zipball/2abce9d956589122c6443d6265f01cf7e9388e3c",
- "reference": "2abce9d956589122c6443d6265f01cf7e9388e3c",
+ "url": "https://api.github.com/repos/filp/whoops/zipball/f2950be7da8b8d6c4e77821b6c9d486e36cdc4f3",
+ "reference": "f2950be7da8b8d6c4e77821b6c9d486e36cdc4f3",
"shasum": ""
},
"require": {
- "php": "^5.5.9 || ^7.0"
+ "php": "^5.5.9 || ^7.0",
+ "psr/log": "^1.0.1"
},
"require-dev": {
"mockery/mockery": "0.9.*",
@@ -315,7 +316,7 @@
"whoops",
"zf2"
],
- "time": "2016-12-26T16:13:31+00:00"
+ "time": "2017-03-07T09:04:45+00:00"
},
{
"name": "gregwar/cache",
@@ -362,17 +363,17 @@
},
{
"name": "gregwar/image",
- "version": "dev-master",
+ "version": "v2.0.21",
"target-dir": "Gregwar/Image",
"source": {
"type": "git",
"url": "https://github.com/Gregwar/Image.git",
- "reference": "72568cfbeb77515278f2ccb386fc344e874b7ae8"
+ "reference": "c9899e4c71009338f89a8c63c12c681692533ede"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Gregwar/Image/zipball/72568cfbeb77515278f2ccb386fc344e874b7ae8",
- "reference": "72568cfbeb77515278f2ccb386fc344e874b7ae8",
+ "url": "https://api.github.com/repos/Gregwar/Image/zipball/c9899e4c71009338f89a8c63c12c681692533ede",
+ "reference": "c9899e4c71009338f89a8c63c12c681692533ede",
"shasum": ""
},
"require": {
@@ -410,7 +411,7 @@
"gd",
"image"
],
- "time": "2016-07-12 17:02:18"
+ "time": "2017-01-24T09:29:39+00:00"
},
{
"name": "league/climate",
@@ -465,16 +466,16 @@
},
{
"name": "matthiasmullie/minify",
- "version": "1.3.43",
+ "version": "1.3.44",
"source": {
"type": "git",
"url": "https://github.com/matthiasmullie/minify.git",
- "reference": "aa50b2dab6fa7bfd402d334fe51005d6f2526ad7"
+ "reference": "a7fc4a98ef8f2cf38bba701b51f1a84a1d67bc5c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/aa50b2dab6fa7bfd402d334fe51005d6f2526ad7",
- "reference": "aa50b2dab6fa7bfd402d334fe51005d6f2526ad7",
+ "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/a7fc4a98ef8f2cf38bba701b51f1a84a1d67bc5c",
+ "reference": "a7fc4a98ef8f2cf38bba701b51f1a84a1d67bc5c",
"shasum": ""
},
"require": {
@@ -518,7 +519,7 @@
"minifier",
"minify"
],
- "time": "2017-01-26T15:48:07+00:00"
+ "time": "2017-03-16T16:42:50+00:00"
},
{
"name": "matthiasmullie/path-converter",
@@ -632,16 +633,16 @@
},
{
"name": "monolog/monolog",
- "version": "1.22.0",
+ "version": "1.22.1",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
- "reference": "bad29cb8d18ab0315e6c477751418a82c850d558"
+ "reference": "1e044bc4b34e91743943479f1be7a1d5eb93add0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bad29cb8d18ab0315e6c477751418a82c850d558",
- "reference": "bad29cb8d18ab0315e6c477751418a82c850d558",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1e044bc4b34e91743943479f1be7a1d5eb93add0",
+ "reference": "1e044bc4b34e91743943479f1be7a1d5eb93add0",
"shasum": ""
},
"require": {
@@ -706,7 +707,7 @@
"logging",
"psr-3"
],
- "time": "2016-11-26T00:15:39+00:00"
+ "time": "2017-03-13T07:08:03+00:00"
},
{
"name": "pimple/pimple",
@@ -851,16 +852,16 @@
},
{
"name": "seld/cli-prompt",
- "version": "1.0.2",
+ "version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/cli-prompt.git",
- "reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4"
+ "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4",
- "reference": "8cbe10923cae5bcd7c5a713f6703fc4727c8c1b4",
+ "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/a19a7376a4689d4d94cab66ab4f3c816019ba8dd",
+ "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd",
"shasum": ""
},
"require": {
@@ -895,25 +896,25 @@
"input",
"prompt"
],
- "time": "2016-04-18T09:31:41+00:00"
+ "time": "2017-03-18T11:32:45+00:00"
},
{
"name": "symfony/console",
- "version": "v2.8.17",
+ "version": "v2.8.18",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4"
+ "reference": "81508e6fac4476771275a3f4f53c3fee9b956bfa"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4",
- "reference": "f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4",
+ "url": "https://api.github.com/repos/symfony/console/zipball/81508e6fac4476771275a3f4f53c3fee9b956bfa",
+ "reference": "81508e6fac4476771275a3f4f53c3fee9b956bfa",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
- "symfony/debug": "~2.7,>=2.7.2|~3.0.0",
+ "symfony/debug": "^2.7.2|~3.0.0",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
@@ -956,7 +957,7 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "time": "2017-02-06T12:04:06+00:00"
+ "time": "2017-03-04T11:00:12+00:00"
},
{
"name": "symfony/debug",
@@ -1017,16 +1018,16 @@
},
{
"name": "symfony/event-dispatcher",
- "version": "v2.8.17",
+ "version": "v2.8.18",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "74877977f90fb9c3e46378d5764217c55f32df34"
+ "reference": "bb4ec47e8e109c1c1172145732d0aa468d967cd0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/74877977f90fb9c3e46378d5764217c55f32df34",
- "reference": "74877977f90fb9c3e46378d5764217c55f32df34",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/bb4ec47e8e109c1c1172145732d0aa468d967cd0",
+ "reference": "bb4ec47e8e109c1c1172145732d0aa468d967cd0",
"shasum": ""
},
"require": {
@@ -1034,7 +1035,7 @@
},
"require-dev": {
"psr/log": "~1.0",
- "symfony/config": "~2.0,>=2.0.5|~3.0.0",
+ "symfony/config": "^2.0.5|~3.0.0",
"symfony/dependency-injection": "~2.6|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0"
@@ -1073,7 +1074,7 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
- "time": "2017-01-02T20:30:24+00:00"
+ "time": "2017-02-21T08:33:48+00:00"
},
{
"name": "symfony/polyfill-iconv",
@@ -1195,22 +1196,25 @@
},
{
"name": "symfony/var-dumper",
- "version": "v2.8.17",
+ "version": "v2.8.18",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "eb4526a20ba9e691f50a7510ea3db3728ada958f"
+ "reference": "c51daca85371e30ce0e3dea99c7b08e2cb5dbf46"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/eb4526a20ba9e691f50a7510ea3db3728ada958f",
- "reference": "eb4526a20ba9e691f50a7510ea3db3728ada958f",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c51daca85371e30ce0e3dea99c7b08e2cb5dbf46",
+ "reference": "c51daca85371e30ce0e3dea99c7b08e2cb5dbf46",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/polyfill-mbstring": "~1.0"
},
+ "conflict": {
+ "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
+ },
"require-dev": {
"twig/twig": "~1.20|~2.0"
},
@@ -1254,20 +1258,20 @@
"debug",
"dump"
],
- "time": "2017-01-24T13:02:12+00:00"
+ "time": "2017-02-20T13:37:30+00:00"
},
{
"name": "symfony/yaml",
- "version": "v2.8.17",
+ "version": "v2.8.18",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153"
+ "reference": "2a7bab3c16f6f452c47818fdd08f3b1e49ffcf7d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/322a8c2dfbca15ad6b1b27e182899f98ec0e0153",
- "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/2a7bab3c16f6f452c47818fdd08f3b1e49ffcf7d",
+ "reference": "2a7bab3c16f6f452c47818fdd08f3b1e49ffcf7d",
"shasum": ""
},
"require": {
@@ -1303,33 +1307,34 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2017-01-21T16:40:50+00:00"
+ "time": "2017-03-01T18:13:50+00:00"
},
{
"name": "twig/twig",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
- "reference": "ddc9e3e20ee9c0b6908f401ac8353635b750eca7"
+ "reference": "05cf49921b13f6f01d3cfdf9018cfa7a8086fd5a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/ddc9e3e20ee9c0b6908f401ac8353635b750eca7",
- "reference": "ddc9e3e20ee9c0b6908f401ac8353635b750eca7",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/05cf49921b13f6f01d3cfdf9018cfa7a8086fd5a",
+ "reference": "05cf49921b13f6f01d3cfdf9018cfa7a8086fd5a",
"shasum": ""
},
"require": {
"php": ">=5.2.7"
},
"require-dev": {
+ "psr/container": "^1.0",
"symfony/debug": "~2.7",
- "symfony/phpunit-bridge": "~3.2"
+ "symfony/phpunit-bridge": "~3.3@dev"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.31-dev"
+ "dev-master": "1.33-dev"
}
},
"autoload": {
@@ -1364,7 +1369,7 @@
"keywords": [
"templating"
],
- "time": "2017-01-11T19:36:15+00:00"
+ "time": "2017-03-22T15:40:09+00:00"
}
],
"packages-dev": [
@@ -1429,16 +1434,16 @@
},
{
"name": "codeception/codeception",
- "version": "2.2.9",
+ "version": "2.2.10",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Codeception.git",
- "reference": "0204f1362040d3e408404af2545e5fa27e8964e2"
+ "reference": "c32a3f92834db08ceedb4666ea2265c3aa43396e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Codeception/Codeception/zipball/0204f1362040d3e408404af2545e5fa27e8964e2",
- "reference": "0204f1362040d3e408404af2545e5fa27e8964e2",
+ "url": "https://api.github.com/repos/Codeception/Codeception/zipball/c32a3f92834db08ceedb4666ea2265c3aa43396e",
+ "reference": "c32a3f92834db08ceedb4666ea2265c3aa43396e",
"shasum": ""
},
"require": {
@@ -1453,6 +1458,7 @@
"phpunit/phpunit": ">4.8.20 <6.0",
"sebastian/comparator": "~1.1",
"sebastian/diff": "^1.4",
+ "stecman/symfony-console-completion": "^0.7.0",
"symfony/browser-kit": ">=2.7 <4.0",
"symfony/console": ">=2.7 <4.0",
"symfony/css-selector": ">=2.7 <4.0",
@@ -1517,7 +1523,7 @@
"functional testing",
"unit testing"
],
- "time": "2017-02-04T02:04:21+00:00"
+ "time": "2017-03-25T03:19:52+00:00"
},
{
"name": "doctrine/instantiator",
@@ -1575,34 +1581,37 @@
},
{
"name": "facebook/webdriver",
- "version": "1.3.0",
+ "version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/facebook/php-webdriver.git",
- "reference": "77300c4ab2025d4316635f592ec849ca7323bd8c"
+ "reference": "3ea034c056189e11c0ce7985332a9f4b5b2b5db2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/77300c4ab2025d4316635f592ec849ca7323bd8c",
- "reference": "77300c4ab2025d4316635f592ec849ca7323bd8c",
+ "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/3ea034c056189e11c0ce7985332a9f4b5b2b5db2",
+ "reference": "3ea034c056189e11c0ce7985332a9f4b5b2b5db2",
"shasum": ""
},
"require": {
"ext-curl": "*",
+ "ext-zip": "*",
"php": "^5.5 || ~7.0",
"symfony/process": "^2.8 || ^3.1"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^1.11",
+ "friendsofphp/php-cs-fixer": "^2.0",
"php-mock/php-mock-phpunit": "^1.1",
"phpunit/phpunit": "4.6.* || ~5.0",
"satooshi/php-coveralls": "^1.0",
"squizlabs/php_codesniffer": "^2.6"
},
- "suggest": {
- "phpdocumentor/phpdocumentor": "2.*"
- },
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-community": "1.5-dev"
+ }
+ },
"autoload": {
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
@@ -1612,7 +1621,7 @@
"license": [
"Apache-2.0"
],
- "description": "A PHP client for WebDriver",
+ "description": "A PHP client for Selenium WebDriver",
"homepage": "https://github.com/facebook/php-webdriver",
"keywords": [
"facebook",
@@ -1620,7 +1629,7 @@
"selenium",
"webdriver"
],
- "time": "2017-01-13T15:48:08+00:00"
+ "time": "2017-03-22T10:56:03+00:00"
},
{
"name": "fzaninotto/faker",
@@ -1672,21 +1681,21 @@
},
{
"name": "guzzlehttp/guzzle",
- "version": "6.2.2",
+ "version": "6.2.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60"
+ "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ebf29dee597f02f09f4d5bbecc68230ea9b08f60",
- "reference": "ebf29dee597f02f09f4d5bbecc68230ea9b08f60",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/8d6c6cc55186db87b7dc5009827429ba4e9dc006",
+ "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006",
"shasum": ""
},
"require": {
"guzzlehttp/promises": "^1.0",
- "guzzlehttp/psr7": "^1.3.1",
+ "guzzlehttp/psr7": "^1.4",
"php": ">=5.5"
},
"require-dev": {
@@ -1730,7 +1739,7 @@
"rest",
"web service"
],
- "time": "2016-10-08T15:01:37+00:00"
+ "time": "2017-02-28T22:50:30+00:00"
},
{
"name": "guzzlehttp/promises",
@@ -1785,16 +1794,16 @@
},
{
"name": "guzzlehttp/psr7",
- "version": "1.3.1",
+ "version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b"
+ "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
- "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
+ "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
"shasum": ""
},
"require": {
@@ -1830,16 +1839,23 @@
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Schultze",
+ "homepage": "https://github.com/Tobion"
}
],
- "description": "PSR-7 message implementation",
+ "description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
+ "request",
+ "response",
"stream",
- "uri"
+ "uri",
+ "url"
],
- "time": "2016-06-24T23:00:38+00:00"
+ "time": "2017-03-20T17:10:46+00:00"
},
{
"name": "phpdocumentor/reflection-common",
@@ -1989,27 +2005,27 @@
},
{
"name": "phpspec/prophecy",
- "version": "v1.6.2",
+ "version": "v1.7.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "6c52c2722f8460122f96f86346600e1077ce22cb"
+ "reference": "93d39f1f7f9326d746203c7c056f300f7f126073"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb",
- "reference": "6c52c2722f8460122f96f86346600e1077ce22cb",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073",
+ "reference": "93d39f1f7f9326d746203c7c056f300f7f126073",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
- "sebastian/comparator": "^1.1",
- "sebastian/recursion-context": "^1.0|^2.0"
+ "sebastian/comparator": "^1.1|^2.0",
+ "sebastian/recursion-context": "^1.0|^2.0|^3.0"
},
"require-dev": {
- "phpspec/phpspec": "^2.0",
+ "phpspec/phpspec": "^2.5|^3.2",
"phpunit/phpunit": "^4.8 || ^5.6.5"
},
"type": "library",
@@ -2048,7 +2064,7 @@
"spy",
"stub"
],
- "time": "2016-11-21T14:58:47+00:00"
+ "time": "2017-03-02T20:05:34+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -2202,25 +2218,30 @@
},
{
"name": "phpunit/php-timer",
- "version": "1.0.8",
+ "version": "1.0.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
- "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": "^5.3.3 || ^7.0"
},
"require-dev": {
- "phpunit/phpunit": "~4|~5"
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
},
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
"autoload": {
"classmap": [
"src/"
@@ -2242,20 +2263,20 @@
"keywords": [
"timer"
],
- "time": "2016-05-12T18:03:57+00:00"
+ "time": "2017-02-26T11:10:40+00:00"
},
{
"name": "phpunit/php-token-stream",
- "version": "1.4.9",
+ "version": "1.4.11",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b"
+ "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b",
- "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7",
+ "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7",
"shasum": ""
},
"require": {
@@ -2291,7 +2312,7 @@
"keywords": [
"tokenizer"
],
- "time": "2016-11-15T14:06:22+00:00"
+ "time": "2017-02-27T10:12:30+00:00"
},
{
"name": "phpunit/phpunit",
@@ -2757,16 +2778,16 @@
},
{
"name": "sebastian/recursion-context",
- "version": "1.0.2",
+ "version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "913401df809e99e4f47b27cdd781f4a258d58791"
+ "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
- "reference": "913401df809e99e4f47b27cdd781f4a258d58791",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
+ "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
"shasum": ""
},
"require": {
@@ -2806,7 +2827,7 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
- "time": "2015-11-11T19:50:13+00:00"
+ "time": "2016-10-03T07:41:43+00:00"
},
{
"name": "sebastian/version",
@@ -2844,17 +2865,62 @@
"time": "2015-06-21T13:59:46+00:00"
},
{
- "name": "symfony/browser-kit",
- "version": "v3.2.3",
+ "name": "stecman/symfony-console-completion",
+ "version": "0.7.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/browser-kit.git",
- "reference": "394a2475a3a89089353fde5714a7f402fbb83880"
+ "url": "https://github.com/stecman/symfony-console-completion.git",
+ "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/browser-kit/zipball/394a2475a3a89089353fde5714a7f402fbb83880",
- "reference": "394a2475a3a89089353fde5714a7f402fbb83880",
+ "url": "https://api.github.com/repos/stecman/symfony-console-completion/zipball/5461d43e53092b3d3b9dbd9d999f2054730f4bbb",
+ "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2",
+ "symfony/console": "~2.3 || ~3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Stecman\\Component\\Symfony\\Console\\BashCompletion\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Stephen Holdaway",
+ "email": "stephen@stecman.co.nz"
+ }
+ ],
+ "description": "Automatic BASH completion for Symfony Console Component based applications.",
+ "time": "2016-02-24T05:08:54+00:00"
+ },
+ {
+ "name": "symfony/browser-kit",
+ "version": "v3.2.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/browser-kit.git",
+ "reference": "2fe0caa60c1a1dfeefd0425741182687a9b382b8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2fe0caa60c1a1dfeefd0425741182687a9b382b8",
+ "reference": "2fe0caa60c1a1dfeefd0425741182687a9b382b8",
"shasum": ""
},
"require": {
@@ -2898,20 +2964,20 @@
],
"description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com",
- "time": "2017-01-31T21:49:23+00:00"
+ "time": "2017-02-21T09:12:04+00:00"
},
{
"name": "symfony/css-selector",
- "version": "v3.2.3",
+ "version": "v3.2.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
- "reference": "f0e628f04fc055c934b3211cfabdb1c59eefbfaa"
+ "reference": "a48f13dc83c168f1253a5d2a5a4fb46c36244c4c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/f0e628f04fc055c934b3211cfabdb1c59eefbfaa",
- "reference": "f0e628f04fc055c934b3211cfabdb1c59eefbfaa",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/a48f13dc83c168f1253a5d2a5a4fb46c36244c4c",
+ "reference": "a48f13dc83c168f1253a5d2a5a4fb46c36244c4c",
"shasum": ""
},
"require": {
@@ -2951,20 +3017,20 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
- "time": "2017-01-02T20:32:22+00:00"
+ "time": "2017-02-21T09:12:04+00:00"
},
{
"name": "symfony/dom-crawler",
- "version": "v3.2.3",
+ "version": "v3.2.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
- "reference": "b814b41373fc4e535aff8c765abe39545216f391"
+ "reference": "403944e294cf4ceb3b8447f54cbad88ea7b99cee"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b814b41373fc4e535aff8c765abe39545216f391",
- "reference": "b814b41373fc4e535aff8c765abe39545216f391",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/403944e294cf4ceb3b8447f54cbad88ea7b99cee",
+ "reference": "403944e294cf4ceb3b8447f54cbad88ea7b99cee",
"shasum": ""
},
"require": {
@@ -3007,20 +3073,20 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
- "time": "2017-01-21T17:14:11+00:00"
+ "time": "2017-02-21T09:12:04+00:00"
},
{
"name": "symfony/finder",
- "version": "v3.2.3",
+ "version": "v3.2.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "8c71141cae8e2957946b403cc71a67213c0380d6"
+ "reference": "92d7476d2df60cd851a3e13e078664b1deb8ce10"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/8c71141cae8e2957946b403cc71a67213c0380d6",
- "reference": "8c71141cae8e2957946b403cc71a67213c0380d6",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/92d7476d2df60cd851a3e13e078664b1deb8ce10",
+ "reference": "92d7476d2df60cd851a3e13e078664b1deb8ce10",
"shasum": ""
},
"require": {
@@ -3056,20 +3122,20 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "time": "2017-01-02T20:32:22+00:00"
+ "time": "2017-02-21T09:12:04+00:00"
},
{
"name": "symfony/process",
- "version": "v3.2.3",
+ "version": "v3.2.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "32646a7cf53f3956c76dcb5c82555224ae321858"
+ "reference": "68bfa8c83f24c0ac04ea7193bcdcda4519f41892"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/32646a7cf53f3956c76dcb5c82555224ae321858",
- "reference": "32646a7cf53f3956c76dcb5c82555224ae321858",
+ "url": "https://api.github.com/repos/symfony/process/zipball/68bfa8c83f24c0ac04ea7193bcdcda4519f41892",
+ "reference": "68bfa8c83f24c0ac04ea7193bcdcda4519f41892",
"shasum": ""
},
"require": {
@@ -3105,7 +3171,7 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
- "time": "2017-02-03T12:11:38+00:00"
+ "time": "2017-03-04T12:23:14+00:00"
},
{
"name": "webmozart/assert",
@@ -3158,19 +3224,9 @@
"time": "2016-11-23T20:04:58+00:00"
}
],
- "aliases": [
- {
- "alias": "1.6.0",
- "alias_normalized": "1.6.0.0",
- "version": "9999999-dev",
- "package": "erusev/parsedown"
- }
- ],
+ "aliases": [],
"minimum-stability": "stable",
- "stability-flags": {
- "erusev/parsedown": 20,
- "gregwar/image": 20
- },
+ "stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
diff --git a/system/blueprints/config/site.yaml b/system/blueprints/config/site.yaml
index fe783f084..57fd3c57a 100644
--- a/system/blueprints/config/site.yaml
+++ b/system/blueprints/config/site.yaml
@@ -19,7 +19,7 @@ form:
default_lang:
type: text
label: PLUGIN_ADMIN.SITE_DEFAULT_LANG
- size: vsmall
+ size: x-small
placeholder: PLUGIN_ADMIN.SITE_DEFAULT_LANG_PLACEHOLDER
help: PLUGIN_ADMIN.SITE_DEFAULT_LANG_HELP
diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml
index 6aa0d6012..4a7f69849 100644
--- a/system/blueprints/config/system.yaml
+++ b/system/blueprints/config/system.yaml
@@ -102,7 +102,7 @@ form:
pages.order.by:
type: select
- size: long
+ size: large
classes: fancy
label: PLUGIN_ADMIN.DEFAULT_ORDERING
help: PLUGIN_ADMIN.DEFAULT_ORDERING_HELP
@@ -155,6 +155,7 @@ form:
pages.append_url_extension:
type: text
+ size: x-small
placeholder: "e.g. .html"
label: PLUGIN_ADMIN.APPEND_URL_EXT
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
@@ -856,13 +857,12 @@ form:
fields:
images.default_image_quality:
- type: text
+ type: range
append: '%'
label: PLUGIN_ADMIN.DEFAULT_IMAGE_QUALITY
help: PLUGIN_ADMIN.DEFAULT_IMAGE_QUALITY_HELP
classes: x-small
validate:
- type: number
min: 1
max: 100
@@ -1057,6 +1057,19 @@ form:
fopen: PLUGIN_ADMIN.FOPEN
curl: PLUGIN_ADMIN.CURL
+ gpm.official_gpm_only:
+ type: toggle
+ label: PLUGIN_ADMIN.GPM_OFFICIAL_ONLY
+ highlight: auto
+ help: PLUGIN_ADMIN.GPM_OFFICIAL_ONLY_HELP
+ highlight: 1
+ options:
+ 1: PLUGIN_ADMIN.YES
+ 0: PLUGIN_ADMIN.NO
+ default: true
+ validate:
+ type: bool
+
gpm.verify_peer:
type: toggle
label: PLUGIN_ADMIN.GPM_VERIFY_PEER
diff --git a/system/blueprints/pages/default.yaml b/system/blueprints/pages/default.yaml
index 4b96ac6a2..0806ba24f 100644
--- a/system/blueprints/pages/default.yaml
+++ b/system/blueprints/pages/default.yaml
@@ -117,17 +117,6 @@ form:
title: PLUGIN_ADMIN.SETTINGS
underline: true
- ordering:
- type: toggle
- label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
- help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
- highlight: 1
- options:
- 1: PLUGIN_ADMIN.ENABLED
- 0: PLUGIN_ADMIN.DISABLED
- validate:
- type: bool
-
folder:
type: text
label: PLUGIN_ADMIN.FOLDER_NAME
@@ -165,9 +154,20 @@ form:
title: PLUGIN_ADMIN.ORDERING
underline: true
+ ordering:
+ type: toggle
+ label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
+ help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
+ highlight: 1
+ options:
+ 1: PLUGIN_ADMIN.ENABLED
+ 0: PLUGIN_ADMIN.DISABLED
+ validate:
+ type: bool
+
order:
type: order
- label: PLUGIN_ADMIN.PAGE_ORDER
+ label: PLUGIN_ADMIN.SORTABLE_PAGES
sitemap:
overrides:
@@ -291,6 +291,18 @@ form:
validate:
type: bool
+ header.debugger:
+ type: toggle
+ toggleable: true
+ label: PLUGIN_ADMIN.DEBUGGER
+ help: PLUGIN_ADMIN.DEBUGGER_HELP
+ highlight: 1
+ options:
+ 1: PLUGIN_ADMIN.ENABLED
+ 0: PLUGIN_ADMIN.DISABLED
+ validate:
+ type: bool
+
header.template:
type: text
toggleable: true
@@ -302,6 +314,25 @@ form:
toggleable: true
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
+ admin_only:
+ type: section
+ title: PLUGIN_ADMIN.ADMIN_SPECIFIC_OVERRIDES
+ underline: true
+
+ fields:
+
+ header.admin.children_display_order:
+ type: select
+ label: PLUGIN_ADMIN.ADMIN_CHILDREN_DISPLAY_ORDER
+ help: PLUGIN_ADMIN.ADMIN_CHILDREN_DISPLAY_ORDER_HELP
+ toggleable: true
+ classes: fancy
+ default: 'collection'
+ options:
+ 'default': 'Ordered by Folder name (default)'
+ 'collection': 'Ordered by Collection definition'
+
+
header.order_by:
type: hidden
diff --git a/system/blueprints/user/account.yaml b/system/blueprints/user/account.yaml
index ff657b4c4..7a7c82b57 100644
--- a/system/blueprints/user/account.yaml
+++ b/system/blueprints/user/account.yaml
@@ -8,6 +8,13 @@ form:
type: userinfo
size: large
+ avatar:
+ type: file
+ size: large
+ destination: 'user://accounts/avatars'
+ multiple: false
+ random_name: true
+
content:
type: section
title: PLUGIN_ADMIN.ACCOUNT
diff --git a/system/config/system.yaml b/system/config/system.yaml
index 7d4de30e0..99628151c 100644
--- a/system/config/system.yaml
+++ b/system/config/system.yaml
@@ -138,3 +138,4 @@ gpm:
proxy_url: # Configure a manual proxy URL for GPM (eg 127.0.0.1:3128)
method: 'auto' # Either 'curl', 'fopen' or 'auto'. 'auto' will try fopen first and if not available cURL
verify_peer: true # Sometimes on some systems (Windows most commonly) GPM is unable to connect because the SSL certificate cannot be verified. Disabling this setting might help.
+ official_gpm_only: true # By default GPM direct-install will only allow URLs via the official GPM proxy to ensure security
diff --git a/system/defines.php b/system/defines.php
index 387435b35..1865c871a 100644
--- a/system/defines.php
+++ b/system/defines.php
@@ -8,7 +8,7 @@
// Some standard defines
define('GRAV', true);
-define('GRAV_VERSION', '1.1.17');
+define('GRAV_VERSION', '1.2.0');
define('GRAV_TESTING', false);
define('DS', '/');
diff --git a/system/src/Grav/Common/Assets.php b/system/src/Grav/Common/Assets.php
index eeb3adabf..20b1fce26 100644
--- a/system/src/Grav/Common/Assets.php
+++ b/system/src/Grav/Common/Assets.php
@@ -1255,13 +1255,8 @@ class Assets
$old_url = $matches[2];
- // ensure this is not a data url
- if (strpos($old_url, 'data:') === 0) {
- return $matches[0];
- }
-
- // ensure this is not a remote url
- if ($this->isRemoteLink($old_url)) {
+ // Ensure link is not rooted to webserver, a data URL, or to a remote host
+ if (Utils::startsWith($old_url, '/') || Utils::startsWith($old_url, 'data:') || $this->isRemoteLink($old_url)) {
return $matches[0];
}
diff --git a/system/src/Grav/Common/Data/Validation.php b/system/src/Grav/Common/Data/Validation.php
index b597cd642..a508312d0 100644
--- a/system/src/Grav/Common/Data/Validation.php
+++ b/system/src/Grav/Common/Data/Validation.php
@@ -339,7 +339,7 @@ class Validation
protected static function filterNumber($value, array $params, array $field)
{
- return (int) $value;
+ return (string)(int)$value !== (string)(float)$value ? (float) $value : (int) $value;
}
protected static function filterDateTime($value, array $params, array $field)
@@ -585,7 +585,7 @@ class Validation
$values[$key] = array_map('trim', explode(',', $value));
} else {
$values[$key] = trim($value);
- }
+ }
}
}
diff --git a/system/src/Grav/Common/GPM/GPM.php b/system/src/Grav/Common/GPM/GPM.php
index 857dd8fc0..584adbdd7 100644
--- a/system/src/Grav/Common/GPM/GPM.php
+++ b/system/src/Grav/Common/GPM/GPM.php
@@ -9,6 +9,7 @@
namespace Grav\Common\GPM;
use Grav\Common\Grav;
+use Grav\Common\Filesystem\Folder;
use Grav\Common\Inflector;
use Grav\Common\Iterator;
use Grav\Common\Utils;
@@ -499,6 +500,151 @@ class GPM extends Iterator
return false;
}
+ /**
+ * Download the zip package via the URL
+ *
+ * @param $package_file
+ * @param $tmp
+ * @return null|string
+ */
+ public static function downloadPackage($package_file, $tmp)
+ {
+ $package = parse_url($package_file);
+ $filename = basename($package['path']);
+
+ if (Grav::instance()['config']->get('system.gpm.official_gpm_only') && $package['host'] !== 'getgrav.org') {
+ throw new \RuntimeException("Only offical GPM URLs are allowed. You can modify this behavior in the System configuration.");
+ }
+
+ $output = Response::get($package_file, []);
+
+ if ($output) {
+ Folder::mkdir($tmp);
+ file_put_contents($tmp . DS . $filename, $output);
+ return $tmp . DS . $filename;
+ }
+
+ return null;
+ }
+
+ /**
+ * Copy the local zip package to tmp
+ *
+ * @param $package_file
+ * @param $tmp
+ * @return null|string
+ */
+ public static function copyPackage($package_file, $tmp)
+ {
+ $package_file = realpath($package_file);
+
+ if (file_exists($package_file)) {
+ $filename = basename($package_file);
+ Folder::mkdir($tmp);
+ copy(realpath($package_file), $tmp . DS . $filename);
+ return $tmp . DS . $filename;
+ }
+
+ return null;
+ }
+
+ /**
+ * Try to guess the package type from the source files
+ *
+ * @param $source
+ * @return bool|string
+ */
+ public static function getPackageType($source)
+ {
+ $plugin_regex = '/^class\\s{1,}[a-zA-Z0-9]{1,}\\s{1,}extends.+Plugin/m';
+ $theme_regex = '/^class\\s{1,}[a-zA-Z0-9]{1,}\\s{1,}extends.+Theme/m';
+
+ if (
+ file_exists($source . 'system/defines.php') &&
+ file_exists($source . 'system/config/system.yaml')
+ ) {
+ return 'grav';
+ } else {
+ // must have a blueprint
+ if (!file_exists($source . 'blueprints.yaml')) {
+ return false;
+ }
+
+ // either theme or plugin
+ $name = basename($source);
+ if (Utils::contains($name, 'theme')) {
+ return 'theme';
+ } elseif (Utils::contains($name, 'plugin')) {
+ return 'plugin';
+ }
+ foreach (glob($source . "*.php") as $filename) {
+ $contents = file_get_contents($filename);
+ if (preg_match($theme_regex, $contents)) {
+ return 'theme';
+ } elseif (preg_match($plugin_regex, $contents)) {
+ return 'plugin';
+ }
+ }
+
+ // Assume it's a theme
+ return 'theme';
+ }
+ }
+
+ /**
+ * Try to guess the package name from the source files
+ *
+ * @param $source
+ * @return bool|string
+ */
+ public static function getPackageName($source)
+ {
+ foreach (glob($source . "*.yaml") as $filename) {
+ $name = strtolower(basename($filename, '.yaml'));
+ if ($name == 'blueprints') {
+ continue;
+ }
+ return $name;
+ }
+ return false;
+ }
+
+ /**
+ * Find/Parse the blueprint file
+ *
+ * @param $source
+ * @return array|bool
+ */
+ public static function getBlueprints($source)
+ {
+ $blueprint_file = $source . 'blueprints.yaml';
+ if (!file_exists($blueprint_file)) {
+ return false;
+ }
+
+ $blueprint = (array)Yaml::parse(file_get_contents($blueprint_file));
+ return $blueprint;
+ }
+
+ /**
+ * Get the install path for a name and a particular type of package
+ *
+ * @param $type
+ * @param $name
+ * @return string
+ */
+ public static function getInstallPath($type, $name)
+ {
+ $locator = Grav::instance()['locator'];
+
+ if ($type == 'theme') {
+ $install_path = $locator->findResource('themes://', false) . DS . $name;
+ } else {
+ $install_path = $locator->findResource('plugins://', false) . DS . $name;
+ }
+ return $install_path;
+ }
+
/**
* Searches for a list of Packages in the repository
* @param array $searches An array of either slugs or names
diff --git a/system/src/Grav/Common/GPM/Response.php b/system/src/Grav/Common/GPM/Response.php
index 6b3036ff7..f046352ac 100644
--- a/system/src/Grav/Common/GPM/Response.php
+++ b/system/src/Grav/Common/GPM/Response.php
@@ -189,6 +189,17 @@ class Response
return preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'));
}
+ /**
+ * Is this a remote file or not
+ *
+ * @param $file
+ * @return bool
+ */
+ public static function isRemote($file)
+ {
+ return (bool) filter_var($file, FILTER_VALIDATE_URL);
+ }
+
/**
* Progress normalized for cURL and Fopen
* Accepts a variable length of arguments passed in by stream method
diff --git a/system/src/Grav/Common/Page/Media.php b/system/src/Grav/Common/Page/Media.php
index eb12eeb1c..34396bff3 100644
--- a/system/src/Grav/Common/Page/Media.php
+++ b/system/src/Grav/Common/Page/Media.php
@@ -141,8 +141,12 @@ class Media extends AbstractMedia
foreach ($types['alternative'] as $altMedium) {
if ($altMedium['file'] != $medium) {
- $ratio = $altMedium['file']->get('width') / $medium->get('width');
- $medium->addAlternative($ratio, $altMedium['file']);
+ $altWidth = $altMedium['file']->get('width');
+ $medWidth = $medium->get('width');
+ if ($altWidth && $medWidth) {
+ $ratio = $altWidth / $medWidth;
+ $medium->addAlternative($ratio, $altMedium['file']);
+ }
}
}
}
diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php
index 010c906e1..e844a75b7 100644
--- a/system/src/Grav/Common/Page/Page.php
+++ b/system/src/Grav/Common/Page/Page.php
@@ -86,6 +86,7 @@ class Page
protected $hide_home_route;
protected $ssl;
protected $template_format;
+ protected $debugger;
/**
* @var Page Unmodified (original) version of the page. Used for copying and moving the page.
@@ -424,6 +425,9 @@ class Page
if (isset($this->header->template_format)) {
$this->template_format = $this->header->template_format;
}
+ if (isset($this->header->debugger)) {
+ $this->debugger = (bool)$this->header->debugger;
+ }
}
return $this->header;
@@ -566,7 +570,8 @@ class Page
$process_markdown = $this->shouldProcess('markdown');
- $process_twig = $this->shouldProcess('twig');
+ $process_twig = $this->shouldProcess('twig') || $this->modularTwig() ;
+
$cache_enable = isset($this->header->cache_enable) ? $this->header->cache_enable : $config->get('system.cache.enabled',
true);
$twig_first = isset($this->header->twig_first) ? $this->header->twig_first : $config->get('system.pages.twig_first',
@@ -799,6 +804,9 @@ class Page
if ($name == 'folder') {
return preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder);
}
+ if ($name == 'slug') {
+ return $this->slug();
+ }
if ($name == 'name') {
$language = $this->language() ? '.' . $this->language() : '';
$name_val = str_replace($language . '.md', '', $this->name());
@@ -882,12 +890,12 @@ class Page
/**
* Save page if there's a file assigned to it.
*
- * @param bool $reorder Internal use.
+ * @param bool|mixed $reorder Internal use.
*/
public function save($reorder = true)
{
- // Perform move, copy or reordering if needed.
- $this->doRelocation($reorder);
+ // Perform move, copy [or reordering] if needed.
+ $this->doRelocation();
$file = $this->file();
if ($file) {
@@ -896,6 +904,13 @@ class Page
$file->markdown($this->raw_content);
$file->save();
}
+
+ // Perform reorder if required
+ if ($reorder && is_array($reorder)) {
+ $this->doReorder($reorder);
+ }
+
+ $this->_original = null;
}
/**
@@ -1208,7 +1223,7 @@ class Page
$this->expires = $var;
}
- return empty($this->expires) ? Grav::instance()['config']->get('system.pages.expires') : $this->expires;
+ return !isset($this->expires) ? Grav::instance()['config']->get('system.pages.expires') : $this->expires;
}
/**
@@ -1373,6 +1388,20 @@ class Page
return $this->process;
}
+ /**
+ * Returns the state of the debugger override etting for this page
+ *
+ * @return mixed
+ */
+ public function debugger()
+ {
+ if (isset($this->debugger) && $this->debugger === false) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
/**
* Function to merge page metadata tags and build an array of Metadata objects
* that can then be rendered in the page.
@@ -2027,7 +2056,6 @@ class Page
if ($var !== null) {
$this->modular_twig = (bool)$var;
if ($var) {
- $this->process['twig'] = true;
$this->visible(false);
// some routable logic
if (empty($this->header->routable)) {
@@ -2560,6 +2588,16 @@ class Page
return $file && $file->exists();
}
+ /**
+ * Returns whether or not the current folder exists
+ *
+ * @return bool
+ */
+ public function folderExists()
+ {
+ return file_exists($this->path());
+ }
+
/**
* Cleans the path.
*
@@ -2578,65 +2616,62 @@ class Page
}
/**
- * Moves or copies the page in filesystem.
+ * Reorders all siblings according to a defined order
*
- * @internal
- *
- * @param bool $reorder
- *
- * @throws Exception
+ * @param $new_order
*/
- protected function doRelocation($reorder)
+ protected function doReorder($new_order)
{
if (!$this->_original) {
return;
}
- // Do reordering.
- if ($reorder && $this->order() != $this->_original->order()) {
- /** @var Pages $pages */
- $pages = Grav::instance()['pages'];
+ $pages = Grav::instance()['pages'];
+ $pages->init();
- $parent = $this->parent();
+ $this->_original->path($this->path());
- // Extract visible children from the parent page.
- $list = [];
- /** @var Page $page */
- foreach ($parent->children()->visible() as $page) {
- if ($page->order()) {
- $list[$page->slug] = $page->path();
- }
- }
+ $siblings = $this->parent()->children();
+ $siblings->order('slug', 'asc', $new_order);
- // If page was moved, take it out of the list.
- if ($this->_action == 'move') {
- unset($list[$this->slug()]);
- }
+ $counter = 0;
- $list = array_values($list);
+ // Reorder all moved pages.
+ foreach ($siblings as $slug => $page) {
+ $order = intval(trim($page->order(),'.'));
+ $counter++;
- // Then add it back to the new location (if needed).
- if ($this->order()) {
- array_splice($list, min($this->order() - 1, count($list)), 0, [$this->path()]);
- }
-
- // Reorder all moved pages.
- foreach ($list as $order => $path) {
- if ($path == $this->path()) {
+ if ($order) {
+ if ($page->path() == $this->path() && $this->folderExists()) {
// Handle current page; we do want to change ordering number, but nothing else.
- $this->order($order + 1);
+ $this->order($counter);
+ $this->save(false);
} else {
// Handle all the other pages.
- $page = $pages->get($path);
-
- if ($page && $page->exists() && !$page->_action && $page->order() != $order + 1) {
- $page = $page->move($parent);
- $page->order($order + 1);
+ $page = $pages->get($page->path());
+ if ($page && $page->folderExists() && !$page->_action) {
+ $page = $page->move($this->parent());
+ $page->order($counter);
$page->save(false);
}
}
}
}
+ }
+
+ /**
+ * Moves or copies the page in filesystem.
+ *
+ * @internal
+ *
+ * @throws Exception
+ */
+ protected function doRelocation()
+ {
+ if (!$this->_original) {
+ return;
+ }
+
if (is_dir($this->_original->path())) {
if ($this->_action == 'move') {
Folder::move($this->_original->path(), $this->path());
@@ -2652,7 +2687,6 @@ class Page
}
}
- $this->_original = null;
}
protected function setPublishState()
diff --git a/system/src/Grav/Common/Service/PageServiceProvider.php b/system/src/Grav/Common/Service/PageServiceProvider.php
index 0db18a298..a363411a1 100644
--- a/system/src/Grav/Common/Service/PageServiceProvider.php
+++ b/system/src/Grav/Common/Service/PageServiceProvider.php
@@ -39,6 +39,11 @@ class PageServiceProvider implements ServiceProviderInterface
/** @var Language $language */
$language = $c['language'];
+ // some debugger override logic
+ if ($page->debugger() === false) {
+ Grav::instance()['debugger']->enabled(false);
+ }
+
if ($c['config']->get('system.force_ssl')) {
if (!isset($_SERVER['HTTPS']) || $_SERVER["HTTPS"] != "on") {
$url = "https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
diff --git a/system/src/Grav/Common/Themes.php b/system/src/Grav/Common/Themes.php
index e1db8d7db..4ce6162b7 100644
--- a/system/src/Grav/Common/Themes.php
+++ b/system/src/Grav/Common/Themes.php
@@ -311,17 +311,23 @@ class Themes extends Iterator
*/
protected function autoloadTheme($class)
{
- /** @var UniformResourceLocator $locator */
- $locator = $this->grav['locator'];
-
$prefix = "Grav\\Theme";
if (false !== strpos($class, $prefix)) {
// Remove prefix from class
$class = substr($class, strlen($prefix));
- // Replace namespace tokens to directory separators
+ // Try Old style theme classes
$path = strtolower(ltrim(preg_replace('#\\\|_(?!.+\\\)#', '/', $class), '/'));
- $file = $locator->findResource("themes://{$path}/{$path}.php");
+ $file = $this->grav['locator']->findResource("themes://{$path}/{$path}.php");
+
+ // Load class
+ if (file_exists($file)) {
+ return include_once($file);
+ }
+
+ // Replace namespace tokens to directory separators
+ $path = $this->grav['inflector']->hyphenize(ltrim($class,"\\"));
+ $file = $this->grav['locator']->findResource("themes://{$path}/{$path}.php");
// Load class
if (file_exists($file)) {
diff --git a/system/src/Grav/Common/Twig/Twig.php b/system/src/Grav/Common/Twig/Twig.php
index 9ef9e3e6d..7eec5b775 100644
--- a/system/src/Grav/Common/Twig/Twig.php
+++ b/system/src/Grav/Common/Twig/Twig.php
@@ -11,6 +11,7 @@ namespace Grav\Common\Twig;
use Grav\Common\Grav;
use Grav\Common\Config\Config;
use Grav\Common\Language\Language;
+use Grav\Common\Language\LanguageCodes;
use Grav\Common\Page\Page;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RocketTheme\Toolbox\Event\Event;
@@ -173,7 +174,7 @@ class Twig
'theme_dir' => $locator->findResource('theme://'),
'theme_url' => $this->grav['base_url'] . '/' . $locator->findResource('theme://', false),
'html_lang' => $this->grav['language']->getActive() ?: $config->get('site.default_lang', 'en'),
-
+ 'language_codes' => new LanguageCodes,
];
}
}
@@ -229,25 +230,22 @@ class Twig
$twig_vars['header'] = $item->header();
$local_twig = clone($this->twig);
- $modular_twig = $item->modularTwig();
- $process_twig = isset($item->header()->process['twig']) ? $item->header()->process['twig'] : false;
-
- $output = '';
try {
// Process Modular Twig
- if ($modular_twig) {
+ if ($item->modularTwig()) {
$twig_vars['content'] = $content;
$template = $item->template() . TEMPLATE_EXT;
$output = $content = $local_twig->render($template, $twig_vars);
}
// Process in-page Twig
- if (!$modular_twig || ($modular_twig && $process_twig)) {
+ if ($item->shouldProcess('twig')) {
$name = '@Page:' . $item->path();
$this->setTemplate($name, $content);
$output = $local_twig->render($name, $twig_vars);
}
+
} catch (\Twig_Error_Loader $e) {
throw new \RuntimeException($e->getRawMessage(), 404, $e);
}
diff --git a/system/src/Grav/Common/Twig/TwigExtension.php b/system/src/Grav/Common/Twig/TwigExtension.php
index fff032e9c..e12fa9a4c 100644
--- a/system/src/Grav/Common/Twig/TwigExtension.php
+++ b/system/src/Grav/Common/Twig/TwigExtension.php
@@ -104,7 +104,8 @@ class TwigExtension extends \Twig_Extension
new \Twig_simpleFunction('authorize', [$this, 'authorize']),
new \Twig_SimpleFunction('debug', [$this, 'dump'], ['needs_context' => true, 'needs_environment' => true]),
new \Twig_SimpleFunction('dump', [$this, 'dump'], ['needs_context' => true, 'needs_environment' => true]),
- new \Twig_SimpleFunction('evaluate', [$this, 'evaluateFunc']),
+ new \Twig_SimpleFunction('evaluate', [$this, 'evaluateStringFunc'], ['needs_context' => true, 'needs_environment' => true]),
+ new \Twig_SimpleFunction('evaluate_twig', [$this, 'evaluateTwigFunc'], ['needs_context' => true, 'needs_environment' => true]),
new \Twig_SimpleFunction('gist', [$this, 'gistFunc']),
new \Twig_SimpleFunction('nonce_field', [$this, 'nonceFieldFunc']),
new \Twig_simpleFunction('random_string', [$this, 'randomStringFunc']),
@@ -432,9 +433,10 @@ class TwigExtension extends \Twig_Extension
/**
* @param $string
*
+ * @param bool $block Block or Line processing
* @return mixed|string
*/
- public function markdownFilter($string)
+ public function markdownFilter($string, $block = true)
{
$page = $this->grav['page'];
$defaults = $this->config->get('system.pages.markdown');
@@ -446,7 +448,12 @@ class TwigExtension extends \Twig_Extension
$parsedown = new Parsedown($page, $defaults);
}
- $string = $parsedown->text($string);
+ if ($block) {
+ $string = $parsedown->text($string);
+ } else {
+ $string = $parsedown->line($string);
+ }
+
return $string;
}
@@ -563,15 +570,22 @@ class TwigExtension extends \Twig_Extension
$domain = true;
}
+ if (Grav::instance()['uri']->isExternal($input)) {
+ return $input;
+ }
- if (strpos((string)$input, '://')) {
+ $input = ltrim((string)$input, '/');
+
+ if (Utils::contains((string)$input, '://')) {
/** @var UniformResourceLocator $locator */
$locator = $this->grav['locator'];
+
+
// Get relative path to the resource (or false if not found).
- $resource = $locator->findResource((string)$input, false);
+ $resource = $locator->findResource($input, false);
} else {
- $resource = (string)$input;
+ $resource = $input;
}
/** @var Uri $uri */
@@ -581,22 +595,51 @@ class TwigExtension extends \Twig_Extension
}
/**
- * Evaluate a string
+ * This function will evaluate Twig $twig through the $environment, and return its results.
*
- * @example {{ evaluate('grav.language.getLanguage') }}
- *
- * @param string $input String to be evaluated
- *
- * @return string Returns the evaluated string
+ * @param \Twig_Environment $environment
+ * @param array $context
+ * @param string $twig
+ * @return mixed
*/
- public function evaluateFunc($input)
- {
- if (!$input) { //prevent an obscure Twig error if $input is not set
- $input = '""';
- }
- return $this->grav['twig']->processString("{{ $input }}");
+ public function evaluateTwigFunc( \Twig_Environment $environment, $context, $twig ) {
+ $loader = $environment->getLoader( );
+
+ $parsed = $this->parseString( $environment, $context, $twig );
+
+ $environment->setLoader( $loader );
+ return $parsed;
}
+ /**
+ * This function will evaluate a $string through the $environment, and return its results.
+ *
+ * @param \Twig_Environment $environment
+ * @param $context
+ * @param $string
+ * @return mixed
+ */
+ public function evaluateStringFunc(\Twig_Environment $environment, $context, $string )
+ {
+ $parsed = $this->evaluateTwigFunc($environment, $context, "{{ $string }}");
+ return $parsed;
+ }
+
+ /**
+ * Sets the parser for the environment to Twig_Loader_String, and parsed the string $string.
+ *
+ * @param \Twig_Environment $environment
+ * @param array $context
+ * @param string $string
+ * @return string
+ */
+ protected function parseString( \Twig_Environment $environment, $context, $string ) {
+ $environment->setLoader( new \Twig_Loader_String( ) );
+ return $environment->render( $string, $context );
+ }
+
+
+
/**
* Based on Twig_Extension_Debug / twig_var_dump
* (c) 2011 Fabien Potencier
@@ -778,7 +821,7 @@ class TwigExtension extends \Twig_Extension
*/
public function nonceFieldFunc($action, $nonceParamName = 'nonce')
{
- $string = '';
+ $string = '';
return $string;
}
diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php
index dd8308db6..e1383688c 100644
--- a/system/src/Grav/Common/Uri.php
+++ b/system/src/Grav/Common/Uri.php
@@ -727,7 +727,7 @@ class Uri
*
* @return boolean is eternal state
*/
- public function isExternal($url)
+ public static function isExternal($url)
{
if (Utils::startsWith($url, 'http')) {
return true;
@@ -1086,4 +1086,20 @@ class Uri
return $urlWithNonce;
}
+
+ /**
+ * Is the passed in URL a valid URL?
+ *
+ * @param $url
+ * @return bool
+ */
+ public static function isValidUrl($url)
+ {
+ $regex = '/^(?:(https?|ftp|telnet):)?\/\/((?:[a-z0-9@:.-]|%[0-9A-F]{2}){3,})(?::(\d+))?((?:\/(?:[a-z0-9-._~!$&\'\(\)\*\+\,\;\=\:\@]|%[0-9A-F]{2})*)*)(?:\?((?:[a-z0-9-._~!$&\'\(\)\*\+\,\;\=\:\/?@]|%[0-9A-F]{2})*))?(?:#((?:[a-z0-9-._~!$&\'\(\)\*\+\,\;\=\:\/?@]|%[0-9A-F]{2})*))?/';
+ if (preg_match($regex, $url)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/system/src/Grav/Common/User/User.php b/system/src/Grav/Common/User/User.php
index fcc8f6c43..d0c35eb31 100644
--- a/system/src/Grav/Common/User/User.php
+++ b/system/src/Grav/Common/User/User.php
@@ -57,14 +57,14 @@ class User extends Data
/**
* Find a user by username, email, etc
*
- * @param $query the query to search for
+ * @param string $query the query to search for
* @param array $fields the fields to search
* @return User
*/
public static function find($query, $fields = ['username', 'email'])
{
$account_dir = Grav::instance()['locator']->findResource('account://');
- $files = array_diff(scandir($account_dir), ['.', '..']);
+ $files = $account_dir ? array_diff(scandir($account_dir), ['.', '..']) : [];
// Try with username first, you never know!
if (in_array('username', $fields)) {
@@ -100,7 +100,7 @@ class User extends Data
public static function remove($username)
{
$file_path = Grav::instance()['locator']->findResource('account://' . $username . YAML_EXT);
- if (file_exists($file_path) && unlink($file_path)) {
+ if ($file_path && unlink($file_path)) {
return true;
}
@@ -239,4 +239,20 @@ class User extends Data
{
return $this->authorize($action);
}
+
+ /**
+ * Return the User's avatar URL
+ *
+ * @return string
+ */
+ public function avatarUrl()
+ {
+ if ($this->avatar) {
+ $avatar = $this->avatar;
+ $avatar = array_shift($avatar);
+ return Grav::instance()['base_url'] . '/' . $avatar['path'];
+ } else {
+ return 'https://www.gravatar.com/avatar/' . md5($this->email);
+ }
+ }
}
diff --git a/system/src/Grav/Console/Gpm/DirectInstallCommand.php b/system/src/Grav/Console/Gpm/DirectInstallCommand.php
index e23712e9f..679d5c635 100644
--- a/system/src/Grav/Console/Gpm/DirectInstallCommand.php
+++ b/system/src/Grav/Console/Gpm/DirectInstallCommand.php
@@ -9,14 +9,13 @@
namespace Grav\Console\Gpm;
use Grav\Common\Grav;
-use Grav\Common\Utils;
use Grav\Common\Filesystem\Folder;
+use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Installer;
use Grav\Common\GPM\Response;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Question\ConfirmationQuestion;
-use Symfony\Component\Yaml\Yaml;
class DirectInstallCommand extends ConsoleCommand
{
@@ -32,7 +31,7 @@ class DirectInstallCommand extends ConsoleCommand
->addArgument(
'package-file',
InputArgument::REQUIRED,
- 'The local location or remote URL to an installable package file'
+ 'Installable package local or remote . Can install specific version'
)
->setDescription("Installs Grav, plugin, or theme directly from a file or a URL")
->setHelp('The direct-install command installs Grav, plugin, or theme directly from a file or a URL');
@@ -63,10 +62,30 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->writeln("Preparing to install " . $package_file . "");
- if ($this->isRemote($package_file)) {
- $zip = $this->downloadPackage($package_file, $tmp_zip);
+ if (Response::isRemote($package_file)) {
+ $this->output->write(" |- Downloading package... 0%");
+ try {
+ $zip = GPM::downloadPackage($package_file, $tmp_zip);
+ } catch (\RuntimeException $e) {
+ $this->output->writeln('');
+ $this->output->writeln(" `- ERROR: " . $e->getMessage() . "");
+ $this->output->writeln('');
+ exit;
+ }
+
+ if ($zip) {
+ $this->output->write("\x0D");
+ $this->output->write(" |- Downloading package... 100%");
+ $this->output->writeln('');
+ }
} else {
- $zip = $this->copyPackage($package_file, $tmp_zip);
+ $this->output->write(" |- Copying package... 0%");
+ $zip = GPM::copyPackage($package_file, $tmp_zip);
+ if ($zip) {
+ $this->output->write("\x0D");
+ $this->output->write(" |- Copying package... 100%");
+ $this->output->writeln('');
+ }
}
if (file_exists($zip)) {
@@ -85,7 +104,7 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->writeln(" |- Extracting package... ok");
- $type = $this->getPackageType($extracted);
+ $type = GPM::getPackageType($extracted);
if (!$type) {
$this->output->writeln(" '- ERROR: Not a valid Grav package");
@@ -93,7 +112,7 @@ class DirectInstallCommand extends ConsoleCommand
exit;
}
- $blueprint = $this->getBlueprints($extracted);
+ $blueprint = GPM::getBlueprints($extracted);
if ($blueprint) {
if (isset($blueprint['dependencies'])) {
$depencencies = [];
@@ -137,7 +156,7 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->write(" |- Installing package... ");
Installer::install($zip, GRAV_ROOT, ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true], $extracted);
} else {
- $name = $this->getPackageName($extracted);
+ $name = GPM::getPackageName($extracted);
if (!$name) {
$this->output->writeln("ERROR: Name could not be determined. Please specify with --name|-n");
@@ -145,7 +164,7 @@ class DirectInstallCommand extends ConsoleCommand
exit;
}
- $install_path = $this->getInstallPath($type, $name);
+ $install_path = GPM::getInstallPath($type, $name);
$is_update = file_exists($install_path);
$this->output->write(" |- Checking destination... ");
@@ -173,7 +192,7 @@ class DirectInstallCommand extends ConsoleCommand
$this->output->write("\x0D");
if(Installer::lastErrorCode()) {
- $this->output->writeln(" '- Installation failed or aborted.");
+ $this->output->writeln(" '- " . Installer::lastErrorMsg() . "");
$this->output->writeln('');
} else {
$this->output->writeln(" |- Installing package... ok");
@@ -193,186 +212,4 @@ class DirectInstallCommand extends ConsoleCommand
return true;
}
-
- /**
- * Get the install path for a name and a particular type of package
- *
- * @param $type
- * @param $name
- * @return string
- */
- protected function getInstallPath($type, $name)
- {
- $locator = Grav::instance()['locator'];
-
- if ($type == 'theme') {
- $install_path = $locator->findResource('themes://', false) . DS . $name;
- } else {
- $install_path = $locator->findResource('plugins://', false) . DS . $name;
- }
- return $install_path;
- }
-
- /**
- * Try to guess the package name from the source files
- *
- * @param $source
- * @return bool|string
- */
- protected function getPackageName($source)
- {
- foreach (glob($source . "*.yaml") as $filename) {
- $name = strtolower(basename($filename, '.yaml'));
- if ($name == 'blueprints') {
- continue;
- }
- return $name;
- }
- return false;
- }
-
- /**
- * Try to guess the package type from the source files
- *
- * @param $source
- * @return bool|string
- */
- protected function getPackageType($source)
- {
- $plugin_regex = '/^class\\s{1,}[a-zA-Z0-9]{1,}\\s{1,}extends.+Plugin/m';
- $theme_regex = '/^class\\s{1,}[a-zA-Z0-9]{1,}\\s{1,}extends.+Theme/m';
-
- if (
- file_exists($source . 'system/defines.php') &&
- file_exists($source . 'system/config/system.yaml')
- ) {
- return 'grav';
- } else {
- // must have a blueprint
- if (!file_exists($source . 'blueprints.yaml')) {
- return false;
- }
-
- // either theme or plugin
- $name = basename($source);
- if (Utils::contains($name, 'theme')) {
- return 'theme';
- } elseif (Utils::contains($name, 'plugin')) {
- return 'plugin';
- }
- foreach (glob($source . "*.php") as $filename) {
- $contents = file_get_contents($filename);
- if (preg_match($theme_regex, $contents)) {
- return 'theme';
- } elseif (preg_match($plugin_regex, $contents)) {
- return 'plugin';
- }
- }
-
- // Assume it's a theme
- return 'theme';
- }
- }
-
- /**
- * Determine if this is a local or a remote file
- *
- * @param $file
- * @return bool
- */
- protected function isRemote($file)
- {
- return (bool) filter_var($file, FILTER_VALIDATE_URL);
- }
-
- /**
- * Find/Parse the blueprint file
- *
- * @param $source
- * @return array|bool
- */
- protected function getBlueprints($source)
- {
- $blueprint_file = $source . 'blueprints.yaml';
- if (!file_exists($blueprint_file)) {
- return false;
- }
-
- $blueprint = (array)Yaml::parse(file_get_contents($blueprint_file));
- return $blueprint;
- }
-
- /**
- * Download the zip package via the URL
- *
- * @param $package_file
- * @param $tmp
- * @return null|string
- */
- private function downloadPackage($package_file, $tmp)
- {
- $this->output->write(" |- Downloading package... 0%");
-
- $package = parse_url($package_file);
-
-
- $filename = basename($package['path']);
- $output = Response::get($package_file, [], [$this, 'progress']);
-
- if ($output) {
- Folder::mkdir($tmp);
-
- $this->output->write("\x0D");
- $this->output->write(" |- Downloading package... 100%");
- $this->output->writeln('');
-
- file_put_contents($tmp . DS . $filename, $output);
-
- return $tmp . DS . $filename;
- }
-
- return null;
-
- }
-
- /**
- * Copy the local zip package to tmp
- *
- * @param $package_file
- * @param $tmp
- * @return null|string
- */
- private function copyPackage($package_file, $tmp)
- {
- $this->output->write(" |- Copying package... 0%");
-
- $package_file = realpath($package_file);
-
- if (file_exists($package_file)) {
- $filename = basename($package_file);
-
- Folder::mkdir($tmp);
-
- $this->output->write("\x0D");
- $this->output->write(" |- Copying package... 100%");
- $this->output->writeln('');
-
- copy(realpath($package_file), $tmp . DS . $filename);
-
- return $tmp . DS . $filename;
- }
-
- return null;
-
- }
-
- /**
- * @param $progress
- */
- public function progress($progress)
- {
- $this->output->write("\x0D");
- $this->output->write(" |- Downloading package... " . str_pad($progress['percent'], 5, " ",
- STR_PAD_LEFT) . '%');
- }
}
diff --git a/system/src/Grav/Console/Gpm/InstallCommand.php b/system/src/Grav/Console/Gpm/InstallCommand.php
index abf5e8163..bd01ead2b 100644
--- a/system/src/Grav/Console/Gpm/InstallCommand.php
+++ b/system/src/Grav/Console/Gpm/InstallCommand.php
@@ -80,7 +80,7 @@ class InstallCommand extends ConsoleCommand
->addArgument(
'package',
InputArgument::IS_ARRAY | InputArgument::REQUIRED,
- 'The package(s) that are desired to be installed. Use the "index" command for a list of packages'
+ 'Package(s) to install. Use "bin/gpm index" to list packages. Use "bin/gpm direct-install" to install a specific version'
)
->setDescription("Performs the installation of plugins and themes")
->setHelp('The install command allows to install plugins and themes');
@@ -563,6 +563,7 @@ class InstallCommand extends ConsoleCommand
$tmp_dir = Grav::instance()['locator']->findResource('tmp://', true, true);
$this->tmp = $tmp_dir . '/Grav-' . uniqid();
$filename = $package->slug . basename($package->zipball_url);
+ $filename = preg_replace('/[\\\\\/:"*?&<>|]+/mi', '-', $filename);
$query = '';
if ($package->premium) {
diff --git a/tests/unit/Grav/Common/Markdown/ParsedownTest.php b/tests/unit/Grav/Common/Markdown/ParsedownTest.php
index bbd1cad3a..e73e11f01 100644
--- a/tests/unit/Grav/Common/Markdown/ParsedownTest.php
+++ b/tests/unit/Grav/Common/Markdown/ParsedownTest.php
@@ -675,6 +675,8 @@ class ParsedownTest extends \Codeception\TestCase\Test
{
$this->uri->initializeWithURL('http://testing.dev/item2/item2-2')->init();
+ $this->assertSame('Anchor Class
',
+ $this->parsedown->text('[Anchor Class](?classes=button#something)'));
$this->assertSame('Relative Class
',
$this->parsedown->text('[Relative Class](../item2-3?classes=button)'));
$this->assertSame('Relative ID
',