Compare commits

...

139 Commits

Author SHA1 Message Date
Andy Miller
50c6e81c09 Merge branch 'release/1.0.0-rc.5' 2015-11-20 17:54:39 -07:00
Andy Miller
2a0a9a225c version update 2015-11-20 17:54:28 -07:00
Andy Miller
aee92b58c7 Updated composer.phar 2015-11-20 17:34:34 -07:00
Andy Miller
16db950009 composer updates 2015-11-20 17:34:02 -07:00
Andy Miller
bde33e7188 Lighttpd/Lightly configuration file - Thanks @Mr3ase 2015-11-20 14:59:58 -07:00
Djamil Legato
267efbe164 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-20 12:40:52 -08:00
Djamil Legato
f9e137c994 Added pad filter for strings (uses str_pad) 2015-11-20 12:40:48 -08:00
Andy Miller
e7f9751403 add new Page.relativePagePath helper method 2015-11-20 08:08:39 -07:00
Djamil Legato
06d663680c Removed unused label 2015-11-19 20:05:29 -08:00
Djamil Legato
1bbdca5032 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-19 18:07:40 -08:00
Djamil Legato
c1654a988e Fixed deprecated message 2015-11-19 18:07:16 -08:00
Andy Miller
18a540c867 Don't set a default hash in system.yaml 2015-11-19 18:56:05 -07:00
Andy Miller
99fc8df322 old command was called newuser not new-user, also pointed to login plugin now. 2015-11-19 18:30:31 -07:00
Flavio Copes
2d21cb8b1e Simplify, clear slashes for all nonces automatically. Remove Utils:: getNonceForGetRequest methoid
The reason is, we need to get the nonce in JavaScript and we can simply
use the one in the form, made for POST requests
2015-11-19 23:23:32 +01:00
Flavio Copes
d8008654b9 Add a new Utils::getNonceForGetRequest() method, and use that in Uri:: addNonce() 2015-11-19 22:44:10 +01:00
Andy Miller
146295fb1e fix for state check if user was already logged in without state 2015-11-19 13:43:15 -07:00
Djamil Legato
63e083ea37 Implemented new state check for accounts. If an account state is set to disabled no actions will be allowed 2015-11-18 18:31:19 -08:00
Andy Miller
b1630feb5d Disable time limit in case of slow downloads: #385 2015-11-18 19:04:57 -07:00
Andy Miller
1185a91c90 Fix for Media using absolute URLs internally causing breakages in functionality: #401 2015-11-18 18:39:30 -07:00
Andy Miller
dce6d7894b Added form blueprints for new append_url_extension field in system.yaml and page headers 2015-11-18 17:35:07 -07:00
Andy Miller
375ee0d1fa remove version from auto-generated generator tag 2015-11-18 17:17:53 -07:00
Andy Miller
ce0574f897 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-18 17:13:31 -07:00
Andy Miller
c515111446 Don't check valid media list if its' in whitelist 2015-11-18 17:13:22 -07:00
Djamil Legato
7d6393628e Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-18 16:12:12 -08:00
Djamil Legato
24fde7261a Deprecated: bin/grav new-user is now deprecated in favor of bin/plugin admin new-user 2015-11-18 16:12:08 -08:00
Djamil Legato
3d922abf1a Fixed listing duplicate plugins when multiple commands present. 2015-11-18 16:11:44 -08:00
Andy Miller
7f1d3a94fe Support default case of allowing all valid media types. Config option replaces with a whitelist of types supported. #452 2015-11-18 15:52:01 -07:00
Andy Miller
3d774b7585 moved fallback types to media 2015-11-18 15:50:46 -07:00
Djamil Legato
b0083548b6 Rearranged properly changelog entries 2015-11-18 11:55:34 -08:00
Djamil Legato
905dae3b16 Updated changelog 2015-11-18 11:51:16 -08:00
Djamil Legato
d79979371b Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-18 11:47:26 -08:00
Flavio Copes
c4bff94f7d Merge pull request #454 from diomed/patch-1
Croatian translation
2015-11-18 20:43:07 +01:00
Kruno H
7c4fd3858c Croatian translation 2015-11-18 20:35:23 +01:00
Djamil Legato
3b9af8883d Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-18 10:43:02 -08:00
Djamil Legato
29b34d7de0 Listing all plugins with CLI available. Better helper when empty arguments 2015-11-18 10:40:06 -08:00
Flavio Copes
5193551d04 Fix date representation in system config
Fixes https://github.com/getgrav/grav-plugin-admin/issues/278
2015-11-18 17:15:18 +01:00
Matias Griese
d2660e0755 Fixed gzip compression making it to work correctly with all servers and browsers 2015-11-18 18:14:35 +02:00
Flavio Copes
2d8ac27fdd Merge pull request #451 from yaman-jain/docfixes
PhpDoc
2015-11-18 14:49:58 +01:00
yaman-jain
49a5b38589 PhpDoc: callback definition as per #451 2015-11-18 16:01:19 +05:30
yaman-jain
6e2f792bb9 Merge branch 'develop' into docfixes 2015-11-18 15:55:25 +05:30
Djamil Legato
da098fd46a Implemented support for Plugins to hook into Grav CLI via bin/plugin <plugin-name> 2015-11-17 19:33:55 -08:00
Djamil Legato
3e081b340f Cleaned up Console commands, now extending Grav's own ConsoleCommand class 2015-11-17 19:31:13 -08:00
Djamil Legato
698015a03d Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-17 19:12:45 -08:00
Djamil Legato
000a10f936 Added check in Plugins::get method to ensure a plugin exists 2015-11-17 18:36:08 -08:00
Flavio Copes
c764e31c8a Merge pull request #448 from bovisp/patch-3
Added form validation translations
2015-11-17 22:32:38 +01:00
Flavio Copes
c18021d52a Merge pull request #450 from bovisp/patch-2
Added a translation for "Invalid input in " text
2015-11-17 22:32:15 +01:00
Flavio Copes
3d0cc67415 Merge pull request #449 from bovisp/patch-1
Added a translation for "Validation failed:" text
2015-11-17 22:32:00 +01:00
Paul Bovis
3f94a6fda9 moved $language variable inside catch statement
As requested
2015-11-17 14:25:51 -07:00
yaman-jain
7f0eefbde5 updated/added PhpDoc for methods 2015-11-18 02:32:44 +05:30
Paul Bovis
280377985f Added form validation translations
These will need to be translated into other languages.
2015-11-17 11:57:15 -07:00
Paul Bovis
d5b3f070a5 Added a translation for "Invalid input in " text
The English phrase "Invalid input in " was hardcoded at line 40. I created a new translation 'FORM.INVALID_INPUT' and placed it in /system/languages/en.yaml. It will need to be translated into other languages by others.
2015-11-17 11:55:31 -07:00
Paul Bovis
3505ef046d Added a translation for "Validation failed:" text
The English term "Validation failed:" was hard coded on line 83. Instead, I created a translation and placed this at /system/languages/en.yaml. It will need to be translated into other languages by others.
2015-11-17 11:50:47 -07:00
Flavio Copes
a6bc565356 Replace forward slashes automatically to avoid problems when used in GET request 2015-11-17 11:59:30 +01:00
Flavio Copes
a1ee3cf4e4 Avoid using our own hash, let PHP use its own for password_hash, fix #445 2015-11-17 11:59:02 +01:00
Andy Miller
e96445abe3 Added append_url_extension option to system/page headers. 2015-11-16 21:33:24 -07:00
Andy Miller
c22fae0d3d just added a comment 2015-11-16 21:33:01 -07:00
Flavio Copes
3cf6e8762c Merge pull request #426 from getgrav/feature/nonce
Add nonce functionality
2015-11-13 19:18:29 +01:00
Flavio Copes
f0cdd7c03e Merge branch 'develop' into feature/nonce 2015-11-13 18:24:03 +01:00
Andy Miller
5e40201888 Merge pull request #441 from yaman-jain/removePackageInterface
PackageInterface was deleted #435
2015-11-13 11:03:08 -06:00
Flavio Copes
f2c2debb28 Fix exception message when label is not set 2015-11-13 17:50:04 +01:00
Andy Miller
0e3e7497ac Fix for https://github.com/getgrav/grav-plugin-form/issues/17 2015-11-12 18:31:15 -07:00
Andy Miller
72313ac9ec Merge branch 'feature/new-imagemedium-methods' into develop 2015-11-12 17:40:21 -07:00
yaman-jain
dc80228f0b PackageInterface was deleted #435 2015-11-13 00:48:54 +05:30
Flavio Copes
a83642a7e3 Added a higherQualityAlternative () method to get the highest quality image available (3x or 2x) 2015-11-12 19:15:26 +01:00
Flavio Copes
00d8403095 Allow to get the image quality in addition to setting it 2015-11-12 19:14:52 +01:00
Matias Griese
e1ec8e9742 Fix undefined variable in Config class 2015-11-12 20:09:23 +02:00
Flavio Copes
0725af5367 Handle case login plugin disabled (thanks @hwmaier) 2015-11-12 09:17:22 +01:00
Andy Miller
65e543af02 Merge pull request #434 from yaman-jain/feature/smallfixes
remove duplicate key
2015-11-11 18:24:29 -07:00
Andy Miller
b49e8315eb Merge pull request #439 from enko/patch-1
Use PCRE_UTF8 so unicode strings don't break up.
2015-11-12 00:42:45 +01:00
Tim
c5a89112b4 Use PCRE_UTF8 so unicode strings don't break up.
The `Truncator`-class fails when the truncated text contains unicode characters with a nice exception:

    "DOMDocumentFragment::appendXML(): Entity: line 1: parser error : Input is not proper UTF-8, indicate encoding ! Bytes: 0xC3 0xE2 0x80 0xA6"

By using the `PCRE_UTF8` modifier `u` everything is UTF8 and all is fine.
2015-11-12 00:13:21 +01:00
Flavio Copes
94ec474ffa Merge branch 'develop' into feature/nonce 2015-11-11 17:47:57 +01:00
Flavio Copes
da4593fdc1 Drop commented referrer code 2015-11-11 17:13:54 +01:00
Flavio Copes
b8413cefaf Avoid having to deal with slashes in URLs 2015-11-10 17:34:23 +01:00
Flavio Copes
d3097e4fd0 Merge pull request #433 from Sommerregen/patch-3
Fixes #432 (Theme autoloading doesn't seem to work)
2015-11-10 14:32:14 +01:00
yaman-jain
51753f0716 remove unused 'use' statements 2015-11-10 18:24:01 +05:30
yaman-jain
b7ada873b8 remove duplicate key 2015-11-10 17:34:01 +05:30
Benny
ed8b08a9e4 Fixes #432 (Theme autoloading doesn't seem to work) 2015-11-10 11:19:30 +01:00
Flavio Copes
e1fdb6803d Add nonce functionality 2015-11-06 15:31:49 +01:00
Andy Miller
5cb9f2f42f Merge pull request #419 from hwmaier/feature/empty-inline-assets
Don't create <style> or <script> tags for empty inline CSS or inline JS
2015-11-06 10:08:10 +05:30
Flavio Copes
fcf48ed2e5 Merge pull request #420 from bariscelik/develop
added "Turkish" language
2015-11-05 09:16:36 +01:00
Barış ÇELİK
050512536a added "Turkish" language 2015-11-05 08:42:24 +03:00
Henrik Maier
99207fca13 Don't create <style> or <script> tags for empty inline CSS or inline JS 2015-11-05 13:37:06 +10:00
Andy Miller
77d80f12f3 Fix for untranslated validation messages #246 2015-11-02 17:28:46 -07:00
Flavio Copes
e400207a65 Fix https://github.com/getgrav/grav-plugin-admin/issues/249, password not required any more. If not set, it's not changed. If set, it's changed (if it satisfies the requirements) 2015-11-02 18:57:16 +01:00
Andy Miller
4b68036a1b Fixed assets stream for bin/grav clear 2015-11-01 20:52:14 -07:00
Henrik Maier
a95b716aa7 Return resource even if not physically present 2015-11-01 19:43:54 -07:00
Henrik Maier
dc8efded34 Use streams instead of hardcoded paths for clearCache() 2015-11-01 19:43:53 -07:00
Andy Miller
e016b17276 Revert "Use streams instead of hardcoded paths for clearCache()"
This reverts commit a86ce7cb28.
2015-11-01 19:24:46 -07:00
Andy Miller
b99876f0b4 Revert "Return resource even if not physically present"
This reverts commit b3144ee921.
2015-11-01 19:24:39 -07:00
Andy Miller
66abc842b7 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-01 18:34:41 -07:00
Andy Miller
9f36158c67 Merge pull request #405 from hwmaier/feature/trailing-slash
Added support for default routes with a trailing slash
2015-11-01 18:34:31 -07:00
Andy Miller
18c1ca3919 added 'theme' to config containing current theme configuration so now possible to just to {{ config.theme.dropdown_enabled }} #406 2015-11-01 18:32:55 -07:00
Andy Miller
0c729e5b0a latest vendor updates 2015-11-01 13:56:10 -07:00
Andy Miller
55f3b78ab1 Merge pull request #393 from hwmaier/feature/image-height-width
Support for width/height and style attributes to media and image files
2015-11-01 09:43:28 -07:00
Andy Miller
a73b796ca7 Merge pull request #407 from hwmaier/feature/enable-progressive-bug
Clear previously applied operations when doing a reset on image files to avoid calling filters twice
2015-11-01 09:42:29 -07:00
Andy Miller
bb0bca7ef1 Merge pull request #408 from hwmaier/feature/clear-cache
Use streams instead of hardcoded paths for clearCache()
2015-11-01 08:53:54 -07:00
Henrik Maier
b3144ee921 Return resource even if not physically present 2015-11-01 18:55:33 +10:00
Henrik Maier
a86ce7cb28 Use streams instead of hardcoded paths for clearCache() 2015-11-01 17:50:23 +10:00
Henrik Maier
ccf2a780b6 Clear previously applied operations when doing a reset on image files 2015-11-01 10:26:56 +10:00
Henrik Maier
b0c1dbe4b7 Added support for default routes with a trailing slash 2015-10-31 16:21:05 +10:00
Djamil Legato
ec73eef695 Updated comments for subfolders 2015-10-30 10:49:08 -07:00
Andy Miller
467d68344e added a default umask_fix property to system.yaml 2015-10-30 11:42:36 -06:00
Andy Miller
8899b3ebb8 Rewrote nginx.conf to be simpler and more in line with .htaccess 2015-10-30 11:42:08 -06:00
Andy Miller
5478cfaf9f Improved .htaccess security 2015-10-30 11:41:52 -06:00
Andy Miller
4b6a85f30a updated vendor libs 2015-10-30 11:41:03 -06:00
Andy Miller
e62ff07726 Merge branch 'release/1.0.0-rc.4' 2015-10-29 22:11:19 -06:00
Andy Miller
a045107cc7 Merge branch 'release/1.0.0-rc.4' into develop 2015-10-29 22:11:19 -06:00
Andy Miller
c97edb60a5 version update 2015-10-29 22:11:06 -06:00
Andy Miller
695793b752 Merge branch 'release/1.0.0-rc.4' 2015-10-29 21:53:48 -06:00
Andy Miller
c953ffb471 Merge branch 'release/1.0.0-rc.4' into develop 2015-10-29 21:53:48 -06:00
Andy Miller
3d7fa06129 version update 2015-10-29 21:52:52 -06:00
Andy Miller
49d4fbcf3d fix for non-existing page with collection @page: /something format 2015-10-29 21:50:58 -06:00
Andy Miller
fc18a40c35 fixed double bang 2015-10-29 20:03:19 -06:00
Andy Miller
1e81d5e38c whitespace tweak 2015-10-29 16:34:30 -06:00
Andy Miller
daf8b53c0d Merge branch 'release/1.0.0-rc.3' into develop 2015-10-29 14:08:39 -06:00
Andy Miller
8de55a745d Merge branch 'release/1.0.0-rc.3' 2015-10-29 14:08:38 -06:00
Andy Miller
6bf669815d version update 2015-10-29 14:08:09 -06:00
Andy Miller
8ba49e163d version update 2015-10-29 14:06:54 -06:00
Andy Miller
26918d90ab Merge pull request #397 from Sommerregen/patch-2
Addresses # 12 (form-plugin) Trim fields before validation
2015-10-29 11:57:11 -06:00
Benny
929b0806dc Addresses # 12 (form-plugin) Trim fields before validation 2015-10-29 16:58:41 +01:00
Flavio Copes
3e32e61db1 Revert "Add a items() method that returns the Data::items array"
This reverts commit fafd72fcd8.
2015-10-29 14:59:11 +01:00
Flavio Copes
038693bffb Merge pull request #396 from Sommerregen/patch-1
Fix #395
2015-10-29 14:00:54 +01:00
Benny
9445aa43e6 Fix #395 (Problem with default language and slugs that is starting with language name) 2015-10-29 13:44:29 +01:00
Henrik Maier
bb16dbab78 Remove debug error_log output 2015-10-29 13:02:22 +10:00
Andy Miller
658212e7be Merge pull request #392 from nickbalestra/readme
Update README.md
2015-10-28 21:01:56 -06:00
Nick Balestra
e91554770c Update README.md 2015-10-28 19:58:38 -07:00
Henrik Maier
8f9671ad32 Allow width and height attributes to be added to Markdown and Twig image tags 2015-10-29 12:53:00 +10:00
Andy Miller
7f134e39f4 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-10-28 20:52:30 -06:00
Henrik Maier
c87e3f419d Allow inline styles to be added to Markdown and Twig image tags 2015-10-29 12:52:24 +10:00
Andy Miller
07b2767ac9 Changed collection types from .recurse to .descendants 2015-10-28 20:52:22 -06:00
Andy Miller
0ca24a9786 Merge pull request #391 from tuphamnguyen/patch-1
Updated README.md
2015-10-28 20:39:58 -06:00
Tu Pham Nguyen
c84c1366e7 Updated README.md
Just a typo :)
2015-10-28 16:25:29 -05:00
Andy Miller
ebf9bb5c18 Improved collection support #384 2015-10-28 13:33:35 -06:00
Andy Miller
70b67a0805 Created whitelist for fallback route functionality 2015-10-28 10:39:15 -06:00
Andy Miller
545b97716f Merge pull request #387 from hwmaier/feature/asset-stream
Asset management uses now streams rather the constant ASSETS_DIR
2015-10-28 10:12:54 -06:00
Flavio Copes
f7140522f6 Merge pull request #388 from littmus/develop
Typo fixed
2015-10-28 09:56:02 +01:00
littmus
bd2f7088e9 Typo fixed 2015-10-28 17:55:23 +09:00
hwmaier
5260c181a1 Asset management uses now streams rather the constant ASSETS_DIR to configure location. In addition it supports subdirectories for assets location, for example assets/runtime. 2015-10-28 13:15:03 +10:00
Andy Miller
a9538adf2b Merge branch 'release/1.0.0-rc.2' into develop 2015-10-27 14:47:43 -06:00
71 changed files with 1212 additions and 786 deletions

View File

@@ -44,15 +44,17 @@ RewriteRule .* index.php [L]
## Begin - Security
# Block all direct access for these folders
RewriteRule ^(.git|cache|bin|logs|backup)/(.*) error [L]
# Block access to specific file types for these folders
RewriteRule ^(system|user|vendor)/(.*)\.(txt|md|html|yaml|php|twig|sh|bat)$ error [L]
RewriteRule ^(.git|cache|bin|logs|backup)/(.*) error [F]
# Block access to specific file types for these system folders
RewriteRule ^(system|vendor)/(.*)\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
# Block access to specific file types for these user folders
RewriteRule ^(user)/(.*)\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
# Block all direct access to .md files:
RewriteRule \.md$ error [L]
RewriteRule \.md$ error [F]
# Block all direct access to files and folders beginning with a dot
RewriteRule (^\.|/\.) - [F]
# Block access to specific files in the root folder
RewriteRule ^(LICENSE|composer.lock|composer.json|nginx.conf|web.config)$ error [F]
RewriteRule ^(LICENSE|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)$ error [F]
## End - Security
</IfModule>

View File

@@ -1,3 +1,66 @@
# v1.0.0-rc.5
## 11/20/2015
1. [](#new)
* Added **nonce** functionality for all admin forms for improved security
* Implemented the ability for Plugins to provide their own CLI commands through `bin/plugin`
* Added Croatian translation
* Added missing `umask_fix` property to `system.yaml`
* Added current theme's config to global config. E.g. `config.theme.dropdown_enabled`
* Added `append_url_extension` option to system config & page headers
* Users have a new `state` property to allow disabling/banning
* Added new `Page.relativePagePath()` helper method
* Added new `|pad` Twig filter for strings (uses `str_pad()`)
* Added `lighttpd.conf` for Lightly web server
1. [](#improved)
* Clear previously applied operations when doing a reset on image media
* Password no longer required when editing user
* Improved support for trailing `/` URLs
* Improved `.nginx.conf` configuration file
* Improved `.htaccess` security
* Updated vendor libs
* Updated `composer.phar`
* Use streams instead of paths for `clearCache()`
* Use PCRE_UTF8 so unicode strings can be regexed in Truncator
* Handle case when login plugin is disabled
* Improved `quality` functionality in media handling
* Added some missing translation strings
* Deprecated `bin/grav newuser` in favor of `bin/plugin login new-user`
* Moved fallback types to use any valid media type
* Renamed `system.pages.fallback_types` to `system.media.allowed_fallback_types`
* Removed version number in default `generator` meta tag
* Disable time limit in case of slow downloads
* Removed default hash in `system.yaml`
1. [](#bugfix)
* Fix for media using absolute URLs causing broken links
* Fix theme auto-loading #432
* Don't create empty `<style>` or `<script>` scripts if no data
* Code cleanups
* Fix undefined variable in Config class
* Fix exception message when label is not set
* Check in `Plugins::get()` to ensure plugins exists
* Fixed GZip compression making output buffering work correctly with all servers and browsers
* Fixed date representation in system config
# v1.0.0-rc.4
## 10/29/2015
1. [](#bugfix)
* Fixed a fatal error if you have a collection with missing or invalid `@page: /route`
# v1.0.0-rc.3
## 10/29/2015
1. [](#new)
* New Page collection options! `@self.parent, @self.siblings, @self.descendants` + more
* Whitelist of file types for fallback route functionality (images by default)
1. [](#improved)
* Assets switched from defines to streams
1. [](#bugfix)
* README.md typos fixed
* Fixed issue with routes that have lang string in them (`/en/english`)
* Trim strings before validation so whitespace is not satisfy 'required'
# v1.0.0-rc.2
## 10/27/2015

View File

@@ -9,10 +9,10 @@ The underlying architecture of Grav is designed to use well-established and _bes
* [Twig Templating](http://twig.sensiolabs.org/): for powerful control of the user interface
* [Markdown](http://en.wikipedia.org/wiki/Markdown): for easy content creation
* [YAML](http://yaml.org): for simple configuration
* [Parsedown](http://parsedown.org/): for fast Markdown and Mardown Extra support
* [Parsedown](http://parsedown.org/): for fast Markdown and Markdown Extra support
* [Doctrine Cache](http://docs.doctrine-project.org/en/2.0.x/reference/caching.html): layer for performance
* [Pimple Dependency Injection Container](http://pimple.sensiolabs.org/): for extensibility and maintainability
* [Symfony Event Dispacher](http://symfony.com/doc/current/components/event_dispatcher/introduction.html): for plugin event handling
* [Symfony Event Dispatcher](http://symfony.com/doc/current/components/event_dispatcher/introduction.html): for plugin event handling
* [Symfony Console](http://symfony.com/doc/current/components/console/introduction.html): for CLI interface
* [Gregwar Image Library](https://github.com/Gregwar/Image): for dynamic image manipulation
@@ -53,7 +53,7 @@ You can download [plugins](http://getgrav.org/downloads/plugins) or [themes](htt
$ bin/gpm index
```
This will display all the available plugins and then you can install one ore more with:
This will display all the available plugins and then you can install one or more with:
```
$ bin/gpm install <plugin/theme>
@@ -76,7 +76,7 @@ $ bin/gpm update
# Contributing
We appreciate any contribution to Grav, whether it is related to bugs, grammar, or simply a suggestion or improvement.
However, we ask that any contribution follow our simple guidelines in order to be properly received.
However, we ask that any contributions follow our simple guidelines in order to be properly received.
All our projects follow the [GitFlow branching model][gitflow-model], from development to release. If you are not familiar with it, there are several guides and tutorials to make you understand what it is about.

Binary file not shown.

116
bin/plugin Executable file
View File

@@ -0,0 +1,116 @@
#!/usr/bin/env php
<?php
define('GRAV_CLI', true);
if (version_compare($ver = PHP_VERSION, $req = '5.4.0', '<')) {
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
}
if (!file_exists(__DIR__ . '/../vendor')) {
require_once __DIR__ . '/../system/src/Grav/Common/Composer.php';
}
use Grav\Common\Composer;
if (!file_exists(__DIR__ . '/../vendor')) {
// Before we can even start, we need to run composer first
$composer = Composer::getComposerExecutor();
echo "Preparing to install vendor dependencies...\n\n";
echo system($composer . ' --working-dir="' . __DIR__ . '/../" --no-interaction --no-dev --prefer-dist -o install');
echo "\n\n";
}
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Grav\Common\Grav;
use Grav\Common\Filesystem\Folder;
$autoload = require_once(__DIR__ . '/../vendor/autoload.php');
if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC');
}
if (!file_exists(ROOT_DIR . 'index.php')) {
exit('FATAL: Must be run from ROOT directory of Grav!');
}
$grav = Grav::instance(array('loader' => $autoload));
$grav['config']->init();
$grav['streams'];
$grav['plugins']->init();
$grav['themes']->init();
$app = new Application('Grav Plugins Commands', GRAV_VERSION);
$pattern = '/([A-Z]\w+Command\.php)$/usm';
// get arguments and strip the application name
if (null === $argv) {
$argv = $_SERVER['argv'];
}
$bin = array_shift($argv);
$name = array_shift($argv);
$argv = array_merge([$bin], $argv);
$input = new ArgvInput($argv);
$plugin = $grav['plugins']->get($name);
$output = new ConsoleOutput();
$output->getFormatter()->setStyle('red', new OutputFormatterStyle('red', null, array('bold')));
$output->getFormatter()->setStyle('white', new OutputFormatterStyle('white', null, array('bold')));
if (!$name) {
$output->writeln('');
$output->writeln("<red>Usage:</red>");
$output->writeln(" {$bin} [slug] [command] [arguments]");
$output->writeln('');
$output->writeln("<red>Example:</red>");
$output->writeln(" {$bin} error log -l 1 --trace");
$list = Folder::all('plugins://', ['compare' => 'Pathname', 'pattern' => '\/cli\/' . $pattern]);
if (count($list)) {
$available = [];
$output->writeln('');
$output->writeln('<red>Plugins with CLI available:</red>');
foreach ($list as $index => $entry) {
$split = explode('/', $entry);
$entry = array_shift($split);
$index = str_pad($index++ + 1, 2, '0', STR_PAD_LEFT);
if (in_array($entry, $available)) {
continue;
}
$available[] = $entry;
$output->writeln(' ' . $index . ". <red>" . str_pad($entry, 15) . "</red> <white>${bin} ${entry} list</white>");
}
}
exit;
}
if ($plugin === null) {
$output->writeln("<red>Grav Plugin <white>'{$name}'</white> is not installed</red>");
exit;
}
$path = 'plugins://' . $name . '/cli';
try {
$commands = Folder::all($path, ['compare' => 'Filename', 'pattern' => $pattern]);
} catch (\RuntimeException $e) {
$output->writeln("<red>No Console Commands for <white>'{$name}'</white> where found in <white>'{$path}'</white></red>");
exit;
}
foreach ($commands as $command) {
require_once "plugins://{$name}/cli/{$command}";
$command = 'Grav\Plugin\Console\\' . preg_replace('/.php$/', '', $command);
$app->add(new $command());
}
$app->run($input);

85
composer.lock generated
View File

@@ -1,23 +1,24 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "e1db721096772d41f16003b39b47c85a",
"content-hash": "294dd2282a332d96b19d163ad08e7ba7",
"packages": [
{
"name": "doctrine/cache",
"version": "v1.4.2",
"version": "v1.5.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "8c434000f420ade76a07c64cbe08ca47e5c101ca"
"reference": "2b9cec5a5e722010cbebc91713d4c11eaa064d5e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/8c434000f420ade76a07c64cbe08ca47e5c101ca",
"reference": "8c434000f420ade76a07c64cbe08ca47e5c101ca",
"url": "https://api.github.com/repos/doctrine/cache/zipball/2b9cec5a5e722010cbebc91713d4c11eaa064d5e",
"reference": "2b9cec5a5e722010cbebc91713d4c11eaa064d5e",
"shasum": ""
},
"require": {
@@ -38,8 +39,8 @@
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Cache\\": "lib/"
"psr-4": {
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -74,7 +75,7 @@
"cache",
"caching"
],
"time": "2015-08-31 12:36:41"
"time": "2015-11-02 18:35:48"
},
{
"name": "donatj/phpuseragentparser",
@@ -216,12 +217,12 @@
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "9a393ceb80f7497b6513feb574638e87048fed55"
"reference": "50a288b51058fa94cf5b37cfa4277535983cc9d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/9a393ceb80f7497b6513feb574638e87048fed55",
"reference": "9a393ceb80f7497b6513feb574638e87048fed55",
"url": "https://api.github.com/repos/filp/whoops/zipball/50a288b51058fa94cf5b37cfa4277535983cc9d5",
"reference": "50a288b51058fa94cf5b37cfa4277535983cc9d5",
"shasum": ""
},
"require": {
@@ -266,7 +267,7 @@
"whoops",
"zf2"
],
"time": "2015-09-27 09:47:06"
"time": "2015-11-14 20:08:27"
},
{
"name": "gregwar/cache",
@@ -714,16 +715,16 @@
},
{
"name": "symfony/console",
"version": "v2.7.5",
"version": "v2.7.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "06cb17c013a82f94a3d840682b49425cd00a2161"
"reference": "5efd632294c8320ea52492db22292ff853a43766"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/06cb17c013a82f94a3d840682b49425cd00a2161",
"reference": "06cb17c013a82f94a3d840682b49425cd00a2161",
"url": "https://api.github.com/repos/symfony/console/zipball/5efd632294c8320ea52492db22292ff853a43766",
"reference": "5efd632294c8320ea52492db22292ff853a43766",
"shasum": ""
},
"require": {
@@ -732,7 +733,6 @@
"require-dev": {
"psr/log": "~1.0",
"symfony/event-dispatcher": "~2.1",
"symfony/phpunit-bridge": "~2.7",
"symfony/process": "~2.1"
},
"suggest": {
@@ -767,20 +767,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2015-09-25 08:32:23"
"time": "2015-10-20 14:38:46"
},
{
"name": "symfony/event-dispatcher",
"version": "v2.7.5",
"version": "v2.7.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9"
"reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae4dcc2a8d3de98bd794167a3ccda1311597c5d9",
"reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/87a5db5ea887763fa3a31a5471b512ff1596d9b8",
"reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8",
"shasum": ""
},
"require": {
@@ -791,7 +791,6 @@
"symfony/config": "~2.0,>=2.0.5",
"symfony/dependency-injection": "~2.6",
"symfony/expression-language": "~2.6",
"symfony/phpunit-bridge": "~2.7",
"symfony/stopwatch": "~2.3"
},
"suggest": {
@@ -825,28 +824,25 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2015-09-22 13:49:29"
"time": "2015-10-11 09:39:48"
},
{
"name": "symfony/var-dumper",
"version": "v2.7.5",
"version": "v2.7.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "ba8c9a0edf18f70a7efcb8d3eb35323a10263338"
"reference": "eb033050050916b6bfa51be71009ef67b16046c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/ba8c9a0edf18f70a7efcb8d3eb35323a10263338",
"reference": "ba8c9a0edf18f70a7efcb8d3eb35323a10263338",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/eb033050050916b6bfa51be71009ef67b16046c9",
"reference": "eb033050050916b6bfa51be71009ef67b16046c9",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
},
"suggest": {
"ext-symfony_debug": ""
},
@@ -884,28 +880,25 @@
"debug",
"dump"
],
"time": "2015-09-22 14:41:01"
"time": "2015-10-25 17:17:38"
},
{
"name": "symfony/yaml",
"version": "v2.7.5",
"version": "v2.7.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "31cb2ad0155c95b88ee55fe12bc7ff92232c1770"
"reference": "eca9019c88fbe250164affd107bc8057771f3f4d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/31cb2ad0155c95b88ee55fe12bc7ff92232c1770",
"reference": "31cb2ad0155c95b88ee55fe12bc7ff92232c1770",
"url": "https://api.github.com/repos/symfony/yaml/zipball/eca9019c88fbe250164affd107bc8057771f3f4d",
"reference": "eca9019c88fbe250164affd107bc8057771f3f4d",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
},
"type": "library",
"extra": {
"branch-alias": {
@@ -933,20 +926,20 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2015-09-14 14:14:09"
"time": "2015-10-11 09:39:48"
},
{
"name": "twig/twig",
"version": "v1.22.3",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "ebfc36b7e77b0c1175afe30459cf943010245540"
"reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ebfc36b7e77b0c1175afe30459cf943010245540",
"reference": "ebfc36b7e77b0c1175afe30459cf943010245540",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
"reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
"shasum": ""
},
"require": {
@@ -959,7 +952,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.22-dev"
"dev-master": "1.23-dev"
}
},
"autoload": {
@@ -994,7 +987,7 @@
"keywords": [
"templating"
],
"time": "2015-10-13 07:07:02"
"time": "2015-11-05 12:49:06"
}
],
"packages-dev": [],

View File

@@ -44,15 +44,17 @@ RewriteRule .* index.php [L]
## Begin - Security
# Block all direct access for these folders
RewriteRule ^(.git|cache|bin|logs|backup)/(.*) error [L]
# Block access to specific file types for these folders
RewriteRule ^(system|user|vendor)/(.*)\.(txt|md|html|yaml|php|twig|sh|bat)$ error [L]
RewriteRule ^(.git|cache|bin|logs|backup)/(.*) error [F]
# Block access to specific file types for these system folders
RewriteRule ^(system|vendor)/(.*)\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
# Block access to specific file types for these user folders
RewriteRule ^(user)/(.*)\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
# Block all direct access to .md files:
RewriteRule \.md$ error [L]
RewriteRule \.md$ error [F]
# Block all direct access to files and folders beginning with a dot
RewriteRule (^\.|/\.) - [F]
# Block access to specific files in the root folder
RewriteRule ^(LICENSE|composer.lock|composer.json|nginx.conf|web.config)$ error [F]
RewriteRule ^(LICENSE|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)$ error [F]
## End - Security
</IfModule>

48
lighttpd.conf Normal file
View File

@@ -0,0 +1,48 @@
############# DO NOT FORGET TO CHANGE "grav_path" BY YOUR ACTUAL GRAV INSTALLATION FOLDER #############
############# IF GRAV IS AT THE ROOT OF YOUR WEBSITE, ie http://yoursite.tld POINTS TO #############
############# GRAV DIRECTLY, THEN JUST REMOVE ANY "/grav_path/" MENTION BELOW. OTHERWISE #############
############# WE ASSUME YOU RUN AN INSTALLATION SUCH AS http://yoursite.tld/grav_path/ #############
#######################################################################################################
### GRAV RULES FOR LIGHTTPD ###
### By Mr3ase ###
### Last Rev. 2015/11/20 ###
#PREVENTING EXPLOITS
$HTTP["querystring"] =~ "base64_encode[^(]*\([^)]*\)" {
url.redirect = (".*" => "/grav_path/index.php" )
}
$HTTP["querystring"] =~ "(<|%3C)([^s]*s)+cript.*(>|%3E)" {
url.redirect = (".*" => "/grav_path/index.php" )
}
$HTTP["querystring"] =~ "GLOBALS(=|\[|\%[0-9A-Z])" {
url.redirect = (".*" => "/grav_path/index.php" )
}
$HTTP["querystring"] =~ "_REQUEST(=|\[|\%[0-9A-Z])" {
url.redirect = (".*" => "/grav_path/index.php" )
}
#REROUTING TO THE INDEX PAGE
url.rewrite-if-not-file = (
"^/grav_path/(.*)$" => "/grav_path/index.php"
)
#IMPROVING SECURITY
$HTTP["url"] =~ "^/grav_path/(LICENSE|composer.json|composer.lock|nginx.conf|web.config)$" {
url.access-deny = ("")
}
$HTTP["url"] =~ "^/grav_path/(.git|cache|bin|logs|backup)/(.*)" {
url.access-deny = ("")
}
$HTTP["url"] =~ "^/grav_path/(system|user|vendor)/(.*)\.(txt|md|html|yaml|php|twig|sh|bat)$" {
url.access-deny = ("")
}
$HTTP["url"] =~ "^/grav_path/(\.(.*))|(\.(.*)/)" {
url.access-deny = ("")
}
url.access-deny = (".md","~",".inc")
#PREVENT BROWSING AND SET INDEXES
$HTTP["url"] =~ "^/grav_path($|/)" {
dir-listing.activate = "disable"
index-file.names = ( "index.php", "index.html" , "index.htm" )
}

View File

@@ -1,87 +1,44 @@
worker_processes 1;
server {
#listen 80;
index index.html index.php;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location / {
root html;
index index.php;
if (!-e $request_filename){ rewrite ^(.*)$ /index.php last; }
}
# if you want grav in a sub-directory of your main site
# (for example, example.com/mygrav) then you need this rewrite:
location /mygrav {
index index.php;
if (!-e $request_filename){ rewrite ^(.*)$ /mygrav/$2 last; }
try_files $uri $uri/ /index.php?$args;
}
# if using grav in a sub-directory of your site,
# prepend the actual path to each location
# for example: /mygrav/images
# and: /mygrav/user
# and: /mygrav/cache
# and so on
location /images/ {
# Serve images as static
}
location /user {
rewrite ^/user/accounts/(.*)$ /error redirect;
rewrite ^/user/config/(.*)$ /error redirect;
rewrite ^/user/(.*)\.(txt|md|html|php|yaml|json|twig|sh|bat)$ /error redirect;
}
location /cache {
rewrite ^/cache/(.*) /error redirect;
}
location /bin {
rewrite ^/bin/(.*)$ /error redirect;
}
location /backup {
rewrite ^/backup/(.*) /error redirect;
}
location /system {
rewrite ^/system/(.*)\.(txt|md|html|php|yaml|json|twig|sh|bat)$ /error redirect;
}
location /vendor {
rewrite ^/vendor/(.*)\.(txt|md|html|php|yaml|json|twig|sh|bat)$ /error redirect;
}
# Remember to change 127.0.0.1:9000 to the Ip/port
# you configured php-cgi.exe to run from
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
## Begin - Server Info
root /home/user/www/html;
server_name localhost;
## End - Server Info
## Begin - Index
# for subfolders, simply adjust:
# `location /subfolder {`
# and the rewrite to use `/subfolder/index.php`
location / {
try_files $uri $uri/ /index.html;
if (!-e $request_filename){ rewrite ^(.*)$ /index.php last; }
}
## End - Index
## Begin - PHP
location ~ \.php$ {
# Choose either a socket or TCP/IP address
fastcgi_pass unix:/var/run/php5-fpm.sock;
# fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
## End - PHP
## Begin - Security
# deny all direct access for these folders
location ~* /(.git|cache|bin|logs|backups)/.*$ { return 403; }
# deny running scripts inside core system folders
location ~* /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
# deny running scripts inside user folder
location ~* /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
# deny access to specific files in the root folder
location ~ /(LICENSE|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) { return 403; }
## End - Security
}

View File

@@ -73,7 +73,7 @@ form:
options:
"F jS \\a\\t g:ia": Date1
"l jS \\of F g:i A": Date2
"D, m M Y G:i:s": Date3
"D, d M Y G:i:s": Date3
"d-m-y G:i": Date4
"jS M Y": Date5
@@ -86,7 +86,7 @@ form:
options:
"F jS \\a\\t g:ia": Date1
"l jS \\of F g:i A": Date2
"D, m M Y G:i:s": Date3
"D, d M Y G:i:s": Date3
"d-m-y G:i": Date4
"jS M Y": Date5
@@ -142,6 +142,12 @@ form:
twig: Twig Events
use: keys
pages.append_url_extension:
type: text
placeholder: "e.g. .html"
label: PLUGIN_ADMIN.APPEND_URL_EXT
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
pages.redirect_default_route:
type: toggle
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE
@@ -225,6 +231,7 @@ form:
languages.supported:
type: selectize
size: large
placeholder: "e.g. en, fr"
label: PLUGIN_ADMIN.SUPPORTED
help: PLUGIN_ADMIN.SUPPORTED_HELP
classes: fancy
@@ -711,6 +718,26 @@ form:
validate:
type: bool
media.allowed_fallback_types:
type: selectize
size: large
label: PLUGIN_ADMIN.FALLBACK_TYPES
help: PLUGIN_ADMIN.FALLBACK_TYPES_HELP
classes: fancy
validate:
type: commalist
media.unsupported_inline_types:
type: selectize
size: large
label: PLUGIN_ADMIN.INLINE_TYPES
help: PLUGIN_ADMIN.INLINE_TYPES_HELP
classes: fancy
validate:
type: commalist
session:
type: section
title: PLUGIN_ADMIN.SESSION
@@ -774,6 +801,7 @@ form:
param_sep:
type: select
size: medium
label: PLUGIN_ADMIN.PARAMETER_SEPARATOR
classes: fancy
help: PLUGIN_ADMIN.PARAMETER_SEPARATOR_HELP

View File

@@ -29,7 +29,6 @@ form:
content:
type: markdown
label: PLUGIN_ADMIN.CONTENT
validate:
type: textarea
@@ -88,7 +87,6 @@ form:
placeholder_key: PLUGIN_ADMIN.METADATA_KEY
placeholder_value: PLUGIN_ADMIN.METADATA_VALUE
taxonomies:
type: section
title: PLUGIN_ADMIN.TAXONOMIES
@@ -264,6 +262,12 @@ form:
default: default
'@data-options': '\Grav\Common\Page\Pages::types'
header.append_url_extension:
type: text
label: PLUGIN_ADMIN.APPEND_URL_EXT
toggleable: true
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
header.order_by:
type: hidden

View File

@@ -25,7 +25,6 @@ form:
content:
type: markdown
label: PLUGIN_ADMIN.CONTENT
uploads:
type: pagemedia

View File

@@ -25,7 +25,6 @@ form:
content:
type: markdown
label: PLUGIN_ADMIN.CONTENT
uploads:
type: pagemedia

View File

@@ -29,7 +29,7 @@ form:
size: large
label: PLUGIN_ADMIN.PASSWORD
validate:
required: true
required: false
message: PLUGIN_ADMIN.PASSWORD_VALIDATION_MESSAGE
pattern: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}'

View File

@@ -1,9 +1,4 @@
schemes:
asset:
type: ReadOnlyStream
paths:
- assets
image:
type: ReadOnlyStream
paths:

View File

@@ -1,111 +1,113 @@
absolute_urls: false # Absolute or relative URLs for `base_url`
timezone: '' # Valid values: http://php.net/manual/en/timezones.php
default_locale: # Default locale (defaults to system)
param_sep: ':' # Parameter separator, use ';' for Apache on windows
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
absolute_urls: false # Absolute or relative URLs for `base_url`
timezone: '' # Valid values: http://php.net/manual/en/timezones.php
default_locale: # Default locale (defaults to system)
param_sep: ':' # Parameter separator, use ';' for Apache on windows
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
languages:
supported: [] # List of languages supported. eg: [en, fr, de]
include_default_lang: true # Include the default lang prefix in all URLs
translations: true # Enable translations by default
translations_fallback: true # Fallback through supported translations if active lang doesn't exist
session_store_active: false # Store active language in session
http_accept_language: false # Attempt to set the language based on http_accept_language header in the browser
override_locale: false # Override the default or system locale with language specific one
supported: [] # List of languages supported. eg: [en, fr, de]
include_default_lang: true # Include the default lang prefix in all URLs
translations: true # Enable translations by default
translations_fallback: true # Fallback through supported translations if active lang doesn't exist
session_store_active: false # Store active language in session
http_accept_language: false # Attempt to set the language based on http_accept_language header in the browser
override_locale: false # Override the default or system locale with language specific one
home:
alias: '/home' # Default path for home, ie /
alias: '/home' # Default path for home, ie /
pages:
theme: antimatter # Default theme (defaults to "antimatter" theme)
theme: antimatter # Default theme (defaults to "antimatter" theme)
order:
by: default # Order pages by "default", "alpha" or "date"
dir: asc # Default ordering direction, "asc" or "desc"
by: default # Order pages by "default", "alpha" or "date"
dir: asc # Default ordering direction, "asc" or "desc"
list:
count: 20 # Default item count per page
count: 20 # Default item count per page
dateformat:
default: # The default date format Grav expects in the `date: ` field
short: 'jS M Y' # Short date format
long: 'F jS \a\t g:ia' # Long date format
publish_dates: true # automatically publish/unpublish based on dates
default: # The default date format Grav expects in the `date: ` field
short: 'jS M Y' # Short date format
long: 'F jS \a\t g:ia' # Long date format
publish_dates: true # automatically publish/unpublish based on dates
process:
markdown: true # Process Markdown
twig: false # Process Twig
markdown: true # Process Markdown
twig: false # Process Twig
events:
page: true # Enable page level events
twig: true # Enable twig level events
page: true # Enable page level events
twig: true # Enable twig level events
markdown:
extra: false # Enable support for Markdown Extra support (GFM by default)
auto_line_breaks: false # Enable automatic line breaks
auto_url_links: false # Enable automatic HTML links
escape_markup: false # Escape markup tags into entities
special_chars: # List of special characters to automatically convert to entities
extra: false # Enable support for Markdown Extra support (GFM by default)
auto_line_breaks: false # Enable automatic line breaks
auto_url_links: false # Enable automatic HTML links
escape_markup: false # Escape markup tags into entities
special_chars: # List of special characters to automatically convert to entities
'>': 'gt'
'<': 'lt'
types: [txt,xml,html,json,rss,atom] # list of valid page types
expires: 604800 # Page expires time in seconds (604800 seconds = 7 days)
last_modified: false # Set the last modified date header based on file modifcation timestamp
etag: false # Set the etag header tag
vary_accept_encoding: false # Add `Vary: Accept-Encoding` header
redirect_default_route: false # Automatically redirect to a page's default route
redirect_default_code: 301 # Default code to use for redirects
redirect_trailing_slash: true # Handle automatically or 301 redirect a trailing / URL
ignore_files: [.DS_Store] # Files to ignore in Pages
ignore_folders: [.git, .idea] # Folders to ignore in Pages
ignore_hidden: true # Ignore all Hidden files and folders
url_taxonomy_filters: true # Enable auto-magic URL-based taxonomy filters for page collections
types: [txt,xml,html,htm,json,rss,atom] # list of valid page types
append_url_extension: '' # Append page's extension in Page urls (e.g. '.html' results in /path/page.html)
expires: 604800 # Page expires time in seconds (604800 seconds = 7 days)
last_modified: false # Set the last modified date header based on file modifcation timestamp
etag: false # Set the etag header tag
vary_accept_encoding: false # Add `Vary: Accept-Encoding` header
redirect_default_route: false # Automatically redirect to a page's default route
redirect_default_code: 301 # Default code to use for redirects
redirect_trailing_slash: true # Handle automatically or 301 redirect a trailing / URL
ignore_files: [.DS_Store] # Files to ignore in Pages
ignore_folders: [.git, .idea] # Folders to ignore in Pages
ignore_hidden: true # Ignore all Hidden files and folders
url_taxonomy_filters: true # Enable auto-magic URL-based taxonomy filters for page collections
cache:
enabled: true # Set to true to enable caching
enabled: true # Set to true to enable caching
check:
method: file # Method to check for updates in pages: file|folder|none
driver: auto # One of: auto|file|apc|xcache|memcache|wincache
prefix: 'g' # Cache prefix string (prevents cache conflicts)
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
gzip: false # GZip compress the page output
method: file # Method to check for updates in pages: file|folder|none
driver: auto # One of: auto|file|apc|xcache|memcache|wincache
prefix: 'g' # Cache prefix string (prevents cache conflicts)
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
gzip: false # GZip compress the page output
twig:
cache: true # Set to true to enable twig caching
debug: false # Enable Twig debug
auto_reload: true # Refresh cache on changes
autoescape: false # Autoescape Twig vars
undefined_functions: true # Allow undefined functions
undefined_filters: true # Allow undefined filters
cache: true # Set to true to enable twig caching
debug: false # Enable Twig debug
auto_reload: true # Refresh cache on changes
autoescape: false # Autoescape Twig vars
undefined_functions: true # Allow undefined functions
undefined_filters: true # Allow undefined filters
umask_fix: false # By default Twig creates cached files as 755, fix switches this to 775
assets: # Configuration for Assets Manager (JS, CSS)
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
css_minify: true # Minify the CSS during pipelining
css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize
css_rewrite: true # Rewrite any CSS relative URLs during pipelining
js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file
js_minify: true # Minify the JS during pipelining
enable_asset_timestamp: false # Enable asset timestamps
assets: # Configuration for Assets Manager (JS, CSS)
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
css_minify: true # Minify the CSS during pipelining
css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize
css_rewrite: true # Rewrite any CSS relative URLs during pipelining
js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file
js_minify: true # Minify the JS during pipelining
enable_asset_timestamp: false # Enable asset timestamps
collections:
jquery: system://assets/jquery/jquery-2.1.4.min.js
errors:
display: false # Display full backtrace-style error page
log: true # Log errors to /logs folder
display: false # Display full backtrace-style error page
log: true # Log errors to /logs folder
debugger:
enabled: false # Enable Grav debugger and following settings
enabled: false # Enable Grav debugger and following settings
shutdown:
close_connection: true # Close the connection before calling onShutdown(). false for debugging
close_connection: true # Close the connection before calling onShutdown(). false for debugging
images:
default_image_quality: 85 # Default image quality to use when resampling images (85%)
cache_all: false # Cache all image by default
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
default_image_quality: 85 # Default image quality to use when resampling images (85%)
cache_all: false # Cache all image by default
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
media:
enable_media_timestamp: false # Enable media timetsamps
upload_limit: 0 # Set maximum upload size in bytes (0 is unlimited)
unsupported_inline_types: [] # Array of unsupported media file types to try to display inline
enable_media_timestamp: false # Enable media timetsamps
upload_limit: 0 # Set maximum upload size in bytes (0 is unlimited)
unsupported_inline_types: [] # Array of supported media types to try to display inline
allowed_fallback_types: [] # Array of allowed media types of files found if accessed via Page route
session:
enabled: true # Enable Session support
timeout: 1800 # Timeout in seconds
name: grav-site # Name prefix of the session cookie
enabled: true # Enable Session support
timeout: 1800 # Timeout in seconds
name: grav-site # Name prefix of the session cookie
security:
default_hash: $2y$10$kwsyMVwM8/7j0K/6LHT.g.Fs49xOCTp2b8hh/S5.dPJuJcJB6T.UK

View File

@@ -2,7 +2,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.0.0-rc.2');
define('GRAV_VERSION', '1.0.0-rc.5');
define('DS', '/');
// Directories and Paths
@@ -13,14 +13,14 @@ define('ROOT_DIR', GRAV_ROOT . '/');
define('USER_PATH', 'user/');
define('USER_DIR', ROOT_DIR . USER_PATH);
define('SYSTEM_DIR', ROOT_DIR .'system/');
define('ASSETS_DIR', ROOT_DIR . 'assets/');
define('CACHE_DIR', ROOT_DIR . 'cache/');
define('IMAGES_DIR', ROOT_DIR . 'images/');
define('LOG_DIR', ROOT_DIR .'logs/');
define('ACCOUNTS_DIR', USER_DIR .'accounts/');
define('PAGES_DIR', USER_DIR .'pages/');
// DEPRECATED: Do not use!
define('ASSETS_DIR', ROOT_DIR . 'assets/');
define('IMAGES_DIR', ROOT_DIR . 'images/');
define('ACCOUNTS_DIR', USER_DIR .'accounts/');
define('PAGES_DIR', USER_DIR .'pages/');
define('DATA_DIR', USER_DIR .'data/');
define('LIB_DIR', SYSTEM_DIR .'src/');
define('PLUGINS_DIR', USER_DIR .'plugins/');

View File

@@ -92,3 +92,6 @@ NICETIME:
MO_PLURAL: mos
YR_PLURAL: yrs
DEC_PLURAL: decs
FORM:
VALIDATION_FAIL: <b>Validation failed:</b>
INVALID_INPUT: Invalid input in

46
system/languages/hr.yaml Normal file
View File

@@ -0,0 +1,46 @@
INFLECTOR_IRREGULAR:
'person': 'Osoba'
'man': 'Čovjek'
'child': 'Dijete'
'sex': 'Spol'
'move': 'Pomakni'
NICETIME:
NO_DATE_PROVIDED: Datum nije upisan
BAD_DATE: Pogrešan datum
AGO: prije
FROM_NOW: od sad
SECOND: sekundi
MINUTE: minuta
HOUR: godina
DAY: dan
WEEK: tjedan
MONTH: mjesec
YEAR: godina
DECADE: desetljeće
SEC: sek
MIN: min
HR: sat
DAY: dan
WK: t
MO: m
YR: g
DEC: des
SECOND_PLURAL: sekundi
MINUTE_PLURAL: minuta
HOUR_PLURAL: sati
DAY_PLURAL: dana
WEEK_PLURAL: tjedana
MONTH_PLURAL: mjeseci
YEAR_PLURAL: godina
DECADE_PLURAL: desetljeća
SEC_PLURAL: sek
MIN_PLURAL: min
HR_PLURAL: sat
DAY_PLURAL: dan
WK_PLURAL: t
MO_PLURAL: m
YR_PLURAL: g
DEC_PLURAL: des
FORM:
VALIDATION_FAIL: <b>Validacija nije uspjela:</b>
INVALID_INPUT: Unos nije valjan

37
system/languages/tr.yaml Normal file
View File

@@ -0,0 +1,37 @@
NICETIME:
NO_DATE_PROVIDED: Tarih yok
BAD_DATE: Yanlış tarih
AGO: önce
FROM_NOW: (şimdiden)
SECOND: saniye
MINUTE: dakika
HOUR: saat
DAY: gün
WEEK: hafta
MONTH: ay
YEAR: yıl
DECADE: onyıl
SEC: sn
MIN: dk
HR: sa
DAY: gün
WK: hft
MO: ay
YR: yl
DEC: onyl
SECOND_PLURAL: saniye
MINUTE_PLURAL: dakika
HOUR_PLURAL: saat
DAY_PLURAL: gün
WEEK_PLURAL: hafta
MONTH_PLURAL: ay
YEAR_PLURAL: yıl
DECADE_PLURAL: onyıl
SEC_PLURAL: sn
MIN_PLURAL: dk
HR_PLURAL: sa
DAY_PLURAL: gün
WK_PLURAL: hft
MO_PLURAL: ay
YR_PLURAL: yl
DEC_PLURAL: onyl

View File

@@ -74,6 +74,8 @@ class Assets
protected $config;
protected $base_url;
protected $timestamp = '';
protected $assets_dir;
protected $assets_url;
// Default values for pipeline settings
protected $css_minify = true;
@@ -117,7 +119,7 @@ class Assets
}
// Pipeline requires public dir
if (($this->js_pipeline || $this->css_pipeline) && !is_dir(ASSETS_DIR)) {
if (($this->js_pipeline || $this->css_pipeline) && !is_dir($this->assets_dir)) {
throw new \Exception('Assets: Public dir not found');
}
@@ -175,6 +177,11 @@ class Assets
$base_url = self::getGrav()['base_url'];
$asset_config = (array)$config->get('system.assets');
/** @var Locator $locator */
$locator = self::$grav['locator'];
$this->assets_dir = self::getGrav()['locator']->findResource('asset://') . DS;
$this->assets_url = self::getGrav()['locator']->findResource('asset://', false);
$this->config($asset_config);
$this->base_url = $base_url . '/';
@@ -406,7 +413,7 @@ class Assets
}
$key = md5($asset);
if (is_string($asset) && !array_key_exists($key, $this->inline_css)) {
if ($asset && is_string($asset) && !array_key_exists($key, $this->inline_css)) {
$this->inline_css[$key] = $data;
}
@@ -453,7 +460,7 @@ class Assets
}
$key = md5($asset);
if (is_string($asset) && !array_key_exists($key, $this->inline_js)) {
if ($asset && is_string($asset) && !array_key_exists($key, $this->inline_js)) {
$this->inline_js[$key] = $data;
}
@@ -621,8 +628,8 @@ class Assets
$file = md5(json_encode($this->css) . $this->css_minify . $this->css_rewrite . $group) . '.css';
$relative_path = "{$this->base_url}" . basename(ASSETS_DIR) . "/{$file}";
$absolute_path = ASSETS_DIR . $file;
$relative_path = "{$this->base_url}{$this->assets_url}/{$file}";
$absolute_path = $this->assets_dir . $file;
// If pipeline exist return it
if (file_exists($absolute_path)) {
@@ -689,8 +696,8 @@ class Assets
$file = md5(json_encode($this->js) . $this->js_minify . $group) . '.js';
$relative_path = "{$this->base_url}" . basename(ASSETS_DIR) . "/{$file}";
$absolute_path = ASSETS_DIR . $file;
$relative_path = "{$this->base_url}{$this->assets_url}/{$file}";
$absolute_path = $this->assets_dir . $file;
// If pipeline exist return it
if (file_exists($absolute_path)) {
@@ -852,12 +859,12 @@ class Assets
public function addDir($directory, $pattern = self::DEFAULT_REGEX)
{
// Check if public_dir exists
if (!is_dir(ASSETS_DIR)) {
if (!is_dir($this->assets_dir)) {
throw new Exception('Assets: Public dir not found');
}
// Get files
$files = $this->rglob(ASSETS_DIR . DIRECTORY_SEPARATOR . $directory, $pattern, ASSETS_DIR);
$files = $this->rglob($this->assets_dir . DIRECTORY_SEPARATOR . $directory, $pattern, $this->assets_dir);
// No luck? Nothing to do
if (!$files) {

View File

@@ -21,6 +21,8 @@ use Grav\Common\Filesystem\Folder;
*/
class Cache extends Getters
{
use GravTrait;
/**
* @var string Cache key.
*/
@@ -44,30 +46,30 @@ class Cache extends Getters
protected $cache_dir;
protected static $standard_remove = [
'cache/twig/',
'cache/doctrine/',
'cache/compiled/',
'cache/validated-',
'images/',
'assets/',
'cache://twig/',
'cache://doctrine/',
'cache://compiled/',
'cache://validated-',
'cache://images',
'asset://',
];
protected static $all_remove = [
'cache/',
'images/',
'assets/'
'cache://',
'cache://images',
'asset://'
];
protected static $assets_remove = [
'assets/'
'asset://'
];
protected static $images_remove = [
'images/'
'cache://images'
];
protected static $cache_remove = [
'cache/'
'cache://'
];
/**
@@ -221,7 +223,7 @@ class Cache extends Getters
*/
public static function clearCache($remove = 'standard')
{
$locator = self::getGrav()['locator'];
$output = [];
$user_config = USER_DIR . 'config/system.yaml';
@@ -243,10 +245,16 @@ class Cache extends Getters
}
foreach ($remove_paths as $path) {
foreach ($remove_paths as $stream) {
// Convert stream to a real path
$path = $locator->findResource($stream, true, true);
// Make sure path exists before proceeding, otherwise we would wipe ROOT_DIR
if (!$path)
throw new \RuntimeException("Stream '{$stream}' not found", 500);
$anything = false;
$files = glob(ROOT_DIR . $path . '*');
$files = glob($path . '/*');
if (is_array($files)) {
foreach ($files as $file) {
@@ -263,7 +271,7 @@ class Cache extends Getters
}
if ($anything) {
$output[] = '<red>Cleared: </red>' . $path . '*';
$output[] = '<red>Cleared: </red>' . $path . '/*';
}
}

View File

@@ -30,6 +30,12 @@ class Config extends Data
'' => ['user'],
]
],
'asset' => [
'type' => 'ReadOnlyStream',
'prefixes' => [
'' => ['assets'],
]
],
'blueprints' => [
'type' => 'ReadOnlyStream',
'prefixes' => [
@@ -194,7 +200,7 @@ class Config extends Data
$checkConfig = $this->get('system.cache.check.config', true);
$checkSystem = $this->get('system.cache.check.system', true);
if (!$checkBlueprints && !!$checkLanguages && $checkConfig && !$checkSystem) {
if (!$checkBlueprints && !$checkLanguages && !$checkConfig && !$checkSystem) {
$this->messages[] = 'Skip configuration timestamp check.';
return false;
}
@@ -286,6 +292,7 @@ class Config extends Data
protected function loadCompiledConfig($configs, $plugins, $filename = null)
{
$checksum = md5(json_encode($configs));
$filename = $filename
? CACHE_DIR . 'compiled/config/' . $filename . '-' . $this->environment . '.php'
: CACHE_DIR . 'compiled/config/' . $checksum . '-' . $this->environment . '.php';

View File

@@ -76,7 +76,9 @@ class Blueprint
try {
$this->validateArray($data, $this->nested);
} catch (\RuntimeException $e) {
throw new \RuntimeException(sprintf('<b>Validation failed:</b> %s', $e->getMessage()));
$language = self::getGrav()['language'];
$message = sprintf($language->translate('FORM.VALIDATION_FAIL', null, true) . ' %s', $e->getMessage());
throw new \RuntimeException($message);
}
}
@@ -449,7 +451,8 @@ class Blueprint
if (isset($field['validate']['required'])
&& $field['validate']['required'] === true
&& empty($data[$name])) {
throw new \RuntimeException("Missing required field: {$field['name']}");
$value = isset($field['label']) ? $field['label'] : $field['name'];
throw new \RuntimeException("Missing required field: {$value}");
}
}
}

View File

@@ -224,16 +224,6 @@ class Data implements DataInterface
return $this->file()->raw();
}
/**
* Return the data items.
*
* @return array
*/
public function items()
{
return $this->items;
}
/**
* Set or get the data storage.
*

View File

@@ -1,5 +1,6 @@
<?php
namespace Grav\Common\Data;
use Grav\Common\GravTrait;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser;
@@ -37,7 +38,7 @@ class Validation
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
$method = 'type'.strtr($type, '-', '_');
$name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']);
$message = (string) isset($field['validate']['message']) ? $field['validate']['message'] : 'Invalid input in "' . $language->translate($name) . '""';
$message = (string) isset($field['validate']['message']) ? $field['validate']['message'] : $language->translate('FORM.INVALID_INPUT', null, true) . ' "' . $language->translate($name) . '"';
if (method_exists(__CLASS__, $method)) {
$success = self::$method($value, $validate, $field);
@@ -588,6 +589,10 @@ class Validation
public static function validateRequired($value, $params)
{
if (is_string($value)) {
$value = trim($value);
}
return (bool) $params !== true || !empty($value);
}

View File

@@ -10,7 +10,7 @@ use Whoops\Run;
* Class Debugger
* @package Grav\Common
*/
class Errors extends \Whoops\Run
class Errors extends Run
{
public function pushHandler($handler, $key = null)

View File

@@ -64,8 +64,8 @@ abstract class Folder
/**
* Get relative path between target and base path. If path isn't relative, return full path.
*
* @param string $path
* @param string $base
* @param string $path
* @param mixed|string $base
* @return string
*/
public static function getRelativePath($path, $base = GRAV_ROOT)

View File

@@ -3,10 +3,9 @@
namespace Grav\Common\GPM\Local;
use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection;
use Grav\Common\GPM\Local\Package;
abstract class AbstractPackageCollection extends BaseCollection {
abstract class AbstractPackageCollection extends BaseCollection
{
public function __construct($items)
{
foreach ($items as $name => $data) {

View File

@@ -1,58 +0,0 @@
<?php
namespace Grav\Common\GPM;
use Grav\Common\Data\Data;
/**
* Interface Package
* @package Grav\Common\GPM
*/
class Package
{
/**
* @var Data
*/
protected $data;
/**
* @var \Grav\Common\Data\Blueprint
*/
protected $blueprints;
/**
* @param Data $package
* @param bool $package_type
*/
public function __construct(Data $package, $package_type = false);
/**
* @return mixed
*/
public function isEnabled();
/**
* @return Data
*/
public function getData();
/**
* @param $key
* @return mixed
*/
public function __get($key);
/**
* @return string
*/
public function __toString();
/**
* @return string
*/
public function toJson();
/**
* @return array
*/
public function toArray();
}

View File

@@ -3,7 +3,6 @@ namespace Grav\Common\GPM\Remote;
use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection;
use Grav\Common\GPM\Response;
use \Doctrine\Common\Cache\FilesystemCache;
class AbstractPackageCollection extends BaseCollection

View File

@@ -16,6 +16,8 @@ class Plugins extends AbstractPackageCollection
/**
* Local Plugins Constructor
* @param bool $refresh
* @param callable $callback Either a function or callback in array notation
*/
public function __construct($refresh = false, $callback = null)
{

View File

@@ -16,6 +16,8 @@ class Themes extends AbstractPackageCollection
/**
* Local Themes Constructor
* @param bool $refresh
* @param callable $callback Either a function or callback in array notation
*/
public function __construct($refresh = false, $callback = null)
{

View File

@@ -1,6 +1,8 @@
<?php
namespace Grav\Common\GPM;
use Grav\Common\Utils;
class Response
{
/**
@@ -50,6 +52,7 @@ class Response
/**
* Sets the preferred method to use for making HTTP calls.
* @param string $method Default is `auto`
* @return Response
*/
public static function setMethod($method = 'auto')
{
@@ -64,8 +67,9 @@ class Response
/**
* Makes a request to the URL by using the preferred method
* @param string $uri URL to call
* @param array $options An array of parameters for both `curl` and `fopen`
* @param string $uri URL to call
* @param array $options An array of parameters for both `curl` and `fopen`
* @param callable $callback Either a function or callback in array notation
* @return string The response of the request
*/
public static function get($uri = '', $options = [], $callback = null)
@@ -74,6 +78,11 @@ class Response
throw new \RuntimeException('Could not start an HTTP request. `allow_url_open` is disabled and `cURL` is not available');
}
// disable time limit if possible to help with slow downloads
if (!Utils::isFunctionDisabled('set_time_limit') && !ini_get('safe_mode')) {
set_time_limit(0);
}
$options = array_replace_recursive(self::$defaults, $options);
$method = 'get' . ucfirst(strtolower(self::$method));

View File

@@ -114,7 +114,7 @@ class Grav extends Container
/** @var Uri $uri */
$uri = $c['uri'];
$path = rtrim($uri->path(), '/');
$path = $uri->path(); // Don't trim to support trailing slash default routes
$path = $path ?: '/';
$page = $pages->dispatch($path);
@@ -201,7 +201,10 @@ class Grav extends Container
// Use output buffering to prevent headers from being sent too early.
ob_start();
if ($this['config']->get('system.cache.gzip')) {
ob_start('ob_gzhandler');
// Enable zip/deflate with a fallback in case of if browser does not support compressing.
if(!ob_start("ob_gzhandler")) {
ob_start();
}
}
// Initialize the timezone
@@ -296,7 +299,10 @@ class Grav extends Container
if ($uri->isExternal($route)) {
$url = $route;
} else {
$url = rtrim($uri->rootUrl(), '/') .'/'. trim($route, '/');
if ($this['config']->get('system.pages.redirect_trailing_slash', true))
$url = rtrim($uri->rootUrl(), '/') .'/'. trim($route, '/'); // Remove trailing slash
else
$url = rtrim($uri->rootUrl(), '/') .'/'. ltrim($route, '/'); // Support trailing slash default routes
}
header("Location: {$url}", true, $code);
@@ -413,22 +419,25 @@ class Grav extends Container
public function shutdown()
{
if ($this['config']->get('system.debugger.shutdown.close_connection')) {
//stop user abort
// Prevent user abort.
if (function_exists('ignore_user_abort')) {
@ignore_user_abort(true);
}
// close the session
// Close the session.
if (isset($this['session'])) {
$this['session']->close();
}
// flush buffer if gzip buffer was started
if ($this['config']->get('system.cache.gzip')) {
ob_end_flush(); // gzhandler buffer
// Flush gzhandler buffer if gzip was enabled.
ob_end_flush();
} else {
// Otherwise prevent server from compressing the output.
header('Content-Encoding: none');
}
// get lengh and close the connection
// Get length and close the connection.
header('Content-Length: ' . ob_get_length());
header("Connection: close");
@@ -437,7 +446,7 @@ class Grav extends Container
@ob_flush();
flush();
// fix for fastcgi close connection issue
// Fix for fastcgi close connection issue.
if (function_exists('fastcgi_finish_request')) {
@fastcgi_finish_request();
}
@@ -457,6 +466,20 @@ class Grav extends Container
/** @var Uri $uri */
$uri = $this['uri'];
/** @var Config $config */
$config = $this['config'];
$uri_extension = $uri->extension();
$fallback_types = $config->get('system.media.allowed_fallback_types', null);
$supported_types = $config->get('media');
// Check whitelist first, then ensure extension is a valid media type
if (!empty($fallback_types) && !in_array($uri_extension, $fallback_types)) {
return;
} elseif (!array_key_exists($uri_extension, $supported_types)) {
return;
}
$path_parts = pathinfo($path);
$page = $this['pages']->dispatch($path_parts['dirname'], true);
if ($page) {
@@ -478,7 +501,6 @@ class Grav extends Container
}
// unsupported media type, try to download it...
$uri_extension = $uri->extension();
if ($uri_extension) {
$extension = $uri_extension;
} else {
@@ -491,7 +513,7 @@ class Grav extends Container
if ($extension) {
$download = true;
if (in_array(ltrim($extension, '.'), $this['config']->get('system.media.unsupported_inline_types', []))) {
if (in_array(ltrim($extension, '.'), $config->get('system.media.unsupported_inline_types', []))) {
$download = false;
}
Utils::download($page->path() . DIRECTORY_SEPARATOR . $uri->basename(), $download);

View File

@@ -131,7 +131,7 @@ class Truncator {
$inner .= $txt;
if ($remaining < 0) {
if (static::ellipsable($node)) {
$inner = preg_replace('/(?:[\s\pP]+|(?:&(?:[a-z]+|#[0-9]+);?))*$/', '', $inner).$opts['ellipsis'];
$inner = preg_replace('/(?:[\s\pP]+|(?:&(?:[a-z]+|#[0-9]+);?))*$/u', '', $inner).$opts['ellipsis'];
$opts['ellipsis'] = '';
$opts['was_truncated'] = true;
}

View File

@@ -162,7 +162,7 @@ class Language
*/
public function setActiveFromUri($uri)
{
$regex = '/(^\/(' . $this->getAvailable() . ')).*/';
$regex = '/(^\/(' . $this->getAvailable() . '))(?:\/.*|$)/i';
// if languages set
if ($this->enabled()) {

View File

@@ -1,12 +1,8 @@
<?php
namespace Grav\Common\Markdown;
use Grav\Common\Config\Config;
use Grav\Common\Debugger;
use Grav\Common\GravTrait;
use Grav\Common\Page\Medium\Medium;
use Grav\Common\Uri;
use Grav\Common\Utils;
/**
* A trait to add some custom processing to the identifyLink() method in Parsedown and ParsedownExtra
@@ -211,7 +207,7 @@ trait ParsedownGravTrait
// if there is no scheme, the file is local
if (!isset($url['scheme']) && (count($url) > 0)) {
// convert the URl is required
$excerpt['element']['attributes']['href'] = Uri::convertUrl($this->page, Uri::buildUrl($url), $type);
$excerpt['element']['attributes']['href'] = Uri::convertUrl($this->page, Uri::buildUrl($url), $type, true);
}
}

View File

@@ -36,6 +36,18 @@ class Collection extends Iterator
return $this->params;
}
/**
* Add a single page to a collection
*
* @param Page $page
* @return $this
*/
public function addPage(Page $page)
{
$this->items[$page->path()] = ['slug' => $page->slug()];
return $this;
}
/**
*
* Create a copy of this collection
@@ -96,6 +108,7 @@ class Collection extends Iterator
* Remove item from the list.
*
* @param Page|string|null $key
* @return $this|void
* @throws \InvalidArgumentException
*/
public function remove($key = null)
@@ -110,6 +123,7 @@ class Collection extends Iterator
}
parent::remove($key);
return $this;
}
/**

View File

@@ -2,8 +2,6 @@
namespace Grav\Common\Page;
use Grav\Common\Getters;
use Grav\Common\Grav;
use Grav\Common\Config\Config;
use Grav\Common\GravTrait;
use Grav\Common\Page\Medium\Medium;
use Grav\Common\Page\Medium\MediumFactory;

View File

@@ -1,13 +1,6 @@
<?php
namespace Grav\Common\Page\Medium;
use Grav\Common\Config\Config;
use Grav\Common\File\CompiledYamlFile;
use Grav\Common\Grav;
use Grav\Common\GravTrait;
use Grav\Common\Data\Blueprint;
use Grav\Common\Data\Data;
class AudioMedium extends Medium
{
use StaticResizeTrait;

View File

@@ -4,11 +4,20 @@ namespace Grav\Common\Page\Medium;
use Grav\Common\GravTrait;
use Gregwar\Image\Exceptions\GenerationError;
use RocketTheme\Toolbox\Event\Event;
use Gregwar\Image\Image;
class ImageFile extends \Gregwar\Image\Image
class ImageFile extends Image
{
use GravTrait;
/**
* Clear previously applied operations
*/
public function clearOperations()
{
$this->operations = [];
}
/**
* This is the same as the Gregwar Image class except this one fires a Grav Event on creation of new cached file
*

View File

@@ -52,7 +52,6 @@ class ImageMedium extends Medium
'forceResize' => [ 0, 1 ],
'cropResize' => [ 0, 1 ],
'crop' => [ 0, 1, 2, 3 ],
'cropResize' => [ 0, 1 ],
'zoomCrop' => [ 0, 1 ]
];
@@ -260,6 +259,7 @@ class ImageMedium extends Medium
if ($this->image) {
$this->image();
$this->image->clearOperations(); // Clear previously applied operations
$this->filter();
}
@@ -311,19 +311,23 @@ class ImageMedium extends Medium
}
/**
* Sets the quality of the image
* Sets or gets the quality of the image
*
* @param int $quality 0-100 quality
* @return Medium
*/
public function quality($quality)
public function quality($quality = null)
{
if (!$this->image) {
$this->image();
if ($quality) {
if (!$this->image) {
$this->image();
}
$this->quality = $quality;
return $this;
}
$this->quality = $quality;
return $this;
return $this->quality;
}
/**
@@ -359,6 +363,48 @@ class ImageMedium extends Medium
return empty($this->sizes) ? '100vw' : $this->sizes;
}
/**
* Allows to set the width attribute from Markdown or Twig
* Examples: ![Example](myimg.png?width=200&height=400)
* ![Example](myimg.png?resize=100,200&width=100&height=200)
* ![Example](myimg.png?width=auto&height=auto)
* ![Example](myimg.png?width&height)
* {{ page.media['myimg.png'].width().height().html }}
* {{ page.media['myimg.png'].resize(100,200).width(100).height(200).html }}
*
* @param mixed $value A value or 'auto' or empty to use the width of the image
* @return $this
*/
public function width($value = 'auto')
{
if (!$value || $value == 'auto')
$this->attributes['width'] = $this->get('width');
else
$this->attributes['width'] = $value;
return $this;
}
/**
* Allows to set the height attribute from Markdown or Twig
* Examples: ![Example](myimg.png?width=200&height=400)
* ![Example](myimg.png?resize=100,200&width=100&height=200)
* ![Example](myimg.png?width=auto&height=auto)
* ![Example](myimg.png?width&height)
* {{ page.media['myimg.png'].width().height().html }}
* {{ page.media['myimg.png'].resize(100,200).width(100).height(200).html }}
*
* @param mixed $value A value or 'auto' or empty to use the height of the image
* @return $this
*/
public function height($value = 'auto')
{
if (!$value || $value == 'auto')
$this->attributes['height'] = $this->get('height');
else
$this->attributes['height'] = $value;
return $this;
}
/**
* Forward the call to the image processing method.
*
@@ -470,4 +516,28 @@ class ImageMedium extends Medium
$this->__call($method, $params);
}
}
/**
* Return the image higher quality version
*
* @return ImageMedium the alternative version with higher quality
*/
public function higherQualityAlternative()
{
if ($this->alternatives) {
$max = reset($this->alternatives);
foreach($this->alternatives as $alternative)
{
if($alternative->quality() > $max->quality())
{
$max = $alternative;
}
}
return $max;
} else {
return $this;
}
}
}

View File

@@ -209,9 +209,13 @@ class Medium extends Data implements RenderableInterface
$style = '';
foreach ($this->styleAttributes as $key => $value) {
$style .= $key . ': ' . $value . ';';
if (is_numeric($key)) // Special case for inline style attributes, refer to style() method
$style .= $value;
else
$style .= $key . ': ' . $value . ';';
}
$attributes['style'] = $style;
if ($style)
$attributes['style'] = $style;
if (empty($attributes['title'])) {
if (!empty($title)) {
@@ -388,6 +392,19 @@ class Medium extends Data implements RenderableInterface
return $this->link($reset, $attributes);
}
/**
* Allows to add an inline style attribute from Markdown or Twig
* Example: ![Example](myimg.png?style=float:left)
*
* @param string $style
* @return $this
*/
public function style($style)
{
$this->styleAttributes[] = rtrim($style, ';') . ';';
return $this;
}
/**
* Allow any action to be called on this medium from twig or markdown
*
@@ -440,4 +457,5 @@ class Medium extends Data implements RenderableInterface
return $this->_thumbnail;
}
}

View File

@@ -1,13 +1,6 @@
<?php
namespace Grav\Common\Page\Medium;
use Grav\Common\Config\Config;
use Grav\Common\File\CompiledYamlFile;
use Grav\Common\Grav;
use Grav\Common\GravTrait;
use Grav\Common\Data\Blueprint;
use Grav\Common\Data\Data;
class VideoMedium extends Medium
{
use StaticResizeTrait;

View File

@@ -41,6 +41,7 @@ class Page
protected $folder;
protected $path;
protected $extension;
protected $url_extension;
protected $id;
protected $parent;
@@ -128,6 +129,7 @@ class Page
$this->modularTwig($this->slug[0] == '_');
$this->setPublishState();
$this->published();
$this->urlExtension();
// some extension logic
if (empty($extension)) {
@@ -136,6 +138,7 @@ class Page
$this->extension($extension);
}
// extract page language from page extension
$language = trim(basename($this->extension(), 'md'), '.') ?: null;
$this->language($language);
@@ -349,7 +352,6 @@ class Page
if (isset($this->header->last_modified)) {
$this->last_modified = (bool) $this->header->last_modified;
}
}
return $this->header;
@@ -957,6 +959,17 @@ class Page
return $this->extension;
}
public function urlExtension()
{
// if not set in the page get the value from system config
if (empty($this->url_extension)) {
$this->url_extension = trim(isset($this->header->append_url_extension) ? $this->header->append_url_extension : self::getGrav()['config']->get('system.pages.append_url_extension', false));
}
return $this->url_extension;
}
/**
* Gets and sets the expires field. If not set will return the default
*
@@ -1137,7 +1150,7 @@ class Page
$this->metadata = [];
// Set the Generator tag
$this->metadata['generator'] = array('name'=>'generator', 'content'=>'GravCMS ' . GRAV_VERSION);
$this->metadata['generator'] = array('name'=>'generator', 'content'=>'GravCMS');
// Get initial metadata for the page
$metadata = self::getGrav()['config']->get('site.metadata');
@@ -1262,7 +1275,7 @@ class Page
$rootUrl = $uri->rootUrl($include_host) . $pages->base();
$url = $rootUrl.'/'.trim($route, '/');
$url = $rootUrl.'/'.trim($route, '/') . $this->urlExtension();
// trim trailing / if not root
if ($url !== '/') {
@@ -1471,7 +1484,17 @@ class Page
*/
public function filePathClean()
{
return str_replace(ROOT_DIR, '', $this->filePath());
$path = str_replace(ROOT_DIR, '', $this->filePath());
return $path;
}
/**
* Returns the clean path to the page file
*/
public function relativePagePath()
{
$path = str_replace('/'.$this->name, '', $this->filePathClean());
return $path;
}
/**
@@ -1935,7 +1958,7 @@ class Page
// Format: @command.param
$cmd = $value;
$params = array();
} elseif (is_array($value) && count($value) == 1) {
} elseif (is_array($value) && count($value) == 1 && !is_int(key($value))) {
// Format: @command.param: { attr1: value1, attr2: value2 }
$cmd = (string) key($value);
$params = (array) current($value);
@@ -1957,51 +1980,92 @@ class Page
return $value;
}
/** @var Pages $pages */
$pages = self::getGrav()['pages'];
$parts = explode('.', $cmd);
$current = array_shift($parts);
$results = null;
$results = new Collection();
switch ($current) {
case '@self':
if (!empty($parts)) {
switch ($parts[0]) {
case 'modular':
// @self.modular: false (alternative to @self.children)
if (!empty($params) && $params[0] === false) {
$results = $this->children()->nonModular()->published();
$results = $this->children()->nonModular();
break;
}
$results = $this->children()->modular()->published();
$results = $this->children()->modular();
break;
case 'children':
$results = $this->children()->nonModular()->published();
$results = $this->children()->nonModular();
break;
case 'parent':
$collection = new Collection();
$results = $collection->addPage($this->parent());
break;
case 'siblings':
$results = $this->parent()->children()->remove($this->path());
break;
case 'descendants':
$results = $pages->all($this)->remove($this->path())->nonModular();
break;
}
}
$results = $results->published();
break;
case '@page':
$page = null;
if (!empty($params)) {
/** @var Pages $pages */
$pages = self::getGrav()['pages'];
$page = $this->find($params[0]);
}
list($what, $recurse) = array_pad($params, 2, null);
// safety check in case page is not found
if (!isset($page)) {
return $results;
}
if ($what == '@root') {
$page = $pages->root();
} else {
$page = $this->find($what);
// Handle a @page.descendants
if (!empty($parts)) {
switch ($parts[0]) {
case 'self':
$results = new Collection();
$results = $results->addPage($page);
break;
case 'descendants':
$results = $pages->all($page)->remove($page->path());
break;
case 'children':
$results = $page->children();
break;
}
} else {
$results = $page->children();
}
if ($page) {
if ($recurse) {
$results = $pages->all($page)->nonModular()->published();
} else {
$results = $page->children()->nonModular()->published();
}
}
$results = $results->nonModular()->published();
break;
case '@root':
if (!empty($parts) && $parts[0] == 'descendants') {
$results = $pages->all($pages->root())->nonModular()->published();
} else {
$results = $pages->root()->children()->nonModular()->published();
}
break;
case '@taxonomy':
// Gets a collection of pages by using one of the following formats:
// @taxonomy.category: blog

View File

@@ -272,6 +272,10 @@ class Pages
{
// Fetch page if there's a defined route to it.
$page = isset($this->routes[$url]) ? $this->get($this->routes[$url]) : null;
// Try without trailing slash
if (!$page && Utils::endsWith($url, '/')) {
$page = isset($this->routes[rtrim($url, '/')]) ? $this->get($this->routes[rtrim($url, '/')]) : null;
}
// Are we in the admin? this is important!
$not_admin = !isset($this->grav['admin']);

View File

@@ -4,7 +4,6 @@ namespace Grav\Common;
use Grav\Common\Config\Config;
use Grav\Common\Data\Blueprints;
use Grav\Common\Data\Data;
use Grav\Common\GravTrait;
use Grav\Common\File\CompiledYamlFile;
use RocketTheme\Toolbox\Event\EventDispatcher;
use RocketTheme\Toolbox\Event\EventSubscriberInterface;
@@ -122,6 +121,12 @@ class Plugins extends Iterator
// Load default configuration.
$file = CompiledYamlFile::instance("plugins://{$name}/{$name}.yaml");
// ensure the plugin exists physically
if (!$file->exists()) {
return null;
}
$obj = new Data($file->content(), $blueprint);
// Override with user configuration.

View File

@@ -171,6 +171,8 @@ class Themes extends Iterator
exit("Theme '$name' does not exist, unable to display page.");
}
$this->config->set('theme', $config->get('themes.' . $name));
if (empty($class)) {
$class = new Theme($grav, $config, $name);
}
@@ -282,11 +284,11 @@ class Themes extends Iterator
$class = substr($class, strlen($prefix));
// Replace namespace tokens to directory separators
$path = ltrim(preg_replace('#\\\|_(?!.+\\\)#', '/', $class), '/');
$path = strtolower(ltrim(preg_replace('#\\\|_(?!.+\\\)#', '/', $class), '/'));
$file = $locator->findResource("themes://{$path}/{$path}.php");
// Load class
if (stream_resolve_include_path($file)) {
if (file_exists($file)) {
return include_once($file);
}
}

View File

@@ -4,8 +4,6 @@ namespace Grav\Common\Twig;
use Grav\Common\Grav;
use Grav\Common\Config\Config;
use Grav\Common\Page\Page;
use Grav\Common\Inflector;
use Grav\Common\Utils;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RocketTheme\Toolbox\Event\Event;

View File

@@ -1,8 +1,6 @@
<?php
namespace Grav\Common\Twig;
use Grav\Common\GravTrait;
/**
* The Twig Environment class is a wrapper that handles configurable permissions
* for the Twig cache files

View File

@@ -70,6 +70,7 @@ class TwigExtension extends \Twig_Extension
new \Twig_SimpleFilter('randomize', [$this,'randomizeFilter']),
new \Twig_SimpleFilter('modulus', [$this,'modulusFilter']),
new \Twig_SimpleFilter('rtrim', [$this, 'rtrimFilter']),
new \Twig_SimpleFilter('pad', [$this, 'padFilter']),
new \Twig_SimpleFilter('safe_email', [$this,'safeEmailFilter']),
new \Twig_SimpleFilter('safe_truncate', ['\Grav\Common\Utils','safeTruncate']),
new \Twig_SimpleFilter('safe_truncate_html', ['\Grav\Common\Utils','safeTruncateHTML']),
@@ -94,14 +95,17 @@ 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('gist', [$this, 'gistFunc']),
new \Twig_SimpleFunction('nonce_field', [$this, 'nonceFieldFunc']),
new \Twig_simpleFunction('random_string', [$this, 'randomStringFunc']),
new \Twig_SimpleFunction('repeat', [$this, 'repeatFunc']),
new \Twig_SimpleFunction('string', [$this, 'stringFunc']),
new \Twig_simpleFunction('t', [$this, 'translate']),
new \Twig_simpleFunction('ta', [$this, 'translateArray']),
new \Twig_SimpleFunction('url', [$this, 'urlFunc']),
new \Twig_SimpleFunction('evaluate', [$this, 'evaluateFunc']),
];
}
@@ -534,6 +538,22 @@ class TwigExtension extends \Twig_Extension
return Utils::generateRandomString($count);
}
/**
* Pad a string to a certain length with another string
*
* @param $input
* @param $pad_length
* @param string $pad_string
* @param int $pad_type
*
* @return string
*/
public static function padFilter($input, $pad_length, $pad_string = " ", $pad_type = STR_PAD_RIGHT)
{
return str_pad($input, (int) $pad_length, $pad_string, $pad_type);
}
/**
* Cast a value to array
*
@@ -595,4 +615,22 @@ class TwigExtension extends \Twig_Extension
return false;
}
/**
* Used to add a nonce to a form. Call {{ nonce_field('action') }} specifying a string representing the action.
*
* For maximum protection, ensure that the string representing the action is as specific as possible.
*
* @todo evaluate if adding referrer or not
*
* @param string action the action
* @param string nonceParamName a custom nonce param name
*
* @return string the nonce input field
*/
public function nonceFieldFunc($action, $nonceParamName = 'nonce')
{
$string = '<input type="hidden" id="' . $nonceParamName . '" name="' . $nonceParamName . '" value="' . Utils::getNonce($action) .'" />';
return $string;
}
}

View File

@@ -2,7 +2,6 @@
namespace Grav\Common;
use Grav\Common\Page\Page;
use Grav\Common\Page\Pages;
/**
* The URI object provides information about the current URL
@@ -133,11 +132,16 @@ class Uri
// set the original basename
$this->basename = $parts['basename'];
// set the extension
if (isset($parts['extension'])) {
$this->extension = $parts['extension'];
}
$valid_page_types = implode('|', $config->get('system.pages.types'));
// Strip the file extension for valid page types
if (preg_match("/\.(".$valid_page_types.")$/", $parts['basename'])) {
$uri = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS). '/' .$parts['filename'];
$this->extension = $parts['extension'];
}
// set the new url
@@ -481,12 +485,14 @@ class Uri
/**
* Converts links from absolute '/' or relative (../..) to a grav friendly format
*
* @param $page the current page to use as reference
* @param Page|the $page the current page to use as reference
* @param string $markdown_url the URL as it was written in the markdown
* @param string $type the type of URL, image | link
* @param null $relative if null, will use system default, if true will use relative links internally
*
* @return string the more friendly formatted url
*/
public static function convertUrl(Page $page, $markdown_url, $type = 'link')
public static function convertUrl(Page $page, $markdown_url, $type = 'link', $relative = null)
{
$grav = Grav::instance();
@@ -500,7 +506,13 @@ class Uri
}
$pages_dir = $grav['locator']->findResource('page://');
$base_url = rtrim($grav['base_url'] . $grav['pages']->base(), '/') . $language_append;
if (is_null($relative)) {
$base = $grav['base_url'];
} else {
$base = $relative ? $grav['base_url_relative'] : $grav['base_url_absolute'];
}
$base_url = rtrim($base . $grav['pages']->base(), '/') . $language_append;
// if absolute and starts with a base_url move on
if (pathinfo($markdown_url, PATHINFO_DIRNAME) == '.' && $page->url() == '/') {
@@ -568,4 +580,20 @@ class Uri
return $normalized_url;
}
}
/**
* Adds the nonce to a URL for a specific action
*
* @param string $url the url
* @param string $action the action
* @param string $nonceParamName the param name to use
*
* @return string the url with the nonce
*/
public static function addNonce($url, $action, $nonceParamName = 'nonce')
{
$urlWithNonce = $url . '/' . $nonceParamName . Grav::instance()['config']->get('system.param_sep', ':') . Utils::getNonce($action);
return $urlWithNonce;
}
}

View File

@@ -40,6 +40,9 @@ class User extends Data
if (!isset($content['username'])) {
$content['username'] = $username;
}
if (!isset($content['state'])) {
$content['state'] = 'enabled';
}
$user = new User($content, $blueprint);
$user->file($file);
@@ -139,6 +142,10 @@ class User extends Data
return false;
}
if (isset($this->state) && $this->state !== 'enabled') {
return false;
}
return Utils::isPositive($this->get("access.{$action}"));
}

View File

@@ -100,6 +100,9 @@ abstract class Utils
return (object)array_merge((array)$obj1, (array)$obj2);
}
/**
* @return array
*/
public static function dateFormats()
{
$now = new DateTime();
@@ -300,6 +303,19 @@ abstract class Utils
return $root . implode('/', $ret);
}
/**
* @param $function
*
* @return bool
*/
public static function isFunctionDisabled($function)
{
return in_array($function, explode(',', ini_get('disable_functions')));
}
/**
* @return array
*/
public static function timezones()
{
$timezones = \DateTimeZone::listIdentifiers(\DateTimeZone::ALL);
@@ -327,6 +343,12 @@ abstract class Utils
}
/**
* @param array $source
* @param $fn
*
* @return array
*/
public static function arrayFilterRecursive(Array $source, $fn)
{
$result = array();
@@ -346,6 +368,11 @@ abstract class Utils
return $result;
}
/**
* @param $string
*
* @return bool
*/
public static function pathPrefixedByLangCode($string)
{
$languages_enabled = self::getGrav()['config']->get('system.languages.supported', []);
@@ -357,6 +384,11 @@ abstract class Utils
return false;
}
/**
* @param $date
*
* @return int
*/
public static function date2timestamp($date)
{
$config = self::getGrav()['config'];
@@ -384,7 +416,111 @@ abstract class Utils
*
* @return boolean
*/
public static function isPositive($value) {
public static function isPositive($value)
{
return in_array($value, [true, 1, '1', 'yes', 'on', 'true'], true);
}
/**
* Generates a nonce string to be hashed. Called by self::getNonce()
*
* @param string $action
* @param bool $plusOneTick if true, generates the token for the next tick (the next 12 hours)
*
* @return string the nonce string
*/
private static function generateNonceString($action, $plusOneTick = false)
{
if (isset(self::getGrav()['user'])) {
$user = self::getGrav()['user'];
$username = $user->username;
} else {
$username = false;
}
if (!$username) {
$username = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
}
$token = session_id();
$i = self::nonceTick();
if ($plusOneTick) {
$i++;
}
return ( $i . '|' . $action . '|' . $username . '|' . $token );
}
/**
* Get the time-dependent variable for nonce creation.
*
* @todo now a tick lasts a day. Once the day is passed, the nonce is not valid any more. Find a better way
* to ensure nonces issued near the end of the day do not expire in that small amount of time
*
* @return int the time part of the nonce. Changes once every 24 hours
*/
private static function nonceTick()
{
$secondsInHalfADay = 60 * 60 * 12;
return (int)ceil(time() / ( $secondsInHalfADay ));
}
/**
* Get hash of given string
*
* @param string $data string to hash
*
* @return string hashed value of $data, cut to 10 characters
*/
private static function hash($data)
{
$hash = password_hash($data, PASSWORD_DEFAULT);
return $hash;
}
/**
* Creates a hashed nonce tied to the passed action. Tied to the current user and time. The nonce for a given
* action is the same for 12 hours.
*
* @param string $action the action the nonce is tied to (e.g. save-user-admin or move-page-homepage)
* @param bool $plusOneTick if true, generates the token for the next tick (the next 12 hours)
*
* @return string the nonce
*/
public static function getNonce($action, $plusOneTick = false)
{
$nonce = self::hash(self::generateNonceString($action, $plusOneTick));
$nonce = str_replace('/', 'SLASH', $nonce);
return $nonce;
}
/**
* Verify the passed nonce for the give action
*
* @param string $nonce the nonce to verify
* @param string $action the action to verify the nonce to
*
* @return boolean verified or not
*/
public static function verifyNonce($nonce, $action)
{
$nonce = str_replace('SLASH', '/', $nonce);
//Nonce generated 0-12 hours ago
if (password_verify(self::generateNonceString($action), $nonce)) {
return true;
}
//Nonce generated 12-24 hours ago
$plusOneTick = true;
if (password_verify(self::generateNonceString($action, $plusOneTick), $nonce)) {
return true;
}
//Invalid nonce
return false;
}
}

View File

@@ -2,23 +2,17 @@
namespace Grav\Console\Cli;
use Grav\Common\Backup\ZipBackup;
use Grav\Console\ConsoleTrait;
use Grav\Console\ConsoleCommand;
use RocketTheme\Toolbox\File\JsonFile;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class BackupCommand
* @package Grav\Console\Cli
*/
class BackupCommand extends Command
class BackupCommand extends ConsoleCommand
{
use ConsoleTrait;
protected $source;
protected $progress;
@@ -42,21 +36,16 @@ class BackupCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->progress = new ProgressBar($output);
$this->progress = new ProgressBar($this->output);
$this->progress->setFormat('Archiving <cyan>%current%</cyan> files [<green>%bar%</green>] %elapsed:6s% %memory:6s%');
self::getGrav()['config']->init();
$destination = ($input->getArgument('destination')) ? $input->getArgument('destination') : null;
$destination = ($this->input->getArgument('destination')) ? $this->input->getArgument('destination') : null;
$log = JsonFile::instance(self::getGrav()['locator']->findResource("log://backup.log", true, true));
$backup = ZipBackup::backup($destination, [$this, 'output']);
@@ -66,16 +55,13 @@ class BackupCommand extends Command
]);
$log->save();
$output->writeln('');
$output->writeln('');
$this->output->writeln('');
$this->output->writeln('');
}
/**
* @param $folder
* @param $zipFile
* @param $exclusiveLength
* @param $progress
* @param $args
*/
public function output($args)
{

View File

@@ -2,20 +2,14 @@
namespace Grav\Console\Cli;
use Grav\Common\Filesystem\Folder;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Grav\Console\ConsoleCommand;
/**
* Class CleanCommand
* @package Grav\Console\Cli
*/
class CleanCommand extends Command
class CleanCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var array
*/
@@ -172,14 +166,10 @@ class CleanCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->cleanPaths();
}

View File

@@ -2,29 +2,24 @@
namespace Grav\Console\Cli;
use Grav\Common\Cache;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputInterface;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class ClearCacheCommand
* @package Grav\Console\Cli
*/
class ClearCacheCommand extends Command
class ClearCacheCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
*
*/
protected function configure()
{
$this
->setName("clear-cache")
->setDescription("Clears Grav cache")
->setName('clear-cache')
->setAliases(['clearcache'])
->setDescription('Clears Grav cache')
->addOption('all', null, InputOption::VALUE_NONE, 'If set will remove all including compiled, twig, doctrine caches')
->addOption('assets-only', null, InputOption::VALUE_NONE, 'If set will remove only assets/*')
->addOption('images-only', null, InputOption::VALUE_NONE, 'If set will remove only images/*')
@@ -33,14 +28,10 @@ class ClearCacheCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->cleanPaths();
}

View File

@@ -1,23 +1,16 @@
<?php
namespace Grav\Console\Cli;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Yaml\Yaml;
/**
* Class ComposerCommand
* @package Grav\Console\Cli
*/
class ComposerCommand extends Command
class ComposerCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var
*/
@@ -59,24 +52,19 @@ class ComposerCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$action = $this->input->getOption('install') ? 'install' : ($this->input->getOption('update') ? 'update' : 'install');
$action = $input->getOption('install') ? 'install' : ($input->getOption('update') ? 'update' : 'install');
if ($input->getOption('install')) {
if ($this->input->getOption('install')) {
$action = 'install';
}
// Updates composer first
$output->writeln("\nInstalling vendor dependencies");
$output->writeln($this->composerUpdate(GRAV_ROOT, $action));
$this->output->writeln("\nInstalling vendor dependencies");
$this->output->writeln($this->composerUpdate(GRAV_ROOT, $action));
}
}

View File

@@ -1,22 +1,17 @@
<?php
namespace Grav\Console\Cli;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Yaml\Yaml;
/**
* Class InstallCommand
* @package Grav\Console\Cli
*/
class InstallCommand extends Command
class InstallCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var
*/
@@ -51,24 +46,18 @@ class InstallCommand extends Command
'destination',
InputArgument::OPTIONAL,
'Where to install the required bits (default to current project)'
)
->setDescription("Installs the dependencies needed by Grav. Optionally can create symbolic links")
->setHelp('The <info>install</info> command installs the dependencies needed by Grav. Optionally can create symbolic links');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$dependencies_file = '.dependencies';
$this->destination = ($input->getArgument('destination')) ? $input->getArgument('destination') : ROOT_DIR;
$this->destination = ($this->input->getArgument('destination')) ? $this->input->getArgument('destination') : ROOT_DIR;
// fix trailing slash
$this->destination = rtrim($this->destination, DS) . DS;
@@ -78,7 +67,7 @@ class InstallCommand extends Command
$local_config_file = exec('eval echo ~/.grav/config');
if (file_exists($local_config_file)) {
$this->local_config = Yaml::parse($local_config_file);
$output->writeln('Read local config from <cyan>' . $local_config_file . '</cyan>');
$this->output->writeln('Read local config from <cyan>' . $local_config_file . '</cyan>');
}
}
@@ -88,22 +77,22 @@ class InstallCommand extends Command
} elseif (file_exists($this->destination . $dependencies_file)) {
$this->config = Yaml::parse($this->destination . $dependencies_file);
} else {
$output->writeln('<red>ERROR</red> Missing .dependencies file in <cyan>user/</cyan> folder');
$this->output->writeln('<red>ERROR</red> Missing .dependencies file in <cyan>user/</cyan> folder');
}
// If yaml config, process
if ($this->config) {
if (!$input->getOption('symlink')) {
if (!$this->input->getOption('symlink')) {
// Updates composer first
$output->writeln("\nInstalling vendor dependencies");
$output->writeln($this->composerUpdate(GRAV_ROOT, 'install'));
$this->output->writeln("\nInstalling vendor dependencies");
$this->output->writeln($this->composerUpdate(GRAV_ROOT, 'install'));
$this->gitclone();
} else {
$this->symlink();
}
} else {
$output->writeln('<red>ERROR</red> invalid YAML in ' . $dependencies_file);
$this->output->writeln('<red>ERROR</red> invalid YAML in ' . $dependencies_file);
}

View File

@@ -1,29 +1,25 @@
<?php
namespace Grav\Console\Cli;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class NewProjectCommand
* @package Grav\Console\Cli
*/
class NewProjectCommand extends Command
class NewProjectCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
*
*/
protected function configure()
{
$this
->setName("new-project")
->setName('new-project')
->setAliases(['newproject'])
->addArgument(
'destination',
InputArgument::REQUIRED,
@@ -35,37 +31,32 @@ class NewProjectCommand extends Command
InputOption::VALUE_NONE,
'Symlink the required bits'
)
->setDescription("Creates a new Grav project with all the dependencies installed")
->setHelp("The <info>new-project</info> command is a combination of the `setup` and `install` commands.\nCreates a new Grav instance and performs the installation of all the required dependencies.");
->setDescription('Creates a new Grav project with all the dependencies installed')
->setHelp('The <info>new-project</info> command is a combination of the `setup` and `install` commands.\nCreates a new Grav instance and performs the installation of all the required dependencies.');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$sandboxCommand = $this->getApplication()->find('sandbox');
$installCommand = $this->getApplication()->find('install');
$sandboxArguments = new ArrayInput(array(
'command' => 'sandbox',
'destination' => $input->getArgument('destination'),
'-s' => $input->getOption('symlink')
'destination' => $this->input->getArgument('destination'),
'-s' => $this->input->getOption('symlink')
));
$installArguments = new ArrayInput(array(
'command' => 'install',
'destination' => $input->getArgument('destination'),
'-s' => $input->getOption('symlink')
'destination' => $this->input->getArgument('destination'),
'-s' => $this->input->getOption('symlink')
));
$sandboxCommand->run($sandboxArguments, $output);
$installCommand->run($installArguments, $output);
$sandboxCommand->run($sandboxArguments, $this->output);
$installCommand->run($installArguments, $this->output);
}
}

View File

@@ -1,160 +1,34 @@
<?php
namespace Grav\Console\Cli;
use Grav\Common\Data\Blueprints;
use Grav\Common\File\CompiledYamlFile;
use Grav\Common\Filesystem\Folder;
use Grav\Common\User\User;
use Grav\Console\ConsoleTrait;
use RuntimeException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\Question;
use Grav\Console\ConsoleCommand;
/**
* Class CleanCommand
*
* @package Grav\Console\Cli
*/
class NewUserCommand extends Command
class NewUserCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* Configure the command
*/
protected function configure()
{
$this
->setName("newuser")
->setDescription("Creates a new user")
->setHelp('The <info>newuser</info> creates a new user file in user/accounts/ folder');
->setName('newuser')
->setDescription('DEPRECATED: Creates a new user')
->setHelp('The <info>newuser</info> from `bin/grav` has been deprecated. Please refer to `bin/plugin login new-user')
;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$helper = $this->getHelper('question');
$data = [];
$this->output->writeln('<green>Create new user</green>');
$this->output->writeln('');
// Get username and validate
$question = new Question('Enter a <yellow>username</yellow>: ', 'admin');
$question->setValidator(function ($value) {
if (!preg_match('/^[a-z0-9_-]{3,16}$/', $value)) {
throw new RuntimeException(
'Username should be between 3 and 16 characters, including lowercase letters, numbers, underscores, and hyphens. Uppercase letters, spaces, and special characters are not allowed'
);
}
if (file_exists(self::getGrav()['locator']->findResource('user://accounts/' . $value . YAML_EXT))) {
throw new RuntimeException(
'Username "'.$value.'" already exists, please pick another username'
);
}
return $value;
});
$username = $helper->ask($this->input, $this->output, $question);
// Get password and validate
$password = $this->askForPassword($helper, 'Enter a <yellow>password</yellow>: ', function ($password1) use ($helper) {
if (!preg_match('/(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}/', $password1)) {
throw new RuntimeException('Password must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters');
}
// Since input is hidden when prompting for passwords, the user is asked to repeat the password
return $this->askForPassword($helper, 'Repeat the <yellow>password</yellow>: ', function ($password2) use ($password1) {
if (strcmp($password2, $password1)) {
throw new RuntimeException('Passwords did not match.');
}
return $password2;
});
});
$data['password'] = $password;
// Get email and validate
$question = new Question('Enter an <yellow>email</yellow>: ');
$question->setValidator(function ($value) {
if (!preg_match('/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/', $value)) {
throw new RuntimeException(
'Not a valid email address'
);
}
return $value;
});
$data['email'] = $helper->ask($this->input, $this->output, $question);
// Choose permissions
$question = new ChoiceQuestion(
'Please choose a set of <yellow>permissions</yellow>:',
array('a'=>'admin access', 's'=>'site access', 'b'=>'admin and site access'),
'a'
);
$question->setErrorMessage('permissions %s is invalid.');
$permissions_choice = $helper->ask($this->input, $this->output, $question);
switch ($permissions_choice) {
case 'a':
$data['access']['admin'] = ['login' => true, 'super' => true];
break;
case 's':
$data['access']['site'] = ['login' => true];
break;
case 'b':
$data['access']['admin'] = ['login' => true, 'super' => true];
$data['access']['site'] = ['login' => true];
}
// Get fullname
$question = new Question('Enter a <yellow>fullname</yellow>: ');
$question->setValidator(function ($value) {
if ($value === null || trim($value) == '') {
throw new RuntimeException(
'Fullname is required'
);
}
return $value;
});
$data['fullname'] = $helper->ask($this->input, $this->output, $question);
// Get title
$question = new Question('Enter a <yellow>title</yellow>: ');
$data['title'] = $helper->ask($this->input, $this->output, $question);
// Create user object and save it
$user = new User($data);
$file = CompiledYamlFile::instance(self::getGrav()['locator']->findResource('user://accounts/' . $username . YAML_EXT, true, true));
$user->file($file);
$user->save();
$this->output->writeln('');
$this->output->writeln('<green>Success!</green> User <cyan>'. $username .'</cyan> created.');
}
/**
* Get password and validate.
*
* @param Helper $helper
* @param string $question
* @param callable $validator
*
* @return string
*/
protected function askForPassword(Helper $helper, $question, callable $validator)
{
$question = new Question($question);
$question->setValidator($validator);
$question->setHidden(true);
$question->setHiddenFallback(true);
return $helper->ask($this->input, $this->output, $question);
$this->output->writeln('<red>DEPRECATED COMMAND</red>');
$this->output->writeln(' <white>`bin/grav new-user`</white> has been <red>deprecated</red> in favor of the new <white>`bin/plugin login new-user`</white>');
}
}

View File

@@ -1,23 +1,17 @@
<?php
namespace Grav\Console\Cli;
use Grav\Console\ConsoleCommand;
use Grav\Common\Filesystem\Folder;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class SandboxCommand
* @package Grav\Console\Cli
*/
class SandboxCommand extends Command
class SandboxCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var array
*/
@@ -96,18 +90,14 @@ class SandboxCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->destination = $input->getArgument('destination');
$this->destination = $this->input->getArgument('destination');
// Symlink the Core Stuff
if ($input->getOption('symlink')) {
if ($this->input->getOption('symlink')) {
// Create Some core stuff if it doesn't exist
$this->createDirectories();

View File

@@ -0,0 +1,35 @@
<?php
namespace Grav\Console;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class ConsoleCommand
*
* @package Grav\Console
*/
class ConsoleCommand extends Command
{
use ConsoleTrait;
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->setupConsole($input, $output);
$this->serve();
}
/**
*
*/
protected function serve() { }
}

View File

@@ -2,20 +2,16 @@
namespace Grav\Console\Gpm;
use Grav\Common\GPM\GPM;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class IndexCommand
*
* @package Grav\Console\Gpm
*/
class IndexCommand extends Command
class IndexCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var
*/
@@ -39,19 +35,15 @@ class IndexCommand extends Command
'Force re-fetching the data from remote'
)
->setDescription("Lists the plugins and themes available for installation")
->setHelp('The <info>index</info> command lists the plugins and themes available for installation');
->setHelp('The <info>index</info> command lists the plugins and themes available for installation')
;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->gpm = new GPM($this->input->getOption('force'));
$this->data = $this->gpm->getRepository();
@@ -93,15 +85,15 @@ class IndexCommand extends Command
*/
private function versionDetails($package)
{
$list = $this->gpm->{'getUpdatable' . ucfirst($package->package_type)}();
$package = isset($list[$package->slug]) ? $list[$package->slug] : $package;
$type = ucfirst(preg_replace("/s$/", '', $package->package_type));
$list = $this->gpm->{'getUpdatable' . ucfirst($package->package_type)}();
$package = isset($list[$package->slug]) ? $list[$package->slug] : $package;
$type = ucfirst(preg_replace("/s$/", '', $package->package_type));
$updatable = $this->gpm->{'is' . $type . 'Updatable'}($package->slug);
$installed = $this->gpm->{'is' . $type . 'Installed'}($package->slug);
$local = $this->gpm->{'getInstalled' . $type}($package->slug);
$local = $this->gpm->{'getInstalled' . $type}($package->slug);
if (!$installed || !$updatable) {
$version = $installed ? $local->version : $package->version;
$version = $installed ? $local->version : $package->version;
$installed = !$installed ? ' (<magenta>not installed</magenta>)' : ' (<cyan>installed</cyan>)';
return str_pad(" [v<green>" . $version . "</green>]", 35) . $installed;

View File

@@ -2,21 +2,16 @@
namespace Grav\Console\Gpm;
use Grav\Common\GPM\GPM;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class InfoCommand
* @package Grav\Console\Gpm
*/
class InfoCommand extends Command
class InfoCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var
*/
@@ -49,20 +44,16 @@ class InfoCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->gpm = new GPM($this->input->getOption('force'));
$foundPackage = $this->gpm->findPackage($input->getArgument('package'));
$foundPackage = $this->gpm->findPackage($this->input->getArgument('package'));
if (!$foundPackage) {
$this->output->writeln("The package <cyan>'" . $input->getArgument('package') . "'</cyan> was not found in the Grav repository.");
$this->output->writeln("The package <cyan>'" . $this->input->getArgument('package') . "'</cyan> was not found in the Grav repository.");
$this->output->writeln('');
$this->output->writeln("You can list all the available packages by typing:");
$this->output->writeln(" <green>" . $this->argv . " index</green>");
@@ -70,7 +61,7 @@ class InfoCommand extends Command
exit;
}
$this->output->writeln("Found package <cyan>'" . $input->getArgument('package') . "'</cyan> under the '<green>" . ucfirst($foundPackage->package_type) . "</green>' section");
$this->output->writeln("Found package <cyan>'" . $this->input->getArgument('package') . "'</cyan> under the '<green>" . ucfirst($foundPackage->package_type) . "</green>' section");
$this->output->writeln('');
$this->output->writeln("<cyan>" . $foundPackage->name . "</cyan> [" . $foundPackage->slug . "]");
$this->output->writeln(str_repeat('-', strlen($foundPackage->name) + strlen($foundPackage->slug) + 3));

View File

@@ -5,14 +5,10 @@ use Grav\Common\Filesystem\Folder;
use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Installer;
use Grav\Common\GPM\Response;
use Grav\Common\Inflector;
use Grav\Common\Utils;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Yaml\Yaml;
@@ -23,10 +19,8 @@ define('GIT_REGEX', '/http[s]?:\/\/(?:.*@)?(github|bitbucket)(?:.org|.com)\/.*\/
* Class InstallCommand
* @package Grav\Console\Gpm
*/
class InstallCommand extends Command
class InstallCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var
*/
@@ -87,15 +81,10 @@ class InstallCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->gpm = new GPM($this->input->getOption('force'));
$this->destination = realpath($this->input->getOption('destination'));

View File

@@ -5,22 +5,17 @@ use Grav\Common\Filesystem\Folder;
use Grav\Common\GPM\Installer;
use Grav\Common\GPM\Response;
use Grav\Common\GPM\Upgrader;
use Grav\Console\ConsoleTrait;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
/**
* Class SelfupgradeCommand
* @package Grav\Console\Gpm
*/
class SelfupgradeCommand extends Command
class SelfupgradeCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var
*/
@@ -75,14 +70,10 @@ class SelfupgradeCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->upgrader = new Upgrader($this->input->getOption('force'));
$update = $this->upgrader->getAssets()['grav-update'];

View File

@@ -1,25 +1,19 @@
<?php
namespace Grav\Console\Gpm;
use Grav\Common\Filesystem\Folder;
use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Installer;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
/**
* Class UninstallCommand
* @package Grav\Console\Gpm
*/
class UninstallCommand extends Command
class UninstallCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var
*/
@@ -64,15 +58,10 @@ class UninstallCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->gpm = new GPM();
$packages = array_map('strtolower', $this->input->getArgument('package'));

View File

@@ -3,23 +3,18 @@ namespace Grav\Console\Gpm;
use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Installer;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
/**
* Class UpdateCommand
* @package Grav\Console\Gpm
*/
class UpdateCommand extends Command
class UpdateCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var
*/
@@ -85,15 +80,10 @@ class UpdateCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->gpm = new GPM($this->input->getOption('force'));
$this->destination = realpath($this->input->getOption('destination'));
$skip_prompt = $this->input->getOption('all-yes');

View File

@@ -3,21 +3,16 @@ namespace Grav\Console\Gpm;
use Grav\Common\GPM\GPM;
use Grav\Common\GPM\Upgrader;
use Grav\Console\ConsoleTrait;
use Symfony\Component\Console\Command\Command;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class VersionCommand
* @package Grav\Console\Gpm
*/
class VersionCommand extends Command
class VersionCommand extends ConsoleCommand
{
use ConsoleTrait;
/**
* @var
*/
@@ -46,15 +41,10 @@ class VersionCommand extends Command
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int|null|void
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function serve()
{
$this->setupConsole($input, $output);
$this->gpm = new GPM($this->input->getOption('force'));
$packages = $this->input->getArgument('package');