Add blueprints and fake content

This commit is contained in:
Paul Nicoué 2021-11-18 17:44:47 +01:00
parent 1ff19bf38f
commit 8235816462
592 changed files with 22385 additions and 31535 deletions

3
.gitignore vendored
View file

@ -11,6 +11,9 @@
/.vscode /.vscode
/.idea /.idea
# Plugins
/site/plugins/
# System files # System files
Icon Icon
.DS_Store .DS_Store

View file

@ -1,34 +0,0 @@
<img src="http://getkirby.com/assets/images/github/plainkit.jpg" width="300">
**Kirby: the CMS that adapts to any project, loved by developers and editors alike.**
The Plainkit is a minimal Kirby setup with the basics you need to start a project from scratch. It is the ideal choice if you are already familiar with Kirby and want to start step-by-step.
You can learn more about Kirby at [getkirby.com](https://getkirby.com).
### Try Kirby for free
You can try Kirby and the Plainkit on your local machine or on a test server as long as you need to make sure it is the right tool for your next project. … and when youre convinced, [buy your license](https://getkirby.com/buy).
### Get going
Read our guide on [how to get started with Kirby](https://getkirby.com/docs/guide/quickstart).
You can [download the latest version](https://github.com/getkirby/plainkit/archive/main.zip) of the Plainkit.
If you are familiar with Git, you can clone Kirby's Plainkit repository from Github.
git clone https://github.com/getkirby/plainkit.git
## What's Kirby?
- **[getkirby.com](https://getkirby.com)** Get to know the CMS.
- **[Try it](https://getkirby.com/try)** Take a test ride with our online demo. Or download one of our kits to get started.
- **[Documentation](https://getkirby.com/docs/guide)** Read the official guide, reference and cookbook recipes.
- **[Issues](https://github.com/getkirby/kirby/issues)** Report bugs and other problems.
- **[Feedback](https://feedback.getkirby.com)** You have an idea for Kirby? Share it.
- **[Forum](https://forum.getkirby.com)** Whenever you get stuck, don't hesitate to reach out for questions and support.
- **[Discord](https://chat.getkirby.com)** Hang out and meet the community.
- **[Twitter](https://twitter.com/getkirby)** Spread the word.
- **[Instagram](https://www.instagram.com/getkirby/)** Share your creations: #madewithkirby.
---
© 2009-2020 Bastian Allgeier (Bastian Allgeier GmbH)
[getkirby.com](https://getkirby.com) · [License agreement](https://getkirby.com/license)

View file

@ -1,26 +1,22 @@
{ {
"name": "getkirby/plainkit", "name": "paulnicoue/xiaowang",
"description": "Kirby Plainkit", "description": "Xiao Wang",
"type": "project", "type": "project",
"keywords": ["kirby", "cms", "starterkit"], "homepage": "https://xiaowang.fr",
"homepage": "https://getkirby.com",
"authors": [ "authors": [
{ {
"name": "Bastian Allgeier", "name": "Paul Nicoué",
"email": "bastian@getkirby.com", "email": "contact@paulnicoue.com",
"homepage": "https://getkirby.com" "homepage": "https://paulnicoue.com"
} }
], ],
"support": {
"email": "support@getkirby.com",
"issues": "https://github.com/getkirby/starterkit/issues",
"forum": "https://forum.getkirby.com",
"source": "https://github.com/getkirby/starterkit"
},
"require": { "require": {
"php": ">=7.3.0 <8.1.0", "php": ">=7.3.0 <8.1.0",
"getkirby/cms": "^3.5", "getkirby/cms": "^3.5",
"amteich/kirby-twig": "^4.1" "amteich/kirby-twig": "^4.1",
"sylvainjule/matomo": "^1.0",
"diesdasdigital/kirby-meta-knight": "^1.2",
"kirbyzone/sitemapper": "^1.2"
}, },
"scripts": { "scripts": {
"start": [ "start": [

261
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "114f3df5841d7c1e6c499a6bbcc2e380", "content-hash": "2b5816560ec69490f1f1ef0c8ae052f5",
"packages": [ "packages": [
{ {
"name": "amteich/kirby-twig", "name": "amteich/kirby-twig",
@ -101,22 +101,64 @@
"time": "2021-04-20T12:18:18+00:00" "time": "2021-04-20T12:18:18+00:00"
}, },
{ {
"name": "filp/whoops", "name": "diesdasdigital/kirby-meta-knight",
"version": "2.12.1", "version": "1.2.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/filp/whoops.git", "url": "https://github.com/diesdasdigital/kirby-meta-knight.git",
"reference": "c13c0be93cff50f88bbd70827d993026821914dd" "reference": "9c3da53a3abee5ffdd95c1363d679e9395794715"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/c13c0be93cff50f88bbd70827d993026821914dd", "url": "https://api.github.com/repos/diesdasdigital/kirby-meta-knight/zipball/9c3da53a3abee5ffdd95c1363d679e9395794715",
"reference": "c13c0be93cff50f88bbd70827d993026821914dd", "reference": "9c3da53a3abee5ffdd95c1363d679e9395794715",
"shasum": ""
},
"require": {
"getkirby/composer-installer": "^1.1"
},
"type": "kirby-plugin",
"autoload": {
"psr-4": {
"diesdasdigital\\kirby-meta-knight\\": "src/models/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jonathan Muth",
"email": "jonathan@diesdas.digital",
"homepage": "https://diesdas.digital",
"role": "Developer"
}
],
"description": "Meta Knight SEO for Kirby",
"support": {
"issues": "https://github.com/diesdasdigital/kirby-meta-knight/issues",
"source": "https://github.com/diesdasdigital/kirby-meta-knight/tree/1.2.2"
},
"time": "2021-11-16T12:41:33+00:00"
},
{
"name": "filp/whoops",
"version": "2.14.4",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "f056f1fe935d9ed86e698905a957334029899895"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/f056f1fe935d9ed86e698905a957334029899895",
"reference": "f056f1fe935d9ed86e698905a957334029899895",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^5.5.9 || ^7.0 || ^8.0", "php": "^5.5.9 || ^7.0 || ^8.0",
"psr/log": "^1.0.1" "psr/log": "^1.0.1 || ^2.0 || ^3.0"
}, },
"require-dev": { "require-dev": {
"mockery/mockery": "^0.9 || ^1.0", "mockery/mockery": "^0.9 || ^1.0",
@ -161,7 +203,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/filp/whoops/issues", "issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.12.1" "source": "https://github.com/filp/whoops/tree/2.14.4"
}, },
"funding": [ "funding": [
{ {
@ -169,33 +211,34 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-04-25T12:00:00+00:00" "time": "2021-10-03T12:00:00+00:00"
}, },
{ {
"name": "getkirby/cms", "name": "getkirby/cms",
"version": "3.5.7.1", "version": "3.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/getkirby/kirby.git", "url": "https://github.com/getkirby/kirby.git",
"reference": "c77ccb82944b5fa0e3a453b4e203bd697e96330d" "reference": "9ea05e38dbeb471657e3066651568fc29763ef06"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/getkirby/kirby/zipball/c77ccb82944b5fa0e3a453b4e203bd697e96330d", "url": "https://api.github.com/repos/getkirby/kirby/zipball/9ea05e38dbeb471657e3066651568fc29763ef06",
"reference": "c77ccb82944b5fa0e3a453b4e203bd697e96330d", "reference": "9ea05e38dbeb471657e3066651568fc29763ef06",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"claviska/simpleimage": "3.6.3", "claviska/simpleimage": "3.6.3",
"ext-ctype": "*", "ext-ctype": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"filp/whoops": "2.12.1", "filp/whoops": "2.14.4",
"getkirby/composer-installer": "^1.2.0", "getkirby/composer-installer": "^1.2.1",
"laminas/laminas-escaper": "2.7.0", "laminas/laminas-escaper": "2.9.0",
"michelf/php-smartypants": "1.8.1", "michelf/php-smartypants": "1.8.1",
"mustangostang/spyc": "0.6.3", "mustangostang/spyc": "0.6.3",
"php": ">=7.3.0 <8.1.0", "php": ">=7.4.0 <8.1.0",
"phpmailer/phpmailer": "6.5.0", "phpmailer/phpmailer": "6.5.1",
"psr/log": "1.1.4",
"true/punycode": "2.1.1" "true/punycode": "2.1.1"
}, },
"type": "kirby-cms", "type": "kirby-cms",
@ -241,7 +284,7 @@
"type": "custom" "type": "custom"
} }
], ],
"time": "2021-07-07T09:21:03+00:00" "time": "2021-11-16T13:49:22+00:00"
}, },
{ {
"name": "getkirby/composer-installer", "name": "getkirby/composer-installer",
@ -291,28 +334,64 @@
"time": "2020-12-28T12:54:39+00:00" "time": "2020-12-28T12:54:39+00:00"
}, },
{ {
"name": "laminas/laminas-escaper", "name": "kirbyzone/sitemapper",
"version": "2.7.0", "version": "1.2.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laminas/laminas-escaper.git", "url": "https://github.com/kirbyzone/sitemapper.git",
"reference": "5e04bc5ae5990b17159d79d331055e2c645e5cc5" "reference": "f94551265d222bae844ad29d0a6a5b5f3737aa48"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/5e04bc5ae5990b17159d79d331055e2c645e5cc5", "url": "https://api.github.com/repos/kirbyzone/sitemapper/zipball/f94551265d222bae844ad29d0a6a5b5f3737aa48",
"reference": "5e04bc5ae5990b17159d79d331055e2c645e5cc5", "reference": "f94551265d222bae844ad29d0a6a5b5f3737aa48",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"laminas/laminas-zendframework-bridge": "^1.0", "getkirby/composer-installer": "^1.1"
"php": "^7.3 || ~8.0.0"
}, },
"replace": { "type": "kirby-plugin",
"zendframework/zend-escaper": "^2.6.1" "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kirbyzone",
"email": "support@kirby.zone",
"homepage": "https://kirby.zone"
}
],
"description": "Kirbyzone's Automatic Sitemap Generator Plugin for Kirby",
"homepage": "https://github.com/kirbyzone/sitemapper",
"support": {
"issues": "https://github.com/kirbyzone/sitemapper/issues",
"source": "https://github.com/kirbyzone/sitemapper"
},
"time": "2021-08-16T07:29:36+00:00"
},
{
"name": "laminas/laminas-escaper",
"version": "2.9.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-escaper.git",
"reference": "891ad70986729e20ed2e86355fcf93c9dc238a5f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/891ad70986729e20ed2e86355fcf93c9dc238a5f",
"reference": "891ad70986729e20ed2e86355fcf93c9dc238a5f",
"shasum": ""
},
"require": {
"php": "^7.3 || ~8.0.0 || ~8.1.0"
},
"conflict": {
"zendframework/zend-escaper": "*"
}, },
"require-dev": { "require-dev": {
"laminas/laminas-coding-standard": "~1.0.0", "laminas/laminas-coding-standard": "~2.3.0",
"phpunit/phpunit": "^9.3", "phpunit/phpunit": "^9.3",
"psalm/plugin-phpunit": "^0.12.2", "psalm/plugin-phpunit": "^0.12.2",
"vimeo/psalm": "^3.16" "vimeo/psalm": "^3.16"
@ -351,69 +430,7 @@
"type": "community_bridge" "type": "community_bridge"
} }
], ],
"time": "2020-11-17T21:26:43+00:00" "time": "2021-09-02T17:10:53+00:00"
},
{
"name": "laminas/laminas-zendframework-bridge",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-zendframework-bridge.git",
"reference": "bf180a382393e7db5c1e8d0f2ec0c4af9c724baf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/bf180a382393e7db5c1e8d0f2ec0c4af9c724baf",
"reference": "bf180a382393e7db5c1e8d0f2ec0c4af9c724baf",
"shasum": ""
},
"require": {
"php": "^7.3 || ~8.0.0 || ~8.1.0"
},
"require-dev": {
"phpunit/phpunit": "^9.3",
"psalm/plugin-phpunit": "^0.15.1",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.6"
},
"type": "library",
"extra": {
"laminas": {
"module": "Laminas\\ZendFrameworkBridge"
}
},
"autoload": {
"files": [
"src/autoload.php"
],
"psr-4": {
"Laminas\\ZendFrameworkBridge\\": "src//"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Alias legacy ZF class names to Laminas Project equivalents.",
"keywords": [
"ZendFramework",
"autoloading",
"laminas",
"zf"
],
"support": {
"forum": "https://discourse.laminas.dev/",
"issues": "https://github.com/laminas/laminas-zendframework-bridge/issues",
"rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom",
"source": "https://github.com/laminas/laminas-zendframework-bridge"
},
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2021-09-03T17:53:30+00:00"
}, },
{ {
"name": "league/color-extractor", "name": "league/color-extractor",
@ -579,16 +596,16 @@
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.5.0", "version": "v6.5.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "a5b5c43e50b7fba655f793ad27303cd74c57363c" "reference": "dd803df5ad7492e1b40637f7ebd258fee5ca7355"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a5b5c43e50b7fba655f793ad27303cd74c57363c", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/dd803df5ad7492e1b40637f7ebd258fee5ca7355",
"reference": "a5b5c43e50b7fba655f793ad27303cd74c57363c", "reference": "dd803df5ad7492e1b40637f7ebd258fee5ca7355",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -600,10 +617,12 @@
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"doctrine/annotations": "^1.2", "doctrine/annotations": "^1.2",
"php-parallel-lint/php-console-highlighter": "^0.5.0",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpcompatibility/php-compatibility": "^9.3.5", "phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest", "roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.5.6", "squizlabs/php_codesniffer": "^3.6.0",
"yoast/phpunit-polyfills": "^0.2.0" "yoast/phpunit-polyfills": "^1.0.0"
}, },
"suggest": { "suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
@ -643,7 +662,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": { "support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues", "issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.5.0" "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.5.1"
}, },
"funding": [ "funding": [
{ {
@ -651,7 +670,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-06-16T14:33:43+00:00" "time": "2021-08-18T09:14:16+00:00"
}, },
{ {
"name": "psr/log", "name": "psr/log",
@ -703,6 +722,44 @@
}, },
"time": "2021-05-03T11:20:27+00:00" "time": "2021-05-03T11:20:27+00:00"
}, },
{
"name": "sylvainjule/matomo",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/sylvainjule/kirby-matomo.git",
"reference": "11d754eb15f7c37cf0877095e50b407f66715096"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sylvainjule/kirby-matomo/zipball/11d754eb15f7c37cf0877095e50b407f66715096",
"reference": "11d754eb15f7c37cf0877095e50b407f66715096",
"shasum": ""
},
"require": {
"getkirby/composer-installer": "^1.1"
},
"type": "kirby-plugin",
"extra": {
"installer-name": "matomo"
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sylvain Julé",
"email": "contact@sylvain-jule.fr"
}
],
"description": "Matomo helpers and panel sections for Kirby",
"support": {
"issues": "https://github.com/sylvainjule/kirby-matomo/issues",
"source": "https://github.com/sylvainjule/kirby-matomo/tree/1.0.6"
},
"time": "2020-12-23T19:00:39+00:00"
},
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.23.0", "version": "v1.23.0",

View file

@ -0,0 +1,4 @@
/galerie-1:
lock:
user: 7C7A1Zba
time: 1637246291

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -0,0 +1,17 @@
Alt-text:
----
Caption:
----
File-type: image
----
Template: artwork
----
Sort: 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -0,0 +1,17 @@
Alt-text:
----
Caption:
----
File-type: image
----
Template: artwork
----
Sort: 2

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -0,0 +1,17 @@
Alt-text:
----
Caption:
----
File-type: image
----
Template: artwork
----
Sort: 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -0,0 +1,17 @@
Alt-text:
----
Caption:
----
File-type: image
----
Template: artwork
----
Sort: 5

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -0,0 +1,17 @@
Alt-text:
----
Caption:
----
File-type: image
----
Template: artwork
----
Sort: 6

Binary file not shown.

View file

@ -0,0 +1,17 @@
Alt-text:
----
Caption:
----
File-type: video
----
Template: artwork
----
Sort: 3

Binary file not shown.

View file

@ -0,0 +1,17 @@
Alt-text:
----
Caption:
----
File-type: video
----
Template: artwork
----
Sort: 7

View file

@ -0,0 +1,45 @@
Title: Galerie 1
----
Text: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eget nulla facilisi etiam dignissim. Felis donec et odio pellentesque. Et malesuada fames ac turpis egestas. Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Lorem donec massa sapien faucibus et molestie ac feugiat. Mauris augue neque gravida in fermentum et sollicitudin. At urna condimentum mattis pellentesque. Dignissim convallis aenean et tortor at. Sit amet massa vitae tortor condimentum lacinia. Sollicitudin tempor id eu nisl nunc mi ipsum. Nibh nisl condimentum id venenatis. Scelerisque in dictum non consectetur a erat nam at. Felis imperdiet proin fermentum leo vel orci porta non.
----
Meta-description:
----
Meta-image:
----
Og-image:
----
Og-type: article
----
Twitter-image:
----
Robots-noindex: default
----
Robots-nofollow: default
----
Robots-noarchive: default
----
Robots-noimageindex: default
----
Robots-nosnippet: default

View file

@ -0,0 +1,45 @@
Title: Galerie 2
----
Text:
----
Meta-description:
----
Meta-image:
----
Og-image:
----
Og-type: article
----
Twitter-image:
----
Robots-noindex: default
----
Robots-nofollow: default
----
Robots-noarchive: default
----
Robots-noimageindex: default
----
Robots-nosnippet: default

View file

@ -0,0 +1,45 @@
Title: Galerie 3
----
Text:
----
Meta-description:
----
Meta-image:
----
Og-image:
----
Og-type: article
----
Twitter-image:
----
Robots-noindex: default
----
Robots-nofollow: default
----
Robots-noarchive: default
----
Robots-noimageindex: default
----
Robots-nosnippet: default

View file

@ -0,0 +1,45 @@
Title: Galerie 4
----
Text:
----
Meta-description:
----
Meta-image:
----
Og-image:
----
Og-type: article
----
Twitter-image:
----
Robots-noindex: default
----
Robots-nofollow: default
----
Robots-noarchive: default
----
Robots-noimageindex: default
----
Robots-nosnippet: default

View file

@ -0,0 +1,45 @@
Title: Galerie 5
----
Text:
----
Meta-description:
----
Meta-image:
----
Og-image:
----
Og-type: article
----
Twitter-image:
----
Robots-noindex: default
----
Robots-nofollow: default
----
Robots-noarchive: default
----
Robots-noimageindex: default
----
Robots-nosnippet: default

3
content/accueil/.lock Normal file
View file

@ -0,0 +1,3 @@
/accueil:
unlock:
- YWFgwsvN

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -0,0 +1,5 @@
Alternative-text: Exemple de texte alternatif
----
Template: image

41
content/accueil/home.txt Normal file
View file

@ -0,0 +1,41 @@
Title: Accueil
----
Meta-description:
----
Meta-image:
----
Og-image:
----
Og-type: website
----
Twitter-image:
----
Robots-noindex: default
----
Robots-nofollow: default
----
Robots-noarchive: default
----
Robots-noimageindex: default
----
Robots-nosnippet: default

View file

@ -0,0 +1,49 @@
Title: Biographie
----
Text:
Interdum posuere lorem ipsum dolor sit. Volutpat lacus laoreet non curabitur gravida. Facilisis magna etiam tempor orci eu lobortis. Eu augue ut lectus arcu bibendum at. Mi eget mauris pharetra et ultrices neque. Mi ipsum faucibus vitae aliquet nec. Vitae justo eget magna fermentum iaculis eu non diam. Sed felis eget velit aliquet sagittis id consectetur purus ut. Platea dictumst quisque sagittis purus sit amet volutpat. Senectus et netus et malesuada fames ac. Id semper risus in hendrerit gravida rutrum quisque. A scelerisque purus semper eget duis at tellus at urna. Lectus nulla at volutpat diam ut. Consectetur a erat nam at lectus urna. Dui accumsan sit amet nulla. Imperdiet proin fermentum leo vel orci. Vestibulum lectus mauris ultrices eros. Diam quis enim lobortis scelerisque fermentum dui faucibus in. Semper auctor neque vitae tempus quam pellentesque nec nam. Elit duis tristique sollicitudin nibh sit amet commodo.
Velit sed ullamcorper morbi tincidunt ornare massa eget egestas. Egestas fringilla phasellus faucibus scelerisque eleifend donec pretium. Dictum varius duis at consectetur lorem donec massa sapien faucibus. Porta nibh venenatis cras sed felis eget velit aliquet sagittis. Sed id semper risus in. Aliquet porttitor lacus luctus accumsan tortor. Quam adipiscing vitae proin sagittis nisl. A iaculis at erat pellentesque adipiscing. Adipiscing bibendum est ultricies integer quis auctor elit sed vulputate. Pretium nibh ipsum consequat nisl vel pretium lectus quam id. Tellus id interdum velit laoreet id donec ultrices. Fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque. Nunc sed blandit libero volutpat sed cras. Odio eu feugiat pretium nibh ipsum consequat nisl vel.
----
Meta-description:
----
Meta-image:
----
Og-image:
----
Og-type: website
----
Twitter-image:
----
Robots-noindex: default
----
Robots-nofollow: default
----
Robots-noarchive: default
----
Robots-noimageindex: default
----
Robots-nosnippet: default

View file

@ -1 +1,21 @@
Title: Error Title: Erreur
----
Robots-noindex: enabled
----
Robots-nofollow: enabled
----
Robots-noarchive: enabled
----
Robots-noimageindex: enabled
----
Robots-nosnippet: enabled

BIN
content/firefox-logo-0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View file

@ -0,0 +1 @@
File-type: image

View file

@ -1 +0,0 @@
Title: Home

View file

@ -1 +1,37 @@
Title: Site Title Title: Xiao Wang
----
Favicon:
----
Email: exemple@gmail.com
----
Instagram: https://www.instagram.com/exemple/
----
Meta-description:
----
Robots-noindex: disabled
----
Robots-nofollow: disabled
----
Robots-noarchive: disabled
----
Robots-noimageindex: disabled
----
Robots-nosnippet: disabled

View file

@ -5,7 +5,7 @@
* stop at older or too recent versions * stop at older or too recent versions
*/ */
if ( if (
version_compare(PHP_VERSION, '7.3.0', '>=') === false || version_compare(PHP_VERSION, '7.4.0', '>=') === false ||
version_compare(PHP_VERSION, '8.1.0', '<') === false version_compare(PHP_VERSION, '8.1.0', '<') === false
) { ) {
die(include __DIR__ . '/views/php.php'); die(include __DIR__ . '/views/php.php');

View file

@ -1,7 +1,7 @@
## ##
## Bundle of CA Root Certificates ## Bundle of CA Root Certificates
## ##
## Certificate data from Mozilla as of: Mon Jul 5 21:35:54 2021 GMT ## Certificate data from Mozilla as of: Tue Oct 26 03:12:05 2021 GMT
## ##
## This is a bundle of X.509 certificates of public Certificate Authorities ## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates ## (CA). These were automatically extracted from Mozilla's root certificates
@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile. ## Just configure this file as the SSLCACertificateFile.
## ##
## Conversion done with mk-ca-bundle.pl version 1.28. ## Conversion done with mk-ca-bundle.pl version 1.28.
## SHA256: c8f6733d1ff4e6a4769c182971a1234f95ae079247a9c439a13423fe8ba5c24f ## SHA256: bb36818a81feaa4cca61101e6d6276cd09e972efcb08112dfed846918ca41d7f
## ##
@ -381,26 +381,6 @@ mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
-----END CERTIFICATE----- -----END CERTIFICATE-----
DST Root CA X3
==============
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----
SwissSign Gold CA - G2 SwissSign Gold CA - G2
====================== ======================
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
@ -3172,3 +3152,81 @@ WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj
OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck
bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
-----END CERTIFICATE----- -----END CERTIFICATE-----
TunTrust Root CA
================
-----BEGIN CERTIFICATE-----
MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG
A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj
dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw
NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD
ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz
2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b
bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7
NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd
gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW
VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f
Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ
juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas
DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS
VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI
04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0
90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl
0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd
Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY
YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp
adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x
xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP
jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM
MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z
ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r
AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
-----END CERTIFICATE-----
HARICA TLS RSA Root CA 2021
===========================
-----BEGIN CERTIFICATE-----
MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG
EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz
OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl
bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB
IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN
JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu
a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y
Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K
5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv
dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR
0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH
GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm
haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ
CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE
AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU
EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq
QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD
QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR
j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5
vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0
qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6
Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/
PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn
kf3/W9b3raYvAwtt41dU63ZTGI0RmLo=
-----END CERTIFICATE-----
HARICA TLS ECC Root CA 2021
===========================
-----BEGIN CERTIFICATE-----
MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH
UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD
QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX
DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj
IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv
b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l
AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b
ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW
0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi
rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw
CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
-----END CERTIFICATE-----

View file

@ -8,7 +8,7 @@
"core" "core"
], ],
"homepage": "https://getkirby.com", "homepage": "https://getkirby.com",
"version": "3.5.7.1", "version": "3.6.0",
"license": "proprietary", "license": "proprietary",
"authors": [ "authors": [
{ {
@ -18,16 +18,17 @@
} }
], ],
"require": { "require": {
"php": ">=7.3.0 <8.1.0", "php": ">=7.4.0 <8.1.0",
"ext-ctype": "*", "ext-ctype": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"claviska/simpleimage": "3.6.3", "claviska/simpleimage": "3.6.3",
"filp/whoops": "2.12.1", "filp/whoops": "2.14.4",
"getkirby/composer-installer": "^1.2.0", "getkirby/composer-installer": "^1.2.1",
"laminas/laminas-escaper": "2.7.0", "laminas/laminas-escaper": "2.9.0",
"michelf/php-smartypants": "1.8.1", "michelf/php-smartypants": "1.8.1",
"mustangostang/spyc": "0.6.3", "mustangostang/spyc": "0.6.3",
"phpmailer/phpmailer": "6.5.0", "phpmailer/phpmailer": "6.5.1",
"psr/log": "1.1.4",
"true/punycode": "2.1.1" "true/punycode": "2.1.1"
}, },
"config": { "config": {
@ -73,5 +74,6 @@
"issues": "https://github.com/getkirby/kirby/issues", "issues": "https://github.com/getkirby/kirby/issues",
"forum": "https://forum.getkirby.com", "forum": "https://forum.getkirby.com",
"source": "https://github.com/getkirby/kirby" "source": "https://github.com/getkirby/kirby"
} },
"_comment": "TODO: psr/log is not used by Kirby; drop pinned version when Kirby no longer supports PHP 7"
} }

129
kirby/composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "c087786719948c60e5d74492f70440a5", "content-hash": "8712d96f826f859411fec3cce4f16e63",
"packages": [ "packages": [
{ {
"name": "claviska/simpleimage", "name": "claviska/simpleimage",
@ -57,21 +57,21 @@
}, },
{ {
"name": "filp/whoops", "name": "filp/whoops",
"version": "2.12.1", "version": "2.14.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/filp/whoops.git", "url": "https://github.com/filp/whoops.git",
"reference": "c13c0be93cff50f88bbd70827d993026821914dd" "reference": "f056f1fe935d9ed86e698905a957334029899895"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/c13c0be93cff50f88bbd70827d993026821914dd", "url": "https://api.github.com/repos/filp/whoops/zipball/f056f1fe935d9ed86e698905a957334029899895",
"reference": "c13c0be93cff50f88bbd70827d993026821914dd", "reference": "f056f1fe935d9ed86e698905a957334029899895",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^5.5.9 || ^7.0 || ^8.0", "php": "^5.5.9 || ^7.0 || ^8.0",
"psr/log": "^1.0.1" "psr/log": "^1.0.1 || ^2.0 || ^3.0"
}, },
"require-dev": { "require-dev": {
"mockery/mockery": "^0.9 || ^1.0", "mockery/mockery": "^0.9 || ^1.0",
@ -116,7 +116,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/filp/whoops/issues", "issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.12.1" "source": "https://github.com/filp/whoops/tree/2.14.4"
}, },
"funding": [ "funding": [
{ {
@ -124,7 +124,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-04-25T12:00:00+00:00" "time": "2021-10-03T12:00:00+00:00"
}, },
{ {
"name": "getkirby/composer-installer", "name": "getkirby/composer-installer",
@ -175,27 +175,26 @@
}, },
{ {
"name": "laminas/laminas-escaper", "name": "laminas/laminas-escaper",
"version": "2.7.0", "version": "2.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laminas/laminas-escaper.git", "url": "https://github.com/laminas/laminas-escaper.git",
"reference": "5e04bc5ae5990b17159d79d331055e2c645e5cc5" "reference": "891ad70986729e20ed2e86355fcf93c9dc238a5f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/5e04bc5ae5990b17159d79d331055e2c645e5cc5", "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/891ad70986729e20ed2e86355fcf93c9dc238a5f",
"reference": "5e04bc5ae5990b17159d79d331055e2c645e5cc5", "reference": "891ad70986729e20ed2e86355fcf93c9dc238a5f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"laminas/laminas-zendframework-bridge": "^1.0", "php": "^7.3 || ~8.0.0 || ~8.1.0"
"php": "^7.3 || ~8.0.0"
}, },
"replace": { "conflict": {
"zendframework/zend-escaper": "^2.6.1" "zendframework/zend-escaper": "*"
}, },
"require-dev": { "require-dev": {
"laminas/laminas-coding-standard": "~1.0.0", "laminas/laminas-coding-standard": "~2.3.0",
"phpunit/phpunit": "^9.3", "phpunit/phpunit": "^9.3",
"psalm/plugin-phpunit": "^0.12.2", "psalm/plugin-phpunit": "^0.12.2",
"vimeo/psalm": "^3.16" "vimeo/psalm": "^3.16"
@ -234,69 +233,7 @@
"type": "community_bridge" "type": "community_bridge"
} }
], ],
"time": "2020-11-17T21:26:43+00:00" "time": "2021-09-02T17:10:53+00:00"
},
{
"name": "laminas/laminas-zendframework-bridge",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-zendframework-bridge.git",
"reference": "13af2502d9bb6f7d33be2de4b51fb68c6cdb476e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/13af2502d9bb6f7d33be2de4b51fb68c6cdb476e",
"reference": "13af2502d9bb6f7d33be2de4b51fb68c6cdb476e",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3",
"psalm/plugin-phpunit": "^0.15.1",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.6"
},
"type": "library",
"extra": {
"laminas": {
"module": "Laminas\\ZendFrameworkBridge"
}
},
"autoload": {
"files": [
"src/autoload.php"
],
"psr-4": {
"Laminas\\ZendFrameworkBridge\\": "src//"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Alias legacy ZF class names to Laminas Project equivalents.",
"keywords": [
"ZendFramework",
"autoloading",
"laminas",
"zf"
],
"support": {
"forum": "https://discourse.laminas.dev/",
"issues": "https://github.com/laminas/laminas-zendframework-bridge/issues",
"rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom",
"source": "https://github.com/laminas/laminas-zendframework-bridge"
},
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2021-06-24T12:49:22+00:00"
}, },
{ {
"name": "league/color-extractor", "name": "league/color-extractor",
@ -462,16 +399,16 @@
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.5.0", "version": "v6.5.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "a5b5c43e50b7fba655f793ad27303cd74c57363c" "reference": "dd803df5ad7492e1b40637f7ebd258fee5ca7355"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a5b5c43e50b7fba655f793ad27303cd74c57363c", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/dd803df5ad7492e1b40637f7ebd258fee5ca7355",
"reference": "a5b5c43e50b7fba655f793ad27303cd74c57363c", "reference": "dd803df5ad7492e1b40637f7ebd258fee5ca7355",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -483,10 +420,12 @@
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"doctrine/annotations": "^1.2", "doctrine/annotations": "^1.2",
"php-parallel-lint/php-console-highlighter": "^0.5.0",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpcompatibility/php-compatibility": "^9.3.5", "phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest", "roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.5.6", "squizlabs/php_codesniffer": "^3.6.0",
"yoast/phpunit-polyfills": "^0.2.0" "yoast/phpunit-polyfills": "^1.0.0"
}, },
"suggest": { "suggest": {
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
@ -526,7 +465,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": { "support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues", "issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.5.0" "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.5.1"
}, },
"funding": [ "funding": [
{ {
@ -534,7 +473,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-06-16T14:33:43+00:00" "time": "2021-08-18T09:14:16+00:00"
}, },
{ {
"name": "psr/log", "name": "psr/log",
@ -588,16 +527,16 @@
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.23.0", "version": "v1.23.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6",
"reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -648,7 +587,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
}, },
"funding": [ "funding": [
{ {
@ -664,7 +603,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-05-27T09:27:20+00:00" "time": "2021-05-27T12:26:48+00:00"
}, },
{ {
"name": "true/punycode", "name": "true/punycode",
@ -724,7 +663,7 @@
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": ">=7.3.0 <8.1.0", "php": ">=7.4.0 <8.1.0",
"ext-ctype": "*", "ext-ctype": "*",
"ext-mbstring": "*" "ext-mbstring": "*"
}, },

View file

@ -1,14 +1,12 @@
<?php <?php
// @codeCoverageIgnoreStart
return [ return [
// cms classes // cms classes
'asset' => 'Kirby\Cms\Asset',
'collection' => 'Kirby\Cms\Collection', 'collection' => 'Kirby\Cms\Collection',
'dir' => 'Kirby\Cms\Dir',
'field' => 'Kirby\Cms\Field', 'field' => 'Kirby\Cms\Field',
'file' => 'Kirby\Cms\File', 'file' => 'Kirby\Cms\File',
'files' => 'Kirby\Cms\Files', 'files' => 'Kirby\Cms\Files',
'find' => 'Kirby\Cms\Find',
'html' => 'Kirby\Cms\Html', 'html' => 'Kirby\Cms\Html',
'kirby' => 'Kirby\Cms\App', 'kirby' => 'Kirby\Cms\App',
'page' => 'Kirby\Cms\Page', 'page' => 'Kirby\Cms\Page',
@ -17,6 +15,7 @@ return [
'r' => 'Kirby\Cms\R', 'r' => 'Kirby\Cms\R',
'response' => 'Kirby\Cms\Response', 'response' => 'Kirby\Cms\Response',
's' => 'Kirby\Cms\S', 's' => 'Kirby\Cms\S',
'sane' => 'Kirby\Sane\Sane',
'site' => 'Kirby\Cms\Site', 'site' => 'Kirby\Cms\Site',
'structure' => 'Kirby\Cms\Structure', 'structure' => 'Kirby\Cms\Structure',
'url' => 'Kirby\Cms\Url', 'url' => 'Kirby\Cms\Url',
@ -29,6 +28,12 @@ return [
'json' => 'Kirby\Data\Json', 'json' => 'Kirby\Data\Json',
'yaml' => 'Kirby\Data\Yaml', 'yaml' => 'Kirby\Data\Yaml',
// file classes
'asset' => 'Kirby\Filesystem\Asset',
'dir' => 'Kirby\Filesystem\Dir',
'f' => 'Kirby\Filesystem\F',
'mime' => 'Kirby\Filesystem\Mime',
// data classes // data classes
'database' => 'Kirby\Database\Database', 'database' => 'Kirby\Database\Database',
'db' => 'Kirby\Database\Db', 'db' => 'Kirby\Database\Db',
@ -45,18 +50,31 @@ return [
// image classes // image classes
'dimensions' => 'Kirby\Image\Dimensions', 'dimensions' => 'Kirby\Image\Dimensions',
// panel classes
'panel' => 'Kirby\Panel\Panel',
// toolkit classes // toolkit classes
'a' => 'Kirby\Toolkit\A', 'a' => 'Kirby\Toolkit\A',
'c' => 'Kirby\Toolkit\Config', 'c' => 'Kirby\Toolkit\Config',
'config' => 'Kirby\Toolkit\Config', 'config' => 'Kirby\Toolkit\Config',
'escape' => 'Kirby\Toolkit\Escape', 'escape' => 'Kirby\Toolkit\Escape',
'f' => 'Kirby\Toolkit\F',
'i18n' => 'Kirby\Toolkit\I18n', 'i18n' => 'Kirby\Toolkit\I18n',
'mime' => 'Kirby\Toolkit\Mime',
'obj' => 'Kirby\Toolkit\Obj', 'obj' => 'Kirby\Toolkit\Obj',
'str' => 'Kirby\Toolkit\Str', 'str' => 'Kirby\Toolkit\Str',
'tpl' => 'Kirby\Toolkit\Tpl', 'tpl' => 'Kirby\Toolkit\Tpl',
'v' => 'Kirby\Toolkit\V', 'v' => 'Kirby\Toolkit\V',
'xml' => 'Kirby\Toolkit\Xml' 'xml' => 'Kirby\Toolkit\Xml',
// TODO: remove in 4.0.0
'kirby\cms\asset' => 'Kirby\Filesystem\Asset',
'kirby\cms\dir' => 'Kirby\Filesystem\Dir',
'kirby\cms\filename' => 'Kirby\Filesystem\Filename',
'kirby\cms\filefoundation' => 'Kirby\Filesystem\IsFile',
'kirby\cms\form' => 'Kirby\Form\Form',
'kirby\cms\kirbytag' => 'Kirby\Text\KirbyTag',
'kirby\cms\kirbytags' => 'Kirby\Text\KirbyTags',
'kirby\toolkit\dir' => 'Kirby\Filesystem\Dir',
'kirby\toolkit\f' => 'Kirby\Filesystem\F',
'kirby\toolkit\file' => 'Kirby\Filesystem\File',
'kirby\toolkit\mime' => 'Kirby\Filesystem\Mime',
]; ];
// @codeCoverageIgnoreEnd

View file

@ -7,7 +7,10 @@ return function () {
$allowImpersonation = $this->kirby()->option('api.allowImpersonation') ?? false; $allowImpersonation = $this->kirby()->option('api.allowImpersonation') ?? false;
// csrf token check // csrf token check
if ($auth->type($allowImpersonation) === 'session' && $auth->csrf() === false) { if (
$auth->type($allowImpersonation) === 'session' &&
$auth->csrf() === false
) {
throw new PermissionException('Unauthenticated'); throw new PermissionException('Unauthenticated');
} }

View file

@ -1,7 +1,7 @@
<?php <?php
use Kirby\Cms\File; use Kirby\Cms\File;
use Kirby\Cms\Form; use Kirby\Form\Form;
/** /**
* File * File
@ -18,7 +18,7 @@ return [
return $file->dimensions()->toArray(); return $file->dimensions()->toArray();
}, },
'dragText' => function (File $file) { 'dragText' => function (File $file) {
return $file->dragText(); return $file->panel()->dragText();
}, },
'exists' => function (File $file) { 'exists' => function (File $file) {
return $file->exists(); return $file->exists();
@ -33,7 +33,7 @@ return [
return $file->id(); return $file->id();
}, },
'link' => function (File $file) { 'link' => function (File $file) {
return $file->panelUrl(true); return $file->panel()->url(true);
}, },
'mime' => function (File $file) { 'mime' => function (File $file) {
return $file->mime(); return $file->mime();
@ -48,7 +48,7 @@ return [
return $file->next(); return $file->next();
}, },
'nextWithTemplate' => function (File $file) { 'nextWithTemplate' => function (File $file) {
$files = $file->templateSiblings()->sort('sort', 'asc', 'filename', 'asc'); $files = $file->templateSiblings()->sorted();
$index = $files->indexOf($file); $index = $files->indexOf($file);
return $files->nth($index + 1); return $files->nth($index + 1);
@ -57,22 +57,26 @@ return [
return $file->niceSize(); return $file->niceSize();
}, },
'options' => function (File $file) { 'options' => function (File $file) {
return $file->panelOptions(); return $file->panel()->options();
}, },
'panelIcon' => function (File $file) { 'panelIcon' => function (File $file) {
return $file->panelIcon(); // TODO: remove in 3.7.0
// @codeCoverageIgnoreStart
deprecated('The API field file.panelIcon has been deprecated and will be removed in 3.7.0. Use file.panelImage instead');
return $file->panel()->image();
// @codeCoverageIgnoreEnd
}, },
'panelImage' => function (File $file) { 'panelImage' => function (File $file) {
return $file->panelImage(); return $file->panel()->image();
}, },
'panelUrl' => function (File $file) { 'panelUrl' => function (File $file) {
return $file->panelUrl(true); return $file->panel()->url(true);
}, },
'prev' => function (File $file) { 'prev' => function (File $file) {
return $file->prev(); return $file->prev();
}, },
'prevWithTemplate' => function (File $file) { 'prevWithTemplate' => function (File $file) {
$files = $file->templateSiblings()->sort('sort', 'asc', 'filename', 'asc'); $files = $file->templateSiblings()->sorted();
$index = $files->indexOf($file); $index = $files->indexOf($file);
return $files->nth($index - 1); return $files->nth($index - 1);
@ -106,7 +110,7 @@ return [
return $file->type(); return $file->type();
}, },
'url' => function (File $file) { 'url' => function (File $file) {
return $file->url(true); return $file->url();
}, },
], ],
'type' => 'Kirby\Cms\File', 'type' => 'Kirby\Cms\File',

View file

@ -41,7 +41,7 @@ return [
return $file->type(); return $file->type();
}, },
'url' => function (FileVersion $file) { 'url' => function (FileVersion $file) {
return $file->url(true); return $file->url();
}, },
], ],
'type' => 'Kirby\Cms\FileVersion', 'type' => 'Kirby\Cms\FileVersion',

View file

@ -1,7 +1,7 @@
<?php <?php
use Kirby\Cms\Form;
use Kirby\Cms\Page; use Kirby\Cms\Page;
use Kirby\Form\Form;
/** /**
* Page * Page
@ -27,7 +27,7 @@ return [
return $page->errors(); return $page->errors();
}, },
'files' => function (Page $page) { 'files' => function (Page $page) {
return $page->files()->sort('sort', 'asc', 'filename', 'asc'); return $page->files()->sorted();
}, },
'hasChildren' => function (Page $page) { 'hasChildren' => function (Page $page) {
return $page->hasChildren(); return $page->hasChildren();
@ -44,6 +44,12 @@ return [
'isSortable' => function (Page $page) { 'isSortable' => function (Page $page) {
return $page->isSortable(); return $page->isSortable();
}, },
/**
* @deprecated 3.6.0
* @todo Throw deprecated warning in 3.7.0
* @todo Remove in 3.8.0
* @codeCoverageIgnore
*/
'next' => function (Page $page) { 'next' => function (Page $page) {
return $page return $page
->nextAll() ->nextAll()
@ -56,13 +62,18 @@ return [
return $page->num(); return $page->num();
}, },
'options' => function (Page $page) { 'options' => function (Page $page) {
return $page->panelOptions(['preview']); return $page->panel()->options(['preview']);
}, },
/**
* @todo Remove in 3.7.0
* @codeCoverageIgnore
*/
'panelIcon' => function (Page $page) { 'panelIcon' => function (Page $page) {
return $page->panelIcon(); deprecated('The API field page.panelIcon has been deprecated and will be removed in 3.7.0. Use page.panelImage instead');
return $page->panel()->image();
}, },
'panelImage' => function (Page $page) { 'panelImage' => function (Page $page) {
return $page->panelImage(); return $page->panel()->image();
}, },
'parent' => function (Page $page) { 'parent' => function (Page $page) {
return $page->parent(); return $page->parent();
@ -70,6 +81,12 @@ return [
'parents' => function (Page $page) { 'parents' => function (Page $page) {
return $page->parents()->flip(); return $page->parents()->flip();
}, },
/**
* @deprecated 3.6.0
* @todo Throw deprecated warning in 3.7.0
* @todo Remove in 3.8.0
* @codeCoverageIgnore
*/
'prev' => function (Page $page) { 'prev' => function (Page $page) {
return $page return $page
->prevAll() ->prevAll()

View file

@ -1,7 +1,7 @@
<?php <?php
use Kirby\Cms\Form;
use Kirby\Cms\Site; use Kirby\Cms\Site;
use Kirby\Form\Form;
/** /**
* Site * Site
@ -24,7 +24,7 @@ return [
return $site->drafts(); return $site->drafts();
}, },
'files' => function (Site $site) { 'files' => function (Site $site) {
return $site->files()->sort('sort', 'asc', 'filename', 'asc'); return $site->files()->sorted();
}, },
'options' => function (Site $site) { 'options' => function (Site $site) {
return $site->permissions()->toArray(); return $site->permissions()->toArray();

View file

@ -52,12 +52,8 @@ return [
'requirements' => function (System $system) { 'requirements' => function (System $system) {
return $system->toArray(); return $system->toArray();
}, },
'site' => function () { 'site' => function (System $system) {
try { return $system->title();
return $this->site()->blueprint()->title();
} catch (Throwable $e) {
return $this->site()->title()->value();
}
}, },
'slugs' => function () { 'slugs' => function () {
return Str::$language; return Str::$language;
@ -87,7 +83,7 @@ return [
'version' => function () { 'version' => function () {
$user = $this->user(); $user = $this->user();
if ($user && $user->role()->permissions()->for('access', 'settings') === true) { if ($user && $user->role()->permissions()->for('access', 'system') === true) {
return $this->kirby()->version(); return $this->kirby()->version();
} else { } else {
return null; return null;

View file

@ -1,7 +1,7 @@
<?php <?php
use Kirby\Cms\Form;
use Kirby\Cms\User; use Kirby\Cms\User;
use Kirby\Form\Form;
/** /**
* User * User
@ -24,7 +24,7 @@ return [
return $user->email(); return $user->email();
}, },
'files' => function (User $user) { 'files' => function (User $user) {
return $user->files()->sort('sort', 'asc', 'filename', 'asc'); return $user->files()->sorted();
}, },
'id' => function (User $user) { 'id' => function (User $user) {
return $user->id(); return $user->id();
@ -39,7 +39,10 @@ return [
return $user->next(); return $user->next();
}, },
'options' => function (User $user) { 'options' => function (User $user) {
return $user->panelOptions(); return $user->panel()->options();
},
'panelImage' => function (User $user) {
return $user->panel()->image();
}, },
'permissions' => function (User $user) { 'permissions' => function (User $user) {
return $user->role()->permissions()->toArray(); return $user->role()->permissions()->toArray();

View file

@ -1,12 +1,15 @@
<?php <?php
// routing pattern to match all models with files
$pattern = '(account|pages/[^/]+|site|users/[^/]+)';
/** /**
* Files Routes * Files Routes
*/ */
return [ return [
[ [
'pattern' => '(:all)/files/(:any)/sections/(:any)', 'pattern' => $pattern . '/files/(:any)/sections/(:any)',
'method' => 'GET', 'method' => 'GET',
'action' => function (string $path, string $filename, string $sectionName) { 'action' => function (string $path, string $filename, string $sectionName) {
if ($section = $this->file($path, $filename)->blueprint()->section($sectionName)) { if ($section = $this->file($path, $filename)->blueprint()->section($sectionName)) {
@ -15,7 +18,7 @@ return [
} }
], ],
[ [
'pattern' => '(:all)/files/(:any)/fields/(:any)/(:all?)', 'pattern' => $pattern . '/files/(:any)/fields/(:any)/(:all?)',
'method' => 'ALL', 'method' => 'ALL',
'action' => function (string $parent, string $filename, string $fieldName, string $path = null) { 'action' => function (string $parent, string $filename, string $fieldName, string $path = null) {
if ($file = $this->file($parent, $filename)) { if ($file = $this->file($parent, $filename)) {
@ -24,27 +27,33 @@ return [
} }
], ],
[ [
'pattern' => '(:all)/files', 'pattern' => $pattern . '/files',
'method' => 'GET', 'method' => 'GET',
'action' => function (string $path) { 'action' => function (string $path) {
return $this->parent($path)->files()->sort('sort', 'asc', 'filename', 'asc'); return $this->parent($path)->files()->sorted();
} }
], ],
[ [
'pattern' => '(:all)/files', 'pattern' => $pattern . '/files',
'method' => 'POST', 'method' => 'POST',
'action' => function (string $path) { 'action' => function (string $path) {
// move_uploaded_file() not working with unit test
// @codeCoverageIgnoreStart
return $this->upload(function ($source, $filename) use ($path) { return $this->upload(function ($source, $filename) use ($path) {
return $this->parent($path)->createFile([ return $this->parent($path)->createFile([
'content' => [
'sort' => $this->requestBody('sort')
],
'source' => $source, 'source' => $source,
'template' => $this->requestBody('template'), 'template' => $this->requestBody('template'),
'filename' => $filename 'filename' => $filename
]); ]);
}); });
// @codeCoverageIgnoreEnd
} }
], ],
[ [
'pattern' => '(:all)/files/search', 'pattern' => $pattern . '/files/search',
'method' => 'GET|POST', 'method' => 'GET|POST',
'action' => function (string $path) { 'action' => function (string $path) {
$files = $this->parent($path)->files(); $files = $this->parent($path)->files();
@ -57,7 +66,7 @@ return [
} }
], ],
[ [
'pattern' => '(:all)/files/sort', 'pattern' => $pattern . '/files/sort',
'method' => 'PATCH', 'method' => 'PATCH',
'action' => function (string $path) { 'action' => function (string $path) {
return $this->parent($path)->files()->changeSort( return $this->parent($path)->files()->changeSort(
@ -67,21 +76,21 @@ return [
} }
], ],
[ [
'pattern' => '(:all)/files/(:any)', 'pattern' => $pattern . '/files/(:any)',
'method' => 'GET', 'method' => 'GET',
'action' => function (string $path, string $filename) { 'action' => function (string $path, string $filename) {
return $this->file($path, $filename); return $this->file($path, $filename);
} }
], ],
[ [
'pattern' => '(:all)/files/(:any)', 'pattern' => $pattern . '/files/(:any)',
'method' => 'PATCH', 'method' => 'PATCH',
'action' => function (string $path, string $filename) { 'action' => function (string $path, string $filename) {
return $this->file($path, $filename)->update($this->requestBody(), $this->language(), true); return $this->file($path, $filename)->update($this->requestBody(), $this->language(), true);
} }
], ],
[ [
'pattern' => '(:all)/files/(:any)', 'pattern' => $pattern . '/files/(:any)',
'method' => 'POST', 'method' => 'POST',
'action' => function (string $path, string $filename) { 'action' => function (string $path, string $filename) {
return $this->upload(function ($source) use ($path, $filename) { return $this->upload(function ($source) use ($path, $filename) {
@ -90,14 +99,14 @@ return [
} }
], ],
[ [
'pattern' => '(:all)/files/(:any)', 'pattern' => $pattern . '/files/(:any)',
'method' => 'DELETE', 'method' => 'DELETE',
'action' => function (string $path, string $filename) { 'action' => function (string $path, string $filename) {
return $this->file($path, $filename)->delete(); return $this->file($path, $filename)->delete();
} }
], ],
[ [
'pattern' => '(:all)/files/(:any)/name', 'pattern' => $pattern . '/files/(:any)/name',
'method' => 'PATCH', 'method' => 'PATCH',
'action' => function (string $path, string $filename) { 'action' => function (string $path, string $filename) {
return $this->file($path, $filename)->changeName($this->requestBody('name')); return $this->file($path, $filename)->changeName($this->requestBody('name'));

View file

@ -1,6 +1,5 @@
<?php <?php
use Kirby\Exception\Exception;
/** /**
* Content Lock Routes * Content Lock Routes
@ -9,7 +8,13 @@ return [
[ [
'pattern' => '(:all)/lock', 'pattern' => '(:all)/lock',
'method' => 'GET', 'method' => 'GET',
/**
* @deprecated 3.6.0
* @todo Remove in 3.7.0
*/
'action' => function (string $path) { 'action' => function (string $path) {
deprecated('The `GET (:all)/lock` API endpoint has been deprecated and will be removed in 3.7.0');
if ($lock = $this->parent($path)->lock()) { if ($lock = $this->parent($path)->lock()) {
return [ return [
'supported' => true, 'supported' => true,
@ -30,11 +35,6 @@ return [
if ($lock = $this->parent($path)->lock()) { if ($lock = $this->parent($path)->lock()) {
return $lock->create(); return $lock->create();
} }
throw new Exception([
'key' => 'lock.notImplemented',
'httpCode' => 501
]);
} }
], ],
[ [
@ -44,17 +44,19 @@ return [
if ($lock = $this->parent($path)->lock()) { if ($lock = $this->parent($path)->lock()) {
return $lock->remove(); return $lock->remove();
} }
throw new Exception([
'key' => 'lock.notImplemented',
'httpCode' => 501
]);
} }
], ],
[ [
'pattern' => '(:all)/unlock', 'pattern' => '(:all)/unlock',
'method' => 'GET', 'method' => 'GET',
/**
* @deprecated 3.6.0
* @todo Remove in 3.7.0
*/
'action' => function (string $path) { 'action' => function (string $path) {
deprecated('The `GET (:all)/unlock` API endpoint has been deprecated and will be removed in 3.7.0');
if ($lock = $this->parent($path)->lock()) { if ($lock = $this->parent($path)->lock()) {
return [ return [
'supported' => true, 'supported' => true,
@ -75,11 +77,6 @@ return [
if ($lock = $this->parent($path)->lock()) { if ($lock = $this->parent($path)->lock()) {
return $lock->unlock(); return $lock->unlock();
} }
throw new Exception([
'key' => 'lock.notImplemented',
'httpCode' => 501
]);
} }
], ],
[ [
@ -89,11 +86,6 @@ return [
if ($lock = $this->parent($path)->lock()) { if ($lock = $this->parent($path)->lock()) {
return $lock->resolve(); return $lock->resolve();
} }
throw new Exception([
'key' => 'lock.notImplemented',
'httpCode' => 501
]);
} }
], ],
]; ];

View file

@ -38,12 +38,17 @@ return [
'pages/(:any)/blueprints', 'pages/(:any)/blueprints',
/** /**
* @deprecated * @deprecated
* @todo remove in 3.6.0 * @todo remove in 3.7.0
*/ */
'pages/(:any)/children/blueprints', 'pages/(:any)/children/blueprints',
], ],
'method' => 'GET', 'method' => 'GET',
'action' => function (string $id) { 'action' => function (string $id) {
// @codeCoverageIgnoreStart
if ($this->route->pattern() === 'pages/([a-zA-Z0-9\.\-_%= \+\@\(\)]+)/children/blueprints') {
deprecated('`GET pages/(:any)/children/blueprints` API endpoint has been deprecated and will be removed in 3.7.0. Use `GET pages/(:any)/blueprints` instead');
}
// @codeCoverageIgnoreEnd
return $this->page($id)->blueprints($this->requestQuery('section')); return $this->page($id)->blueprints($this->requestQuery('section'));
} }
], ],

View file

@ -51,12 +51,17 @@ return [
'site/blueprints', 'site/blueprints',
/** /**
* @deprecated * @deprecated
* @todo remove in 3.6.0 * @todo remove in 3.7.0
*/ */
'site/children/blueprints', 'site/children/blueprints',
], ],
'method' => 'GET', 'method' => 'GET',
'action' => function () { 'action' => function () {
// @codeCoverageIgnoreStart
if ($this->route->pattern() === 'site/children/blueprints') {
deprecated('`GET site/children/blueprints` API endpoint has been deprecated and will be removed in 3.7.0. Use `GET site/blueprints` instead.');
}
// @codeCoverageIgnoreEnd
return $this->site()->blueprints($this->requestQuery('section')); return $this->site()->blueprints($this->requestQuery('section'));
} }
], ],

View file

@ -1,12 +1,11 @@
<?php <?php
use Kirby\Toolkit\F; use Kirby\Filesystem\F;
/** /**
* User Routes * User Routes
*/ */
return [ return [
[ [
'pattern' => 'users', 'pattern' => 'users',
'method' => 'GET', 'method' => 'GET',
@ -33,35 +32,51 @@ return [
} }
], ],
[ [
'pattern' => 'users/(:any)', 'pattern' => [
'(account)',
'users/(:any)',
],
'method' => 'GET', 'method' => 'GET',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id); return $this->user($id);
} }
], ],
[ [
'pattern' => 'users/(:any)', 'pattern' => [
'(account)',
'users/(:any)',
],
'method' => 'PATCH', 'method' => 'PATCH',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->update($this->requestBody(), $this->language(), true); return $this->user($id)->update($this->requestBody(), $this->language(), true);
} }
], ],
[ [
'pattern' => 'users/(:any)', 'pattern' => [
'(account)',
'users/(:any)',
],
'method' => 'DELETE', 'method' => 'DELETE',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->delete(); return $this->user($id)->delete();
} }
], ],
[ [
'pattern' => 'users/(:any)/avatar', 'pattern' => [
'(account)/avatar',
'users/(:any)/avatar',
],
'method' => 'GET', 'method' => 'GET',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->avatar(); return $this->user($id)->avatar();
} }
], ],
// @codeCoverageIgnoreStart
[ [
'pattern' => 'users/(:any)/avatar', 'pattern' => [
'(account)/avatar',
'users/(:any)/avatar',
],
'method' => 'POST', 'method' => 'POST',
'action' => function (string $id) { 'action' => function (string $id) {
if ($avatar = $this->user($id)->avatar()) { if ($avatar = $this->user($id)->avatar()) {
@ -77,79 +92,101 @@ return [
}, $single = true); }, $single = true);
} }
], ],
// @codeCoverageIgnoreEnd
[ [
'pattern' => 'users/(:any)/avatar', 'pattern' => [
'(account)/avatar',
'users/(:any)/avatar',
],
'method' => 'DELETE', 'method' => 'DELETE',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->avatar()->delete(); return $this->user($id)->avatar()->delete();
} }
], ],
[ [
'pattern' => 'users/(:any)/blueprint', 'pattern' => [
'(account)/blueprint',
'users/(:any)/blueprint',
],
'method' => 'GET', 'method' => 'GET',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->blueprint(); return $this->user($id)->blueprint();
} }
], ],
[ [
'pattern' => 'users/(:any)/blueprints', 'pattern' => [
'(account)/blueprints',
'users/(:any)/blueprints',
],
'method' => 'GET', 'method' => 'GET',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->blueprints($this->requestQuery('section')); return $this->user($id)->blueprints($this->requestQuery('section'));
} }
], ],
[ [
'pattern' => 'users/(:any)/email', 'pattern' => [
'(account)/email',
'users/(:any)/email',
],
'method' => 'PATCH', 'method' => 'PATCH',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->changeEmail($this->requestBody('email')); return $this->user($id)->changeEmail($this->requestBody('email'));
} }
], ],
[ [
'pattern' => 'users/(:any)/fields/(:any)/(:all?)', 'pattern' => [
'method' => 'ALL', '(account)/language',
'action' => function (string $id, string $fieldName, string $path = null) { 'users/(:any)/language',
if ($user = $this->user($id)) { ],
return $this->fieldApi($user, $fieldName, $path);
}
}
],
[
'pattern' => 'users/(:any)/language',
'method' => 'PATCH', 'method' => 'PATCH',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->changeLanguage($this->requestBody('language')); return $this->user($id)->changeLanguage($this->requestBody('language'));
} }
], ],
[ [
'pattern' => 'users/(:any)/name', 'pattern' => [
'(account)/name',
'users/(:any)/name',
],
'method' => 'PATCH', 'method' => 'PATCH',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->changeName($this->requestBody('name')); return $this->user($id)->changeName($this->requestBody('name'));
} }
], ],
[ [
'pattern' => 'users/(:any)/password', 'pattern' => [
'(account)/password',
'users/(:any)/password',
],
'method' => 'PATCH', 'method' => 'PATCH',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->changePassword($this->requestBody('password')); return $this->user($id)->changePassword($this->requestBody('password'));
} }
], ],
[ [
'pattern' => 'users/(:any)/role', 'pattern' => [
'(account)/role',
'users/(:any)/role',
],
'method' => 'PATCH', 'method' => 'PATCH',
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->changeRole($this->requestBody('role')); return $this->user($id)->changeRole($this->requestBody('role'));
} }
], ],
[ [
'pattern' => 'users/(:any)/roles', 'pattern' => [
'(account)/roles',
'users/(:any)/roles',
],
'action' => function (string $id) { 'action' => function (string $id) {
return $this->user($id)->roles(); return $this->user($id)->roles();
} }
], ],
[ [
'pattern' => 'users/(:any)/sections/(:any)', 'pattern' => [
'(account)/sections/(:any)',
'users/(:any)/sections/(:any)',
],
'method' => 'GET', 'method' => 'GET',
'action' => function (string $id, string $sectionName) { 'action' => function (string $id, string $sectionName) {
if ($section = $this->user($id)->blueprint()->section($sectionName)) { if ($section = $this->user($id)->blueprint()->section($sectionName)) {
@ -157,4 +194,14 @@ return [
} }
} }
], ],
[
'pattern' => [
'(account)/fields/(:any)/(:all?)',
'users/(:any)/fields/(:any)/(:all?)',
],
'method' => 'ALL',
'action' => function (string $id, string $fieldName, string $path = null) {
return $this->fieldApi($this->user($id), $fieldName, $path);
}
],
]; ];

View file

@ -0,0 +1,12 @@
<?php
return function () {
return [
'icon' => 'account',
'label' => t('view.account'),
'search' => 'users',
'dialogs' => require __DIR__ . '/account/dialogs.php',
'dropdowns' => require __DIR__ . '/account/dropdowns.php',
'views' => require __DIR__ . '/account/views.php'
];
};

View file

@ -0,0 +1,70 @@
<?php
$dialogs = require __DIR__ . '/../users/dialogs.php';
return [
// change email
'account.changeEmail' => [
'pattern' => '(account)/changeEmail',
'load' => $dialogs['user.changeEmail']['load'],
'submit' => $dialogs['user.changeEmail']['submit'],
],
// change language
'account.changeLanguage' => [
'pattern' => '(account)/changeLanguage',
'load' => $dialogs['user.changeLanguage']['load'],
'submit' => $dialogs['user.changeLanguage']['submit'],
],
// change name
'account.changeName' => [
'pattern' => '(account)/changeName',
'load' => $dialogs['user.changeName']['load'],
'submit' => $dialogs['user.changeName']['submit'],
],
// change password
'account.changePassword' => [
'pattern' => '(account)/changePassword',
'load' => $dialogs['user.changePassword']['load'],
'submit' => $dialogs['user.changePassword']['submit'],
],
// change role
'account.changeRole' => [
'pattern' => '(account)/changeRole',
'load' => $dialogs['user.changeRole']['load'],
'submit' => $dialogs['user.changeRole']['submit'],
],
// delete
'account.delete' => [
'pattern' => '(account)/delete',
'load' => $dialogs['user.delete']['load'],
'submit' => $dialogs['user.delete']['submit'],
],
// change file name
'account.file.changeName' => [
'pattern' => '(account)/files/(:any)/changeName',
'load' => $dialogs['user.file.changeName']['load'],
'submit' => $dialogs['user.file.changeName']['submit'],
],
// change file sort
'account.file.changeSort' => [
'pattern' => '(account)/files/(:any)/changeSort',
'load' => $dialogs['user.file.changeSort']['load'],
'submit' => $dialogs['user.file.changeSort']['submit'],
],
// delete
'account.file.delete' => [
'pattern' => '(account)/files/(:any)/delete',
'load' => $dialogs['user.file.delete']['load'],
'submit' => $dialogs['user.file.delete']['submit'],
],
];

View file

@ -0,0 +1,14 @@
<?php
$dropdowns = require __DIR__ . '/../users/dropdowns.php';
return [
'account' => [
'pattern' => '(account)',
'options' => $dropdowns['user']['options']
],
'account.file' => [
'pattern' => '(account)/files/(:any)',
'options' => $dropdowns['user.file']['options']
],
];

View file

@ -0,0 +1,40 @@
<?php
use Kirby\Cms\Find;
use Kirby\Panel\Panel;
return [
'account' => [
'pattern' => 'account',
'action' => function () {
return [
'component' => 'k-account-view',
'props' => kirby()->user()->panel()->props(),
];
},
],
'account.file' => [
'pattern' => 'account/files/(:any)',
'action' => function (string $filename) {
return Find::file('account', $filename)->panel()->view();
}
],
'account.logout' => [
'pattern' => 'logout',
'auth' => false,
'action' => function () {
if ($user = kirby()->user()) {
$user->logout();
}
Panel::go('login');
},
],
'account.password' => [
'pattern' => 'reset-password',
'action' => function () {
return [
'component' => 'k-reset-password-view',
];
}
]
];

View file

@ -0,0 +1,131 @@
<?php
use Kirby\Cms\Find;
use Kirby\Panel\Field;
use Kirby\Panel\Panel;
use Kirby\Toolkit\Escape;
/**
* Shared file dialogs
* They are included in the site and
* users area to create dialogs there.
* The array keys are replaced by
* the appropriate routes in the areas.
*/
return [
'changeName' => [
'load' => function (string $path, string $filename) {
$file = Find::file($path, $filename);
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'name' => [
'label' => t('name'),
'type' => 'slug',
'required' => true,
'icon' => 'title',
'allow' => '@._-',
'after' => '.' . $file->extension(),
'preselect' => true
]
],
'submitButton' => t('rename'),
'value' => [
'name' => $file->name(),
]
]
];
},
'submit' => function (string $path, string $filename) {
$file = Find::file($path, $filename);
$renamed = $file->changeName(get('name'));
$oldUrl = $file->panel()->url(true);
$newUrl = $renamed->panel()->url(true);
$response = [
'event' => 'file.changeName',
'dispatch' => [
'content/move' => [
$oldUrl,
$newUrl
]
],
];
// check for a necessary redirect after the filename has changed
if (Panel::referrer() === $oldUrl && $oldUrl !== $newUrl) {
$response['redirect'] = $newUrl;
}
return $response;
}
],
'changeSort' => [
'load' => function (string $path, string $filename) {
$file = Find::file($path, $filename);
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'position' => Field::filePosition($file)
],
'submitButton' => t('change'),
'value' => [
'position' => $file->sort()->isEmpty() ? $file->siblings(false)->count() + 1 : $file->sort()->toInt(),
]
]
];
},
'submit' => function (string $path, string $filename) {
$file = Find::file($path, $filename);
$files = $file->siblings()->sorted();
$ids = $files->keys();
$newIndex = (int)(get('position')) - 1;
$oldIndex = $files->indexOf($file);
array_splice($ids, $oldIndex, 1);
array_splice($ids, $newIndex, 0, $file->id());
$files->changeSort($ids);
return [
'event' => 'file.sort',
];
}
],
'delete' => [
'load' => function (string $path, string $filename) {
$file = Find::file($path, $filename);
return [
'component' => 'k-remove-dialog',
'props' => [
'text' => tt('file.delete.confirm', [
'filename' => Escape::html($file->filename())
]),
]
];
},
'submit' => function (string $path, string $filename) {
$file = Find::file($path, $filename);
$redirect = false;
$referrer = Panel::referrer();
$url = $file->panel()->url(true);
$file->delete();
// redirect to the parent model URL
// if the dialog has been opened in the file view
if ($referrer === $url) {
$redirect = $file->parent()->panel()->url(true);
}
return [
'event' => 'file.delete',
'dispatch' => ['content/remove' => [$url]],
'redirect' => $redirect
];
}
],
];

View file

@ -0,0 +1,9 @@
<?php
use Kirby\Cms\Find;
return [
'file' => function (string $parent, string $filename) {
return Find::file($parent, $filename)->panel()->dropdown();
}
];

View file

@ -0,0 +1,41 @@
<?php
use Kirby\Panel\Panel;
return function ($kirby) {
return [
'icon' => 'settings',
'label' => t('view.installation'),
'views' => [
'installation' => [
'pattern' => 'installation',
'auth' => false,
'action' => function () use ($kirby) {
$system = $kirby->system();
return [
'component' => 'k-installation-view',
'props' => [
'isInstallable' => $system->isInstallable(),
'isInstalled' => $system->isInstalled(),
'isOk' => $system->isOk(),
'requirements' => $system->status(),
'translations' => $kirby->translations()->values(function ($translation) {
return [
'text' => $translation->name(),
'value' => $translation->code(),
];
}),
]
];
}
],
'installation.fallback' => [
'pattern' => '(:all)',
'auth' => false,
'action' => function () {
Panel::go('installation');
}
]
]
];
};

View file

@ -0,0 +1,11 @@
<?php
return function ($kirby) {
return [
'icon' => 'globe',
'label' => t('view.languages'),
'menu' => true,
'dialogs' => require __DIR__ . '/languages/dialogs.php',
'views' => require __DIR__ . '/languages/views.php'
];
};

View file

@ -0,0 +1,149 @@
<?php
use Kirby\Cms\Find;
use Kirby\Panel\Field;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Escape;
$languageDialogFields = [
'name' => [
'label' => t('language.name'),
'type' => 'text',
'required' => true,
'icon' => 'title'
],
'code' => [
'label' => t('language.code'),
'type' => 'text',
'required' => true,
'counter' => false,
'icon' => 'globe',
'width' => '1/2'
],
'direction' => [
'label' => t('language.direction'),
'type' => 'select',
'required' => true,
'empty' => false,
'options' => [
['value' => 'ltr', 'text' => t('language.direction.ltr')],
['value' => 'rtl', 'text' => t('language.direction.rtl')]
],
'width' => '1/2'
],
'locale' => [
'label' => t('language.locale'),
'type' => 'text',
],
];
return [
// create language
'language.create' => [
'pattern' => 'languages/create',
'load' => function () use ($languageDialogFields) {
return [
'component' => 'k-language-dialog',
'props' => [
'fields' => $languageDialogFields,
'submitButton' => t('language.create'),
'value' => [
'code' => '',
'direction' => 'ltr',
'locale' => '',
'name' => '',
]
]
];
},
'submit' => function () {
kirby()->languages()->create([
'code' => get('code'),
'direction' => get('direction'),
'locale' => get('locale'),
'name' => get('name'),
]);
return [
'event' => 'language.create'
];
}
],
// delete language
'language.delete' => [
'pattern' => 'languages/(:any)/delete',
'load' => function (string $id) {
$language = Find::language($id);
return [
'component' => 'k-remove-dialog',
'props' => [
'text' => tt('language.delete.confirm', [
'name' => Escape::html($language->name())
])
]
];
},
'submit' => function (string $id) {
Find::language($id)->delete();
return [
'event' => 'language.delete',
];
}
],
// update language
'language.update' => [
'pattern' => 'languages/(:any)/update',
'load' => function (string $id) use ($languageDialogFields) {
$language = Find::language($id);
$fields = $languageDialogFields;
$locale = $language->locale();
// use the first locale key if there's only one
if (count($locale) === 1) {
$locale = A::first($locale);
}
// the code of an existing language cannot be changed
$fields['code']['disabled'] = true;
// if the locale settings is more complex than just a
// single string, the text field won't do it anymore.
// Changes can only be made in the language file and
// we display a warning box instead.
if (is_array($locale) === true) {
$fields['locale'] = [
'label' => $fields['locale']['label'],
'type' => 'info',
'text' => t('language.locale.warning')
];
}
return [
'component' => 'k-language-dialog',
'props' => [
'fields' => $fields,
'submitButton' => t('save'),
'value' => [
'code' => $language->code(),
'direction' => $language->direction(),
'locale' => $locale,
'name' => $language->name(),
'rules' => $language->rules(),
]
]
];
},
'submit' => function (string $id) {
$language = Find::language($id)->update([
'direction' => get('direction'),
'locale' => get('locale'),
'name' => get('name'),
]);
return [
'event' => 'language.update'
];
}
],
];

View file

@ -0,0 +1,26 @@
<?php
use Kirby\Toolkit\Escape;
return [
'languages' => [
'pattern' => 'languages',
'action' => function () {
$kirby = kirby();
return [
'component' => 'k-languages-view',
'props' => [
'languages' => $kirby->languages()->values(function ($language) {
return [
'default' => $language->isDefault(),
'id' => $language->code(),
'info' => Escape::html($language->code()),
'text' => Escape::html($language->name()),
];
})
]
];
}
],
];

View file

@ -0,0 +1,43 @@
<?php
use Kirby\Panel\Panel;
return function ($kirby) {
return [
'icon' => 'user',
'label' => t('login'),
'views' => [
'login' => [
'pattern' => 'login',
'auth' => false,
'action' => function () use ($kirby) {
$system = $kirby->system();
$status = $kirby->auth()->status();
return [
'component' => 'k-login-view',
'props' => [
'methods' => array_keys($system->loginMethods()),
'pending' => [
'email' => $status->email(),
'challenge' => $status->challenge()
]
],
];
}
],
'login.fallback' => [
'pattern' => '(:all)',
'auth' => false,
'action' => function ($path) use ($kirby) {
/**
* Store the current path in the session
* Once the user is logged in, the path will
* be used to redirect to that view again
*/
$kirby->session()->set('panel.path', $path);
Panel::go('login');
}
]
]
];
};

View file

@ -0,0 +1,17 @@
<?php
return function ($kirby) {
return [
'breadcrumbLabel' => function () use ($kirby) {
return $kirby->site()->title()->or(t('view.site'))->toString();
},
'icon' => 'home',
'label' => $kirby->site()->blueprint()->title() ?? t('view.site'),
'menu' => true,
'dialogs' => require __DIR__ . '/site/dialogs.php',
'dropdowns' => require __DIR__ . '/site/dropdowns.php',
'searches' => require __DIR__ . '/site/searches.php',
'views' => require __DIR__ . '/site/views.php',
];
};

View file

@ -0,0 +1,547 @@
<?php
use Kirby\Cms\Find;
use Kirby\Exception\Exception;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Exception\PermissionException;
use Kirby\Panel\Field;
use Kirby\Panel\Panel;
use Kirby\Toolkit\Str;
$files = require __DIR__ . '/../files/dialogs.php';
return [
// change page position
'page.changeSort' => [
'pattern' => 'pages/(:any)/changeSort',
'load' => function (string $id) {
$page = Find::page($id);
$position = null;
if ($page->blueprint()->num() !== 'default') {
throw new PermissionException([
'key' => 'page.sort.permission',
'data' => [
'slug' => $page->slug()
]
]);
}
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'position' => Field::pagePosition($page),
],
'submitButton' => t('change'),
'value' => [
'position' => $page->panel()->position()
]
]
];
},
'submit' => function (string $id) {
Find::page($id)->changeStatus('listed', get('position'));
return [
'event' => 'page.sort',
];
}
],
// change page status
'page.changeStatus' => [
'pattern' => 'pages/(:any)/changeStatus',
'load' => function (string $id) {
$page = Find::page($id);
$blueprint = $page->blueprint();
$status = $page->status();
$states = [];
$position = null;
foreach ($blueprint->status() as $key => $state) {
$states[] = [
'value' => $key,
'text' => $state['label'],
'info' => $state['text'],
];
}
if ($status === 'draft') {
$errors = $page->errors();
// switch to the error dialog if there are
// errors and the draft cannot be published
if (count($errors) > 0) {
return [
'component' => 'k-error-dialog',
'props' => [
'message' => t('error.page.changeStatus.incomplete'),
'details' => $errors,
]
];
}
}
$fields = [
'status' => [
'label' => t('page.changeStatus.select'),
'type' => 'radio',
'required' => true,
'options' => $states
]
];
if ($blueprint->num() === 'default') {
$fields['position'] = Field::pagePosition($page, [
'when' => [
'status' => 'listed'
]
]);
$position = $page->panel()->position();
}
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => $fields,
'submitButton' => t('change'),
'value' => [
'status' => $status,
'position' => $position
]
]
];
},
'submit' => function (string $id) {
Find::page($id)->changeStatus(get('status'), get('position'));
return [
'event' => 'page.changeStatus',
];
}
],
// change template
'page.changeTemplate' => [
'pattern' => 'pages/(:any)/changeTemplate',
'load' => function (string $id) {
$page = Find::page($id);
$blueprints = $page->blueprints();
if (count($blueprints) <= 1) {
throw new Exception([
'key' => 'page.changeTemplate.invalid',
'data' => [
'slug' => $id
]
]);
}
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'template' => Field::template($blueprints, [
'required' => true
])
],
'submitButton' => t('change'),
'value' => [
'template' => $page->intendedTemplate()->name()
]
]
];
},
'submit' => function (string $id) {
Find::page($id)->changeTemplate(get('template'));
return [
'event' => 'page.changeTemplate',
];
}
],
// change title
'page.changeTitle' => [
'pattern' => 'pages/(:any)/changeTitle',
'load' => function (string $id) {
$page = Find::page($id);
$permissions = $page->permissions();
$select = get('select', 'title');
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'title' => Field::title([
'required' => true,
'preselect' => $select === 'title',
'disabled' => $permissions->can('changeTitle') === false
]),
'slug' => Field::slug([
'required' => true,
'preselect' => $select === 'slug',
'path' => $page->parent() ? '/' . $page->parent()->id() . '/' : '/',
'disabled' => $permissions->can('changeSlug') === false,
'wizard' => [
'text' => t('page.changeSlug.fromTitle'),
'field' => 'title'
]
])
],
'autofocus' => false,
'submitButton' => t('change'),
'value' => [
'title' => $page->title()->value(),
'slug' => $page->slug(),
]
]
];
},
'submit' => function (string $id) {
$page = Find::page($id);
$title = trim(get('title'));
$slug = trim(get('slug'));
// basic input validation before we move on
if (Str::length($title) === 0) {
throw new InvalidArgumentException(['key' => 'page.changeTitle.empty']);
}
if (Str::length($slug) === 0) {
throw new InvalidArgumentException(['key' => 'page.slug.invalid']);
}
// nothing changed
if ($page->title()->value() === $title && $page->slug() === $slug) {
return true;
}
// prepare the response
$response = [
'event' => []
];
// the page title changed
if ($page->title()->value() !== $title) {
$page->changeTitle($title);
$response['event'][] = 'page.changeTitle';
}
// the slug changed
if ($page->slug() !== $slug) {
$newPage = $page->changeSlug($slug);
$response['event'][] = 'page.changeSlug';
$response['dispatch'] = [
'content/move' => [
$oldUrl = $page->panel()->url(true),
$newUrl = $newPage->panel()->url(true)
]
];
// check for a necessary redirect after the slug has changed
if (Panel::referrer() === $oldUrl && $oldUrl !== $newUrl) {
$response['redirect'] = $newUrl;
}
}
return $response;
}
],
// create a new page
'page.create' => [
'pattern' => 'pages/create',
'load' => function () {
// the parent model for the new page
$parent = get('parent', 'site');
// the view on which the add button is located
// this is important to find the right section
// and provide the correct templates for the new page
$view = get('view', $parent);
// templates will be fetched depending on the
// section settings in the blueprint
$section = get('section');
// this is the parent model
$model = Find::parent($parent);
// this is the view model
// i.e. site if the add button is on
// the dashboard
$view = Find::parent($view);
// available blueprints/templates for the new page
// are always loaded depending on the matching section
// in the view model blueprint
$blueprints = $view->blueprints($section);
// the pre-selected template
$template = $blueprints[0]['name'] ?? $blueprints[0]['value'] ?? null;
$fields = [
'parent' => Field::hidden(),
'title' => Field::title([
'required' => true,
'preselect' => true
]),
'slug' => Field::slug([
'required' => true,
'sync' => 'title',
'path' => empty($model->id()) === false ? '/' . $model->id() . '/' : '/'
]),
'template' => Field::hidden()
];
// only show template field if > 1 templates available
// or when in debug mode
if (count($blueprints) > 1 || option('debug') === true) {
$fields['template'] = Field::template($blueprints, [
'required' => true
]);
}
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => $fields,
'submitButton' => t('page.draft.create'),
'value' => [
'parent' => $parent,
'slug' => '',
'template' => $template,
'title' => '',
]
]
];
},
'submit' => function () {
$title = trim(get('title'));
if (Str::length($title) === 0) {
throw new InvalidArgumentException([
'key' => 'page.changeTitle.empty'
]);
}
$page = Find::parent(get('parent', 'site'))->createChild([
'content' => ['title' => $title],
'slug' => get('slug'),
'template' => get('template'),
]);
return [
'event' => 'page.create',
'redirect' => $page->panel()->url(true)
];
}
],
// delete page
'page.delete' => [
'pattern' => 'pages/(:any)/delete',
'load' => function (string $id) {
$page = Find::page($id);
$text = tt('page.delete.confirm', [
'title' => Escape::html($page->title()->value())
]);
if ($page->childrenAndDrafts()->count() > 0) {
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'info' => [
'type' => 'info',
'theme' => 'negative',
'text' => t('page.delete.confirm.subpages')
],
'check' => [
'label' => t('page.delete.confirm.title'),
'type' => 'text',
'counter' => false
]
],
'size' => 'medium',
'submitButton' => t('delete'),
'text' => $text,
'theme' => 'negative',
]
];
}
return [
'component' => 'k-remove-dialog',
'props' => [
'text' => $text
]
];
},
'submit' => function (string $id) {
$page = Find::page($id);
$redirect = false;
$referrer = Panel::referrer();
$url = $page->panel()->url(true);
if ($page->childrenAndDrafts()->count() > 0 && get('check') !== $page->title()->value()) {
throw new InvalidArgumentException(['key' => 'page.delete.confirm']);
}
$page->delete(true);
// redirect to the parent model URL
// if the dialog has been opened in the page view
if ($referrer === $url) {
$redirect = $page->parentModel()->panel()->url(true);
}
return [
'event' => 'page.delete',
'dispatch' => ['content/remove' => [$url]],
'redirect' => $redirect
];
}
],
// duplicate page
'page.duplicate' => [
'pattern' => 'pages/(:any)/duplicate',
'load' => function (string $id) {
$page = Find::page($id);
$hasChildren = $page->hasChildren();
$hasFiles = $page->hasFiles();
$toggleWidth = '1/' . count(array_filter([$hasChildren, $hasFiles]));
$fields = [
'title' => Field::title([
'required' => true
]),
'slug' => Field::slug([
'required' => true,
'path' => $page->parent() ? '/' . $page->parent()->id() . '/' : '/',
'wizard' => [
'text' => t('page.changeSlug.fromTitle'),
'field' => 'title'
]
])
];
if ($hasFiles === true) {
$fields['files'] = [
'label' => t('page.duplicate.files'),
'type' => 'toggle',
'required' => true,
'width' => $toggleWidth
];
}
if ($hasChildren === true) {
$fields['children'] = [
'label' => t('page.duplicate.pages'),
'type' => 'toggle',
'required' => true,
'width' => $toggleWidth
];
}
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => $fields,
'submitButton' => t('duplicate'),
'value' => [
'children' => false,
'files' => false,
'slug' => $page->slug() . '-' . Str::slug(t('page.duplicate.appendix')),
'title' => $page->title() . ' ' . t('page.duplicate.appendix')
]
]
];
},
'submit' => function (string $id) {
$newPage = Find::page($id)->duplicate(get('slug'), [
'children' => (bool)get('children'),
'files' => (bool)get('files'),
'title' => (string)get('title'),
]);
return [
'event' => 'page.duplicate',
'redirect' => $newPage->panel()->url(true)
];
}
],
// change filename
'page.file.changeName' => [
'pattern' => '(pages/.*?)/files/(:any)/changeName',
'load' => $files['changeName']['load'],
'submit' => $files['changeName']['submit'],
],
// change sort
'page.file.changeSort' => [
'pattern' => '(pages/.*?)/files/(:any)/changeSort',
'load' => $files['changeSort']['load'],
'submit' => $files['changeSort']['submit'],
],
// delete
'page.file.delete' => [
'pattern' => '(pages/.*?)/files/(:any)/delete',
'load' => $files['delete']['load'],
'submit' => $files['delete']['submit'],
],
// change site title
'site.changeTitle' => [
'pattern' => 'site/changeTitle',
'load' => function () {
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'title' => Field::title([
'required' => true,
'preselect' => true
])
],
'submitButton' => t('rename'),
'value' => [
'title' => site()->title()->value()
]
]
];
},
'submit' => function () {
site()->changeTitle(get('title'));
return [
'event' => 'site.changeTitle',
];
}
],
// change filename
'site.file.changeName' => [
'pattern' => '(site)/files/(:any)/changeName',
'load' => $files['changeName']['load'],
'submit' => $files['changeName']['submit'],
],
// change sort
'site.file.changeSort' => [
'pattern' => '(site)/files/(:any)/changeSort',
'load' => $files['changeSort']['load'],
'submit' => $files['changeSort']['submit'],
],
// delete
'site.file.delete' => [
'pattern' => '(site)/files/(:any)/delete',
'load' => $files['delete']['load'],
'submit' => $files['delete']['submit'],
],
];

View file

@ -0,0 +1,28 @@
<?php
use Kirby\Panel\Dropdown;
$files = require __DIR__ . '/../files/dropdowns.php';
return [
'changes' => [
'pattern' => 'changes',
'options' => function () {
return Dropdown::changes();
}
],
'page' => [
'pattern' => 'pages/(:any)',
'options' => function (string $path) {
return Find::page($path)->panel()->dropdown();
}
],
'page.file' => [
'pattern' => '(pages/.*?)/files/(:any)',
'options' => $files['file']
],
'site.file' => [
'pattern' => '(site)/files/(:any)',
'options' => $files['file']
]
];

View file

@ -0,0 +1,55 @@
<?php
use Kirby\Toolkit\Escape;
return [
'pages' => [
'label' => t('pages'),
'icon' => 'page',
'query' => function (string $query = null) {
$pages = site()
->index(true)
->search($query)
->filter('isReadable', true)
->limit(10);
$results = [];
foreach ($pages as $page) {
$results[] = [
'image' => $page->panel()->image(),
'text' => Escape::html($page->title()->value()),
'link' => $page->panel()->url(true),
'info' => Escape::html($page->id())
];
}
return $results;
}
],
'files' => [
'label' => t('files'),
'icon' => 'image',
'query' => function (string $query = null) {
$files = site()
->index(true)
->filter('isReadable', true)
->files()
->search($query)
->limit(10);
$results = [];
foreach ($files as $file) {
$results[] = [
'image' => $file->panel()->image(),
'text' => Escape::html($file->filename()),
'link' => $file->panel()->url(true),
'info' => Escape::html($file->id())
];
}
return $results;
}
]
];

View file

@ -0,0 +1,30 @@
<?php
use Kirby\Cms\Find;
return [
'page' => [
'pattern' => 'pages/(:any)',
'action' => function (string $path) {
return Find::page($path)->panel()->view();
}
],
'page.file' => [
'pattern' => 'pages/(:any)/files/(:any)',
'action' => function (string $id, string $filename) {
return Find::file('pages/' . $id, $filename)->panel()->view();
}
],
'site' => [
'pattern' => 'site',
'action' => function () {
return site()->panel()->view();
}
],
'site.file' => [
'pattern' => 'site/files/(:any)',
'action' => function (string $filename) {
return Find::file('site', $filename)->panel()->view();
}
],
];

View file

@ -0,0 +1,11 @@
<?php
return function ($kirby) {
return [
'icon' => 'settings',
'label' => t('view.system'),
'menu' => true,
'dialogs' => require __DIR__ . '/system/dialogs.php',
'views' => require __DIR__ . '/system/views.php'
];
};

View file

@ -0,0 +1,43 @@
<?php
use Kirby\Panel\Field;
return [
// license registration
'registration' => [
'load' => function () {
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'license' => [
'label' => t('license.register.label'),
'type' => 'text',
'required' => true,
'counter' => false,
'placeholder' => 'K3-',
'help' => t('license.register.help')
],
'email' => Field::email([
'required' => true
])
],
'submitButton' => t('license.register'),
'value' => [
'license' => null,
'email' => null
]
]
];
},
'submit' => function () {
// @codeCoverageIgnoreStart
kirby()->system()->register(get('license'), get('email'));
return [
'event' => 'system.register',
'message' => t('license.register.success')
];
// @codeCoverageIgnoreEnd
}
],
];

View file

@ -0,0 +1,46 @@
<?php
return [
'system' => [
'pattern' => 'system',
'action' => function () {
$kirby = kirby();
$system = $kirby->system();
$license = $system->license();
// @codeCoverageIgnoreStart
if ($license === true) {
// valid license, but user is not admin
$license = 'Kirby 3';
} elseif ($license === false) {
// no valid license
$license = null;
}
// @codeCoverageIgnoreEnd
$plugins = $system->plugins()->values(function ($plugin) {
return [
'author' => $plugin->authorsNames(),
'license' => $plugin->license(),
'link' => $plugin->link(),
'name' => $plugin->name(),
'version' => $plugin->version(),
];
});
return [
'component' => 'k-system-view',
'props' => [
'debug' => $kirby->option('debug', false),
'license' => $license,
'plugins' => $plugins,
'php' => phpversion(),
'server' => $system->serverSoftware(),
'ssl' => Server::https(),
'version' => $kirby->version(),
]
];
}
],
];

View file

@ -0,0 +1,14 @@
<?php
return function ($kirby) {
return [
'icon' => 'users',
'label' => t('view.users'),
'search' => 'users',
'menu' => true,
'dialogs' => require __DIR__ . '/users/dialogs.php',
'dropdowns' => require __DIR__ . '/users/dropdowns.php',
'searches' => require __DIR__ . '/users/searches.php',
'views' => require __DIR__ . '/users/views.php'
];
};

View file

@ -0,0 +1,295 @@
<?php
use Kirby\Cms\Find;
use Kirby\Cms\UserRules;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Panel\Field;
use Kirby\Panel\Panel;
use Kirby\Toolkit\Escape;
$files = require __DIR__ . '/../files/dialogs.php';
return [
// create
'user.create' => [
'pattern' => 'users/create',
'load' => function () {
$kirby = kirby();
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'name' => Field::username(),
'email' => Field::email([
'link' => false,
'required' => true
]),
'password' => Field::password(),
'language' => Field::translation([
'required' => true
]),
'role' => Field::role([
'required' => true
])
],
'submitButton' => t('create'),
'value' => [
'name' => '',
'email' => '',
'password' => '',
'language' => $kirby->panelLanguage(),
'role' => $kirby->user()->role()->name()
]
]
];
},
'submit' => function () {
kirby()->users()->create([
'name' => get('name'),
'email' => get('email'),
'password' => get('password'),
'language' => get('language'),
'role' => get('role')
]);
return [
'event' => 'user.create'
];
}
],
// change email
'user.changeEmail' => [
'pattern' => 'users/(:any)/changeEmail',
'load' => function (string $id) {
$user = Find::user($id);
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'email' => [
'label' => t('email'),
'required' => true,
'type' => 'email',
'preselect' => true
]
],
'submitButton' => t('change'),
'value' => [
'email' => $user->email()
]
]
];
},
'submit' => function (string $id) {
Find::user($id)->changeEmail(get('email'));
return [
'event' => 'user.changeEmail'
];
}
],
// change language
'user.changeLanguage' => [
'pattern' => 'users/(:any)/changeLanguage',
'load' => function (string $id) {
$user = Find::user($id);
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'translation' => Field::translation(['required' => true])
],
'submitButton' => t('change'),
'value' => [
'translation' => $user->language()
]
]
];
},
'submit' => function (string $id) {
Find::user($id)->changeLanguage(get('translation'));
return [
'event' => 'user.changeLanguage',
'reload' => [
'globals' => '$translation'
]
];
}
],
// change name
'user.changeName' => [
'pattern' => 'users/(:any)/changeName',
'load' => function (string $id) {
$user = Find::user($id);
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'name' => Field::username([
'preselect' => true
])
],
'submitButton' => t('rename'),
'value' => [
'name' => $user->name()->value()
]
]
];
},
'submit' => function (string $id) {
Find::user($id)->changeName(get('name'));
return [
'event' => 'user.changeName'
];
}
],
// change password
'user.changePassword' => [
'pattern' => 'users/(:any)/changePassword',
'load' => function (string $id) {
$user = Find::user($id);
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'password' => Field::password([
'label' => t('user.changePassword.new'),
]),
'passwordConfirmation' => Field::password([
'label' => t('user.changePassword.new.confirm'),
])
],
'submitButton' => t('change'),
]
];
},
'submit' => function (string $id) {
$user = Find::user($id);
$password = get('password');
$passwordConfirmation = get('passwordConfirmation');
// validate the password
UserRules::validPassword($user, $password ?? '');
// compare passwords
if ($password !== $passwordConfirmation) {
throw new InvalidArgumentException([
'key' => 'user.password.notSame'
]);
}
// change password if everything's fine
$user->changePassword($password);
return [
'event' => 'user.changePassword'
];
}
],
// change role
'user.changeRole' => [
'pattern' => 'users/(:any)/changeRole',
'load' => function (string $id) {
$user = Find::user($id);
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'role' => Field::role([
'label' => t('user.changeRole.select'),
'required' => true,
])
],
'submitButton' => t('user.changeRole'),
'value' => [
'role' => $user->role()->name()
]
]
];
},
'submit' => function (string $id) {
$user = Find::user($id)->changeRole(get('role'));
return [
'event' => 'user.changeRole',
'user' => $user->toArray()
];
}
],
// delete
'user.delete' => [
'pattern' => 'users/(:any)/delete',
'load' => function (string $id) {
$user = Find::user($id);
$i18nPrefix = $user->isLoggedIn() ? 'account' : 'user';
return [
'component' => 'k-remove-dialog',
'props' => [
'text' => tt($i18nPrefix . '.delete.confirm', [
'email' => Escape::html($user->email())
])
]
];
},
'submit' => function (string $id) {
$user = Find::user($id);
$redirect = false;
$referrer = Panel::referrer();
$url = $user->panel()->url(true);
$user->delete();
// redirect to the users view
// if the dialog has been opened in the user view
if ($referrer === $url) {
$redirect = '/users';
}
// logout the user if they deleted themselves
if ($user->isLoggedIn()) {
$redirect = '/logout';
}
return [
'event' => 'user.delete',
'dispatch' => ['content/remove' => [$url]],
'redirect' => $redirect
];
}
],
// change file name
'user.file.changeName' => [
'pattern' => '(users/.*?)/files/(:any)/changeName',
'load' => $files['changeName']['load'],
'submit' => $files['changeName']['submit'],
],
// change file sort
'user.file.changeSort' => [
'pattern' => '(users/.*?)/files/(:any)/changeSort',
'load' => $files['changeSort']['load'],
'submit' => $files['changeSort']['submit'],
],
// delete file
'user.file.delete' => [
'pattern' => '(users/.*?)/files/(:any)/delete',
'load' => $files['delete']['load'],
'submit' => $files['delete']['submit'],
]
];

View file

@ -0,0 +1,18 @@
<?php
use Kirby\Cms\Find;
$files = require __DIR__ . '/../files/dropdowns.php';
return [
'user' => [
'pattern' => 'users/(:any)',
'options' => function (string $id) {
return Find::user($id)->panel()->dropdown();
}
],
'user.file' => [
'pattern' => '(users/.*?)/files/(:any)',
'options' => $files['file']
]
];

View file

@ -0,0 +1,25 @@
<?php
use Kirby\Toolkit\Escape;
return [
'users' => [
'label' => t('users'),
'icon' => 'users',
'query' => function (string $query = null) {
$users = kirby()->users()->search($query)->limit(10);
$results = [];
foreach ($users as $user) {
$results[] = [
'image' => $user->panel()->image(),
'text' => Escape::html($user->username()),
'link' => $user->panel()->url(true),
'info' => Escape::html($user->role()->title())
];
}
return $results;
}
]
];

View file

@ -0,0 +1,69 @@
<?php
use Kirby\Cms\Find;
use Kirby\Toolkit\Escape;
return [
'users' => [
'pattern' => 'users',
'action' => function () {
$kirby = kirby();
$role = get('role');
$roles = $kirby->roles()->toArray(function ($role) {
return [
'id' => $role->id(),
'title' => $role->title(),
];
});
return [
'component' => 'k-users-view',
'props' => [
'role' => function () use ($kirby, $roles, $role) {
if ($role) {
return $roles[$role] ?? null;
}
},
'roles' => array_values($roles),
'users' => function () use ($kirby, $role) {
$users = $kirby->users();
if (empty($role) === false) {
$users = $users->role($role);
}
$users = $users->paginate([
'limit' => 20,
'page' => get('page')
]);
return [
'data' => $users->values(function ($user) {
return [
'id' => $user->id(),
'image' => $user->panel()->image(),
'info' => Escape::html($user->role()->title()),
'link' => $user->panel()->url(true),
'text' => Escape::html($user->username())
];
}),
'pagination' => $users->pagination()->toArray()
];
},
]
];
}
],
'user' => [
'pattern' => 'users/(:any)',
'action' => function (string $id) {
return Find::user($id)->panel()->view();
}
],
'user.file' => [
'pattern' => 'users/(:any)/files/(:any)',
'action' => function (string $id, string $filename) {
return Find::file('users/' . $id, $filename)->panel()->view();
}
],
];

View file

@ -9,7 +9,7 @@ $ratio = $block->ratio()->or('auto');
$src = null; $src = null;
if ($block->location() == 'web') { if ($block->location() == 'web') {
$src = $block->src(); $src = $block->src()->esc();
} elseif ($image = $block->image()->toFile()) { } elseif ($image = $block->image()->toFile()) {
$alt = $alt ?? $image->alt(); $alt = $alt ?? $image->alt();
$src = $image->url(); $src = $image->url();
@ -19,11 +19,11 @@ if ($block->location() == 'web') {
<?php if ($src): ?> <?php if ($src): ?>
<figure<?= attr(['data-ratio' => $ratio, 'data-crop' => $crop], ' ') ?>> <figure<?= attr(['data-ratio' => $ratio, 'data-crop' => $crop], ' ') ?>>
<?php if ($link->isNotEmpty()): ?> <?php if ($link->isNotEmpty()): ?>
<a href="<?= $link->toUrl() ?>"> <a href="<?= esc($link->toUrl()) ?>">
<img src="<?= $src ?>" alt="<?= $alt ?>"> <img src="<?= $src ?>" alt="<?= $alt->esc() ?>">
</a> </a>
<?php else: ?> <?php else: ?>
<img src="<?= $src ?>" alt="<?= $alt ?>"> <img src="<?= $src ?>" alt="<?= $alt->esc() ?>">
<?php endif ?> <?php endif ?>
<?php if ($caption->isNotEmpty()): ?> <?php if ($caption->isNotEmpty()): ?>

View file

@ -0,0 +1 @@
<hr />

View file

@ -0,0 +1,4 @@
name: field.blocks.line.name
icon: divider
preview: line
wysiwyg: true

View file

@ -1,7 +1,7 @@
<?php /** @var \Kirby\Cms\Block $block */ ?> <?php /** @var \Kirby\Cms\Block $block */ ?>
<?php if ($block->url()->isNotEmpty()): ?> <?php if ($video = video($block->url())): ?>
<figure> <figure>
<?= video($block->url()) ?> <?= $video ?>
<?php if ($block->caption()->isNotEmpty()): ?> <?php if ($block->caption()->isNotEmpty()): ?>
<figcaption><?= $block->caption() ?></figcaption> <figcaption><?= $block->caption() ?></figcaption>
<?php endif ?> <?php endif ?>

View file

@ -1,26 +0,0 @@
<?php
$blocksRoot = __DIR__ . '/blocks';
return [
// blocks
'blocks/code' => $blocksRoot . '/code/code.yml',
'blocks/gallery' => $blocksRoot . '/gallery/gallery.yml',
'blocks/heading' => $blocksRoot . '/heading/heading.yml',
'blocks/image' => $blocksRoot . '/image/image.yml',
'blocks/list' => $blocksRoot . '/list/list.yml',
'blocks/markdown' => $blocksRoot . '/markdown/markdown.yml',
'blocks/quote' => $blocksRoot . '/quote/quote.yml',
'blocks/table' => $blocksRoot . '/table/table.yml',
'blocks/text' => $blocksRoot . '/text/text.yml',
'blocks/video' => $blocksRoot . '/video/video.yml',
// file blueprints
'files/default' => __DIR__ . '/blueprints/files/default.yml',
// page blueprints
'pages/default' => __DIR__ . '/blueprints/pages/default.yml',
// site blueprints
'site' => __DIR__ . '/blueprints/site.yml'
];

View file

@ -5,7 +5,6 @@ fields:
level: level:
type: select type: select
width: 1/2 width: 1/2
default: 1
empty: false empty: false
default: "2" default: "2"
options: options:

View file

@ -3,10 +3,12 @@
use Kirby\Cms\App; use Kirby\Cms\App;
use Kirby\Cms\Collection; use Kirby\Cms\Collection;
use Kirby\Cms\File; use Kirby\Cms\File;
use Kirby\Cms\Filename;
use Kirby\Cms\FileVersion; use Kirby\Cms\FileVersion;
use Kirby\Cms\Template; use Kirby\Cms\Template;
use Kirby\Data\Data; use Kirby\Data\Data;
use Kirby\Email\PHPMailer as Emailer;
use Kirby\Filesystem\F;
use Kirby\Filesystem\Filename;
use Kirby\Http\Server; use Kirby\Http\Server;
use Kirby\Http\Uri; use Kirby\Http\Uri;
use Kirby\Http\Url; use Kirby\Http\Url;
@ -14,7 +16,6 @@ use Kirby\Image\Darkroom;
use Kirby\Text\Markdown; use Kirby\Text\Markdown;
use Kirby\Text\SmartyPants; use Kirby\Text\SmartyPants;
use Kirby\Toolkit\A; use Kirby\Toolkit\A;
use Kirby\Toolkit\F;
use Kirby\Toolkit\Str; use Kirby\Toolkit\Str;
use Kirby\Toolkit\Tpl as Snippet; use Kirby\Toolkit\Tpl as Snippet;
@ -55,6 +56,17 @@ return [
return $output; return $output;
}, },
/**
* Add your own email provider
*
* @param \Kirby\Cms\App $kirby Kirby instance
* @param array $props
* @param bool $debug
*/
'email' => function (App $kirby, array $props = [], bool $debug = false) {
return new Emailer($props, $debug);
},
/** /**
* Modify URLs for file objects * Modify URLs for file objects
* *
@ -70,7 +82,7 @@ return [
* Adapt file characteristics * Adapt file characteristics
* *
* @param \Kirby\Cms\App $kirby Kirby instance * @param \Kirby\Cms\App $kirby Kirby instance
* @param \Kirby\Cms\File|\Kirby\Cms\FileModifications $file The file object * @param \Kirby\Cms\File|\Kirby\Filesystem\Asset $file The file object
* @param array $options All thumb options (width, height, crop, blur, grayscale) * @param array $options All thumb options (width, height, crop, blur, grayscale)
* @return \Kirby\Cms\File|\Kirby\Cms\FileVersion * @return \Kirby\Cms\File|\Kirby\Cms\FileVersion
*/ */
@ -233,7 +245,7 @@ return [
} }
} }
return $item->searchHits > 0 ? true : false; return $item->searchHits > 0;
}); });
return $results->sort('searchScore', 'desc'); return $results->sort('searchScore', 'desc');
@ -305,15 +317,18 @@ return [
* Add your own thumb generator * Add your own thumb generator
* *
* @param \Kirby\Cms\App $kirby Kirby instance * @param \Kirby\Cms\App $kirby Kirby instance
* @param string $src The root of the original file * @param string $src Root of the original file
* @param string $template The template for the root to the desired destination * @param string $dst Template string for the root to the desired destination
* @param array $options All thumb options that should be applied: `width`, `height`, `crop`, `blur`, `grayscale` * @param array $options All thumb options that should be applied: `width`, `height`, `crop`, `blur`, `grayscale`
* @return string * @return string
*/ */
'thumb' => function (App $kirby, string $src, string $template, array $options): string { 'thumb' => function (App $kirby, string $src, string $dst, array $options): string {
$darkroom = Darkroom::factory(option('thumbs.driver', 'gd'), option('thumbs', [])); $darkroom = Darkroom::factory(
option('thumbs.driver', 'gd'),
option('thumbs', [])
);
$options = $darkroom->preprocess($src, $options); $options = $darkroom->preprocess($src, $options);
$root = (new Filename($src, $template, $options))->toString(); $root = (new Filename($src, $dst, $options))->toString();
F::copy($src, $root, true); F::copy($src, $root, true);
$darkroom->process($root, $options); $darkroom->process($root, $options);
@ -327,13 +342,9 @@ return [
* @param \Kirby\Cms\App $kirby Kirby instance * @param \Kirby\Cms\App $kirby Kirby instance
* @param string $path URL path * @param string $path URL path
* @param array|string|null $options Array of options for the Uri class * @param array|string|null $options Array of options for the Uri class
* @param Closure $originalHandler Deprecated: Callback function to the original URL handler with `$path` and `$options` as parameters
* Use `$kirby->nativeComponent('url')` inside your URL component instead.
* @return string * @return string
*
* @todo Remove $originalHandler parameter in 3.6.0
*/ */
'url' => function (App $kirby, string $path = null, $options = null, Closure $originalHandler = null): string { 'url' => function (App $kirby, string $path = null, $options = null): string {
$language = null; $language = null;
// get language from simple string option // get language from simple string option

View file

@ -1,32 +0,0 @@
<?php
return [
'blocks' => 'Kirby\Form\Field\BlocksField',
'checkboxes' => __DIR__ . '/fields/checkboxes.php',
'date' => __DIR__ . '/fields/date.php',
'email' => __DIR__ . '/fields/email.php',
'files' => __DIR__ . '/fields/files.php',
'gap' => __DIR__ . '/fields/gap.php',
'headline' => __DIR__ . '/fields/headline.php',
'hidden' => __DIR__ . '/fields/hidden.php',
'info' => __DIR__ . '/fields/info.php',
'layout' => 'Kirby\Form\Field\LayoutField',
'line' => __DIR__ . '/fields/line.php',
'list' => __DIR__ . '/fields/list.php',
'multiselect' => __DIR__ . '/fields/multiselect.php',
'number' => __DIR__ . '/fields/number.php',
'pages' => __DIR__ . '/fields/pages.php',
'radio' => __DIR__ . '/fields/radio.php',
'range' => __DIR__ . '/fields/range.php',
'select' => __DIR__ . '/fields/select.php',
'structure' => __DIR__ . '/fields/structure.php',
'tags' => __DIR__ . '/fields/tags.php',
'tel' => __DIR__ . '/fields/tel.php',
'text' => __DIR__ . '/fields/text.php',
'textarea' => __DIR__ . '/fields/textarea.php',
'time' => __DIR__ . '/fields/time.php',
'toggle' => __DIR__ . '/fields/toggle.php',
'url' => __DIR__ . '/fields/url.php',
'users' => __DIR__ . '/fields/users.php',
'writer' => __DIR__ . '/fields/writer.php'
];

View file

@ -5,9 +5,10 @@ use Kirby\Toolkit\A;
return [ return [
'mixins' => [ 'mixins' => [
'picker',
'filepicker', 'filepicker',
'layout',
'min', 'min',
'picker',
'upload' 'upload'
], ],
'props' => [ 'props' => [
@ -27,20 +28,6 @@ return [
return $default; return $default;
}, },
/**
* Changes the layout of the selected files. Available layouts: `list`, `cards`
*/
'layout' => function (string $layout = 'list') {
return $layout;
},
/**
* Layout size for cards: `tiny`, `small`, `medium`, `large` or `huge`
*/
'size' => function (string $size = 'auto') {
return $size;
},
'value' => function ($value = null) { 'value' => function ($value = null) {
return $value; return $value;
} }
@ -68,11 +55,12 @@ return [
], ],
'methods' => [ 'methods' => [
'fileResponse' => function ($file) { 'fileResponse' => function ($file) {
return $file->panelPickerData([ return $file->panel()->pickerData([
'image' => $this->image, 'image' => $this->image,
'info' => $this->info ?? false, 'info' => $this->info ?? false,
'model' => $this->model(), 'layout' => $this->layout,
'text' => $this->text, 'model' => $this->model(),
'text' => $this->text,
]); ]);
}, },
'toFiles' => function ($value = null) { 'toFiles' => function ($value = null) {
@ -101,6 +89,7 @@ return [
return $field->filepicker([ return $field->filepicker([
'image' => $field->image(), 'image' => $field->image(),
'info' => $field->info(), 'info' => $field->info(),
'layout' => $field->layout(),
'limit' => $field->limit(), 'limit' => $field->limit(),
'page' => $this->requestQuery('page'), 'page' => $this->requestQuery('page'),
'query' => $field->query(), 'query' => $field->query(),
@ -116,14 +105,18 @@ return [
$field = $this->field(); $field = $this->field();
$uploads = $field->uploads(); $uploads = $field->uploads();
// move_uploaded_file() not working with unit test
// @codeCoverageIgnoreStart
return $field->upload($this, $uploads, function ($file, $parent) use ($field) { return $field->upload($this, $uploads, function ($file, $parent) use ($field) {
return $file->panelPickerData([ return $file->panel()->pickerData([
'image' => $field->image(), 'image' => $field->image(),
'info' => $field->info(), 'info' => $field->info(),
'model' => $field->model(), 'layout' => $field->layout(),
'text' => $field->text(), 'model' => $field->model(),
'text' => $field->text(),
]); ]);
}); });
// @codeCoverageIgnoreEnd
} }
] ]
]; ];

View file

@ -34,7 +34,7 @@ return [
'computed' => [ 'computed' => [
'text' => function () { 'text' => function () {
if ($text = $this->text) { if ($text = $this->text) {
$text = $this->model()->toString($text); $text = $this->model()->toSafeString($text);
$text = $this->kirby()->kirbytext($text); $text = $this->kirby()->kirbytext($text);
return $text; return $text;
} }

View file

@ -0,0 +1,21 @@
<?php
return [
'props' => [
/**
* Changes the layout of the selected entries.
* Available layouts: `list`, `cardlets`, `cards`
*/
'layout' => function (string $layout = 'list') {
$layouts = ['list', 'cardlets', 'cards'];
return in_array($layout, $layouts) ? $layout : 'list';
},
/**
* Layout size for cards: `tiny`, `small`, `medium`, `large` or `huge`
*/
'size' => function (string $size = 'auto') {
return $size;
},
]
];

View file

@ -27,6 +27,7 @@ return [
if ($template) { if ($template) {
$file = new File([ $file = new File([
'filename' => 'tmp', 'filename' => 'tmp',
'parent' => $this->model(),
'template' => $template 'template' => $template
]); ]);

View file

@ -4,7 +4,12 @@ use Kirby\Data\Data;
use Kirby\Toolkit\A; use Kirby\Toolkit\A;
return [ return [
'mixins' => ['min', 'pagepicker', 'picker'], 'mixins' => [
'layout',
'min',
'pagepicker',
'picker',
],
'props' => [ 'props' => [
/** /**
* Unset inherited props * Unset inherited props
@ -22,13 +27,6 @@ return [
return $this->toPages($default); return $this->toPages($default);
}, },
/**
* Changes the layout of the selected files. Available layouts: `list`, `cards`
*/
'layout' => function (string $layout = 'list') {
return $layout;
},
/** /**
* Optional query to select a specific set of pages * Optional query to select a specific set of pages
*/ */
@ -36,13 +34,6 @@ return [
return $query; return $query;
}, },
/**
* Layout size for cards: `tiny`, `small`, `medium`, `large` or `huge`
*/
'size' => function (string $size = 'auto') {
return $size;
},
/** /**
* Optionally include subpages of pages * Optionally include subpages of pages
*/ */
@ -62,10 +53,11 @@ return [
], ],
'methods' => [ 'methods' => [
'pageResponse' => function ($page) { 'pageResponse' => function ($page) {
return $page->panelPickerData([ return $page->panel()->pickerData([
'image' => $this->image, 'image' => $this->image,
'info' => $this->info, 'info' => $this->info,
'text' => $this->text, 'layout' => $this->layout,
'text' => $this->text,
]); ]);
}, },
'toPages' => function ($value = null) { 'toPages' => function ($value = null) {
@ -95,6 +87,7 @@ return [
return $field->pagepicker([ return $field->pagepicker([
'image' => $field->image(), 'image' => $field->image(),
'info' => $field->info(), 'info' => $field->info(),
'layout' => $field->layout(),
'limit' => $field->limit(), 'limit' => $field->limit(),
'page' => $this->requestQuery('page'), 'page' => $this->requestQuery('page'),
'parent' => $this->requestQuery('parent'), 'parent' => $this->requestQuery('parent'),

View file

@ -0,0 +1,55 @@
<?php
return [
'extends' => 'text',
'props' => [
/**
* Unset inherited props
*/
'converter' => null,
'counter' => null,
'spellcheck' => null,
/**
* Set of characters allowed in the slug
*/
'allow' => function (string $allow = '') {
return $allow;
},
/**
* Changes the link icon
*/
'icon' => function (string $icon = 'url') {
return $icon;
},
/**
* Set prefix for the help text
*/
'path' => function (string $path = null) {
return $path;
},
/**
* Name of another field that should be used to
* automatically update this field's value
*/
'sync' => function (string $sync = null) {
return $sync;
},
/**
* Set to object with keys `field` and `text` to add
* button to generate from another field
*/
'wizard' => function ($wizard = false) {
return $wizard;
}
],
'validations' => [
'minlength',
'maxlength'
],
];

View file

@ -1,7 +1,7 @@
<?php <?php
use Kirby\Cms\Form;
use Kirby\Data\Data; use Kirby\Data\Data;
use Kirby\Form\Form;
use Kirby\Toolkit\I18n; use Kirby\Toolkit\I18n;
return [ return [

View file

@ -109,7 +109,7 @@ return [
return [ return [
'filename' => $file->filename(), 'filename' => $file->filename(),
'dragText' => $file->dragText('auto', $absolute), 'dragText' => $file->panel()->dragText('auto', $absolute),
]; ];
}); });
} }

View file

@ -1,6 +1,7 @@
<?php <?php
use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\InvalidArgumentException;
use Kirby\Toolkit\A;
use Kirby\Toolkit\I18n; use Kirby\Toolkit\I18n;
return [ return [
@ -20,19 +21,25 @@ return [
* Sets the text next to the toggle. The text can be a string or an array of two options. The first one is the negative text and the second one the positive. The text will automatically switch when the toggle is triggered. * Sets the text next to the toggle. The text can be a string or an array of two options. The first one is the negative text and the second one the positive. The text will automatically switch when the toggle is triggered.
*/ */
'text' => function ($value = null) { 'text' => function ($value = null) {
$model = $this->model();
if (is_array($value) === true) { if (is_array($value) === true) {
if (A::isAssociative($value) === true) { if (A::isAssociative($value) === true) {
return I18n::translate($value, $value); return $model->toSafeString(I18n::translate($value, $value));
} }
foreach ($value as $key => $val) { foreach ($value as $key => $val) {
$value[$key] = I18n::translate($val, $val); $value[$key] = $model->toSafeString(I18n::translate($val, $val));
} }
return $value; return $value;
} }
return I18n::translate($value, $value); if (empty($value) === false) {
return $model->toSafeString(I18n::translate($value, $value));
}
return $value;
}, },
], ],
'computed' => [ 'computed' => [

View file

@ -4,7 +4,12 @@ use Kirby\Data\Data;
use Kirby\Toolkit\A; use Kirby\Toolkit\A;
return [ return [
'mixins' => ['min', 'picker', 'userpicker'], 'mixins' => [
'layout',
'min',
'picker',
'userpicker'
],
'props' => [ 'props' => [
/** /**
* Unset inherited props * Unset inherited props
@ -44,10 +49,11 @@ return [
], ],
'methods' => [ 'methods' => [
'userResponse' => function ($user) { 'userResponse' => function ($user) {
return $user->panelPickerData([ return $user->panel()->pickerData([
'info' => $this->info, 'info' => $this->info,
'image' => $this->image, 'image' => $this->image,
'text' => $this->text, 'layout' => $this->layout,
'text' => $this->text,
]); ]);
}, },
'toUsers' => function ($value = null) { 'toUsers' => function ($value = null) {
@ -77,6 +83,7 @@ return [
return $field->userpicker([ return $field->userpicker([
'image' => $field->image(), 'image' => $field->image(),
'info' => $field->info(), 'info' => $field->info(),
'layout' => $field->layout(),
'limit' => $field->limit(), 'limit' => $field->limit(),
'page' => $this->requestQuery('page'), 'page' => $this->requestQuery('page'),
'query' => $field->query(), 'query' => $field->query(),

View file

@ -1,5 +1,7 @@
<?php <?php
use Kirby\Sane\Sane;
return [ return [
'props' => [ 'props' => [
/** /**
@ -11,14 +13,14 @@ return [
return $inline; return $inline;
}, },
/** /**
* Sets the allowed HTML formats. Available formats: `bold`, `italic`, `underline`, `strike`, `code`, `link`. Activate them all by passing `true`. Deactivate them all by passing `false` * Sets the allowed HTML formats. Available formats: `bold`, `italic`, `underline`, `strike`, `code`, `link`, `email`. Activate them all by passing `true`. Deactivate them all by passing `false`
* @param array|bool $marks * @param array|bool $marks
*/ */
'marks' => function ($marks = true) { 'marks' => function ($marks = true) {
return $marks; return $marks;
}, },
/** /**
* Sets the allowed nodes. Available nodes: `bulletList`, `orderedList`, `heading`, `horizontalRule`, `listItem`. Activate/deactivate them all by passing `true`/`false`. Default nodes are `heading`, `bulletList`, `orderedList`. * Sets the allowed nodes. Available nodes: `paragraph`, `heading`, `bulletList`, `orderedList`. Activate/deactivate them all by passing `true`/`false`. Default nodes are `paragraph`, `heading`, `bulletList`, `orderedList`.
* @param array|bool|null $nodes * @param array|bool|null $nodes
*/ */
'nodes' => function ($nodes = null) { 'nodes' => function ($nodes = null) {
@ -27,7 +29,7 @@ return [
], ],
'computed' => [ 'computed' => [
'value' => function () { 'value' => function () {
return trim($this->value); return Sane::sanitize(trim($this->value), 'html');
} }
], ],
]; ];

View file

@ -1,13 +1,14 @@
<?php <?php
use Kirby\Cms\App; use Kirby\Cms\App;
use Kirby\Cms\Asset;
use Kirby\Cms\Html; use Kirby\Cms\Html;
use Kirby\Cms\Response; use Kirby\Cms\Response;
use Kirby\Cms\Url; use Kirby\Cms\Url;
use Kirby\Exception\InvalidArgumentException; use Kirby\Exception\InvalidArgumentException;
use Kirby\Filesystem\Asset;
use Kirby\Filesystem\F;
use Kirby\Http\Router;
use Kirby\Toolkit\Escape; use Kirby\Toolkit\Escape;
use Kirby\Toolkit\F;
use Kirby\Toolkit\I18n; use Kirby\Toolkit\I18n;
use Kirby\Toolkit\Str; use Kirby\Toolkit\Str;
use Kirby\Toolkit\V; use Kirby\Toolkit\V;
@ -16,7 +17,7 @@ use Kirby\Toolkit\V;
* Helper to create an asset object * Helper to create an asset object
* *
* @param string $path * @param string $path
* @return \Kirby\Cms\Asset * @return \Kirby\Filesystem\Asset
*/ */
function asset(string $path) function asset(string $path)
{ {
@ -26,12 +27,12 @@ function asset(string $path)
/** /**
* Generates a list of HTML attributes * Generates a list of HTML attributes
* *
* @param array $attr A list of attributes as key/value array * @param array|null $attr A list of attributes as key/value array
* @param string $before An optional string that will be prepended if the result is not empty * @param string|null $before An optional string that will be prepended if the result is not empty
* @param string $after An optional string that will be appended if the result is not empty * @param string|null $after An optional string that will be appended if the result is not empty
* @return string * @return string|null
*/ */
function attr(array $attr = null, $before = null, $after = null) function attr(?array $attr = null, ?string $before = null, ?string $after = null): ?string
{ {
if ($attrs = Html::attr($attr)) { if ($attrs = Html::attr($attr)) {
return $before . $attrs . $after; return $before . $attrs . $after;
@ -54,28 +55,33 @@ function collection(string $name)
/** /**
* Checks / returns a CSRF token * Checks / returns a CSRF token
* *
* @param string $check Pass a token here to compare it to the one in the session * @param string|null $check Pass a token here to compare it to the one in the session
* @return string|bool Either the token or a boolean check result * @return string|bool Either the token or a boolean check result
*/ */
function csrf(string $check = null) function csrf(?string $check = null)
{ {
$session = App::instance()->session(); $session = App::instance()->session();
// check explicitly if there have been no arguments at all; // no arguments, generate/return a token
// (check explicitly if there have been no arguments at all;
// checking for null introduces a security issue because null could come // checking for null introduces a security issue because null could come
// from user input or bugs in the calling code! // from user input or bugs in the calling code!)
if (func_num_args() === 0) { if (func_num_args() === 0) {
// no arguments, generate/return a token
$token = $session->get('kirby.csrf'); $token = $session->get('kirby.csrf');
if (is_string($token) !== true) { if (is_string($token) !== true) {
$token = bin2hex(random_bytes(32)); $token = bin2hex(random_bytes(32));
$session->set('kirby.csrf', $token); $session->set('kirby.csrf', $token);
} }
return $token; return $token;
} elseif (is_string($check) === true && is_string($session->get('kirby.csrf')) === true) { }
// argument has been passed, check the token
// argument has been passed, check the token
if (
is_string($check) === true &&
is_string($session->get('kirby.csrf')) === true
) {
return hash_equals($session->get('kirby.csrf'), $check) === true; return hash_equals($session->get('kirby.csrf'), $check) === true;
} }
@ -174,7 +180,7 @@ if (function_exists('e') === false) {
* @param string $context Location of output (`html`, `attr`, `js`, `css`, `url` or `xml`) * @param string $context Location of output (`html`, `attr`, `js`, `css`, `url` or `xml`)
* @return string Escaped data * @return string Escaped data
*/ */
function esc($string, $context = 'html') function esc(string $string, string $context = 'html'): string
{ {
if (method_exists('Kirby\Toolkit\Escape', $context) === true) { if (method_exists('Kirby\Toolkit\Escape', $context) === true) {
return Escape::$context($string); return Escape::$context($string);
@ -200,10 +206,10 @@ function get($key = null, $default = null)
* Embeds a Github Gist * Embeds a Github Gist
* *
* @param string $url * @param string $url
* @param string $file * @param string|null $file
* @return string * @return string
*/ */
function gist(string $url, string $file = null): string function gist(string $url, ?string $file = null): string
{ {
return kirbytag([ return kirbytag([
'gist' => $url, 'gist' => $url,
@ -255,10 +261,10 @@ function html(?string $string, bool $keepTags = false)
* Example: * Example:
* <?= image('some/page/myimage.jpg') ?> * <?= image('some/page/myimage.jpg') ?>
* *
* @param string $path * @param string|null $path
* @return \Kirby\Cms\File|null * @return \Kirby\Cms\File|null
*/ */
function image(string $path = null) function image(?string $path = null)
{ {
if ($path === null) { if ($path === null) {
return page()->image(); return page()->image();
@ -296,9 +302,9 @@ function image(string $path = null)
* @param array $data * @param array $data
* @param array $rules * @param array $rules
* @param array $messages * @param array $messages
* @return false|array * @return array
*/ */
function invalid(array $data = [], array $rules = [], array $messages = []) function invalid(array $data = [], array $rules = [], array $messages = []): array
{ {
$errors = []; $errors = [];
@ -407,12 +413,12 @@ function kirby()
* Makes it possible to use any defined Kirbytag as standalone function * Makes it possible to use any defined Kirbytag as standalone function
* *
* @param string|array $type * @param string|array $type
* @param string $value * @param string|null $value
* @param array $attr * @param array $attr
* @param array $data * @param array $data
* @return string * @return string
*/ */
function kirbytag($type, string $value = null, array $attr = [], array $data = []): string function kirbytag($type, ?string $value = null, array $attr = [], array $data = []): string
{ {
if (is_array($type) === true) { if (is_array($type) === true) {
$kirbytag = $type; $kirbytag = $type;
@ -434,11 +440,11 @@ function kirbytag($type, string $value = null, array $attr = [], array $data = [
* Parses KirbyTags in the given string. Shortcut * Parses KirbyTags in the given string. Shortcut
* for `$kirby->kirbytags($text, $data)` * for `$kirby->kirbytags($text, $data)`
* *
* @param string $text * @param string|null $text
* @param array $data * @param array $data
* @return string * @return string
*/ */
function kirbytags(string $text = null, array $data = []): string function kirbytags(?string $text = null, array $data = []): string
{ {
return App::instance()->kirbytags($text, $data); return App::instance()->kirbytags($text, $data);
} }
@ -447,11 +453,11 @@ function kirbytags(string $text = null, array $data = []): string
* Parses KirbyTags and Markdown in the * Parses KirbyTags and Markdown in the
* given string. Shortcut for `$kirby->kirbytext()` * given string. Shortcut for `$kirby->kirbytext()`
* *
* @param string $text * @param string|null $text
* @param array $data * @param array $data
* @return string * @return string
*/ */
function kirbytext(string $text = null, array $data = []): string function kirbytext(?string $text = null, array $data = []): string
{ {
return App::instance()->kirbytext($text, $data); return App::instance()->kirbytext($text, $data);
} }
@ -461,11 +467,11 @@ function kirbytext(string $text = null, array $data = []): string
* given string. * given string.
* @since 3.1.0 * @since 3.1.0
* *
* @param string $text * @param string|null $text
* @param array $data * @param array $data
* @return string * @return string
*/ */
function kirbytextinline(string $text = null, array $data = []): string function kirbytextinline(?string $text = null, array $data = []): string
{ {
return App::instance()->kirbytext($text, $data, true); return App::instance()->kirbytext($text, $data, true);
} }
@ -473,11 +479,11 @@ function kirbytextinline(string $text = null, array $data = []): string
/** /**
* Shortcut for `kirbytext()` helper * Shortcut for `kirbytext()` helper
* *
* @param string $text * @param string|null $text
* @param array $data * @param array $data
* @return string * @return string
*/ */
function kt(string $text = null, array $data = []): string function kt(?string $text = null, array $data = []): string
{ {
return kirbytext($text, $data); return kirbytext($text, $data);
} }
@ -486,11 +492,11 @@ function kt(string $text = null, array $data = []): string
* Shortcut for `kirbytextinline()` helper * Shortcut for `kirbytextinline()` helper
* @since 3.1.0 * @since 3.1.0
* *
* @param string $text * @param string|null $text
* @param array $data * @param array $data
* @return string * @return string
*/ */
function kti(string $text = null, array $data = []): string function kti(?string $text = null, array $data = []): string
{ {
return kirbytextinline($text, $data); return kirbytextinline($text, $data);
} }
@ -499,10 +505,10 @@ function kti(string $text = null, array $data = []): string
* A super simple class autoloader * A super simple class autoloader
* *
* @param array $classmap * @param array $classmap
* @param string $base * @param string|null $base
* @return void * @return void
*/ */
function load(array $classmap, string $base = null) function load(array $classmap, ?string $base = null)
{ {
// convert all classnames to lowercase // convert all classnames to lowercase
$classmap = array_change_key_case($classmap); $classmap = array_change_key_case($classmap);
@ -526,10 +532,10 @@ function load(array $classmap, string $base = null)
* Parses markdown in the given string. Shortcut for * Parses markdown in the given string. Shortcut for
* `$kirby->markdown($text)` * `$kirby->markdown($text)`
* *
* @param string $text * @param string|null $text
* @return string * @return string
*/ */
function markdown(string $text = null): string function markdown(?string $text = null): string
{ {
return App::instance()->markdown($text); return App::instance()->markdown($text);
} }
@ -551,7 +557,8 @@ function option(string $key, $default = null)
* id or the current page when no id is specified * id or the current page when no id is specified
* *
* @param string|array ...$id * @param string|array ...$id
* @return \Kirby\Cms\Page|null * @return \Kirby\Cms\Page|\Kirby\Cms\Pages|null
* @todo reduce to one parameter in 3.7.0 (also change return and return type)
*/ */
function page(...$id) function page(...$id)
{ {
@ -559,6 +566,12 @@ function page(...$id)
return App::instance()->site()->page(); return App::instance()->site()->page();
} }
if (count($id) > 1) {
// @codeCoverageIgnoreStart
deprecated('Passing multiple parameters to the `page()` helper has been deprecated. Please use the `pages()` helper instead.');
// @codeCoverageIgnoreEnd
}
return App::instance()->site()->find(...$id); return App::instance()->site()->find(...$id);
} }
@ -566,10 +579,17 @@ function page(...$id)
* Helper to build page collections * Helper to build page collections
* *
* @param string|array ...$id * @param string|array ...$id
* @return \Kirby\Cms\Pages * @return \Kirby\Cms\Page|\Kirby\Cms\Pages|null
* @todo return only Pages|null in 3.7.0, wrap in Pages for single passed id
*/ */
function pages(...$id) function pages(...$id)
{ {
if (count($id) === 1) {
// @codeCoverageIgnoreStart
deprecated('Passing a single id to the `pages()` helper will return a Kirby\Cms\Pages collection with a single element instead of the single Kirby\Cms\Page object itself - starting in 3.7.0.');
// @codeCoverageIgnoreEnd
}
return App::instance()->site()->find(...$id); return App::instance()->site()->find(...$id);
} }
@ -577,10 +597,10 @@ function pages(...$id)
* Returns a single param from the URL * Returns a single param from the URL
* *
* @param string $key * @param string $key
* @param string $fallback * @param string|null $fallback
* @return string|null * @return string|null
*/ */
function param(string $key, string $fallback = null): ?string function param(string $key, ?string $fallback = null): ?string
{ {
return App::instance()->request()->url()->params()->$key ?? $fallback; return App::instance()->request()->url()->params()->$key ?? $fallback;
} }
@ -608,6 +628,22 @@ function r($condition, $value, $alternative = null)
return $condition ? $value : $alternative; return $condition ? $value : $alternative;
} }
/**
* Creates a micro-router and executes
* the routing action immediately
* @since 3.6.0
*
* @param string|null $path
* @param string $method
* @param array $routes
* @param \Closure|null $callback
* @return mixed
*/
function router(?string $path = null, string $method = 'GET', array $routes = [], ?Closure $callback = null)
{
return (new Router($routes))->call($path, $method, $callback);
}
/** /**
* Returns the current site object * Returns the current site object
* *
@ -623,6 +659,7 @@ function site()
* *
* @param mixed $value * @param mixed $value
* @return int * @return int
* @throws \Kirby\Exception\InvalidArgumentException
*/ */
function size($value): int function size($value): int
{ {
@ -655,10 +692,10 @@ function size($value): int
* Enhances the given string with * Enhances the given string with
* smartypants. Shortcut for `$kirby->smartypants($text)` * smartypants. Shortcut for `$kirby->smartypants($text)`
* *
* @param string $text * @param string|null $text
* @return string * @return string
*/ */
function smartypants(string $text = null): string function smartypants(?string $text = null): string
{ {
return App::instance()->smartypants($text); return App::instance()->smartypants($text);
} }
@ -725,7 +762,7 @@ function svg($file)
* *
* @param string|array $key * @param string|array $key
* @param string|null $fallback * @param string|null $fallback
* @return mixed * @return array|string|null
*/ */
function t($key, string $fallback = null) function t($key, string $fallback = null)
{ {
@ -735,11 +772,11 @@ function t($key, string $fallback = null)
/** /**
* Translates a count * Translates a count
* *
* @param string|array $key * @param string $key
* @param int $count * @param int $count
* @return mixed * @return mixed
*/ */
function tc($key, int $count) function tc(string $key, int $count)
{ {
return I18n::translateCount($key, $count); return I18n::translateCount($key, $count);
} }
@ -748,11 +785,11 @@ function tc($key, int $count)
* Rounds the minutes of the given date * Rounds the minutes of the given date
* by the defined step * by the defined step
* *
* @param string $date * @param string|null $date
* @param int $step array of `unit` and `size` to round to nearest * @param int|array|null $step array of `unit` and `size` to round to nearest
* @return int|null * @return int|null
*/ */
function timestamp(string $date = null, $step = null): ?int function timestamp(?string $date = null, $step = null): ?int
{ {
if (V::date($date) === false) { if (V::date($date) === false) {
return null; return null;
@ -807,7 +844,7 @@ function timestamp(string $date = null, $step = null): ?int
); );
// on error, convert `false` into `null` // on error, convert `false` into `null`
return $timestamp ? $timestamp : null; return $timestamp ?? null;
} }
/** /**
@ -815,12 +852,12 @@ function timestamp(string $date = null, $step = null): ?int
* placeholders in the text * placeholders in the text
* *
* @param string $key * @param string $key
* @param string $fallback * @param string|array|null $fallback
* @param array $replace * @param array|null $replace
* @param string $locale * @param string|null $locale
* @return string * @return string
*/ */
function tt(string $key, $fallback = null, array $replace = null, string $locale = null) function tt(string $key, $fallback = null, ?array $replace = null, ?string $locale = null)
{ {
return I18n::template($key, $fallback, $replace, $locale); return I18n::template($key, $fallback, $replace, $locale);
} }
@ -829,12 +866,12 @@ function tt(string $key, $fallback = null, array $replace = null, string $locale
* Builds a Twitter link * Builds a Twitter link
* *
* @param string $username * @param string $username
* @param string $text * @param string|null $text
* @param string $title * @param string|null $title
* @param string $class * @param string|null $class
* @return string * @return string
*/ */
function twitter(string $username, string $text = null, string $title = null, string $class = null): string function twitter(string $username, ?string $text = null, ?string $title = null, ?string $class = null): string
{ {
return kirbytag([ return kirbytag([
'twitter' => $username, 'twitter' => $username,
@ -847,11 +884,11 @@ function twitter(string $username, string $text = null, string $title = null, st
/** /**
* Shortcut for url() * Shortcut for url()
* *
* @param string $path * @param string|null $path
* @param array|string|null $options * @param array|string|null $options
* @return string * @return string
*/ */
function u(string $path = null, $options = null): string function u(?string $path = null, $options = null): string
{ {
return Url::to($path, $options); return Url::to($path, $options);
} }
@ -859,11 +896,11 @@ function u(string $path = null, $options = null): string
/** /**
* Builds an absolute URL for a given path * Builds an absolute URL for a given path
* *
* @param string $path * @param string|null $path
* @param array|string|null $options * @param array|string|null $options
* @return string * @return string
*/ */
function url(string $path = null, $options = null): string function url(?string $path = null, $options = null): string
{ {
return Url::to($path, $options); return Url::to($path, $options);
} }
@ -906,9 +943,9 @@ function uuid(): string
* @param string $url * @param string $url
* @param array $options * @param array $options
* @param array $attr * @param array $attr
* @return string * @return string|null
*/ */
function video(string $url, array $options = [], array $attr = []): string function video(string $url, array $options = [], array $attr = []): ?string
{ {
return Html::video($url, $options, $attr); return Html::video($url, $options, $attr);
} }
@ -919,9 +956,9 @@ function video(string $url, array $options = [], array $attr = []): string
* @param string $url * @param string $url
* @param array $options * @param array $options
* @param array $attr * @param array $attr
* @return string * @return string|null
*/ */
function vimeo(string $url, array $options = [], array $attr = []): string function vimeo(string $url, array $options = [], array $attr = []): ?string
{ {
return Html::vimeo($url, $options, $attr); return Html::vimeo($url, $options, $attr);
} }
@ -945,9 +982,9 @@ function widont(string $string = null): string
* @param string $url * @param string $url
* @param array $options * @param array $options
* @param array $attr * @param array $attr
* @return string * @return string|null
*/ */
function youtube(string $url, array $options = [], array $attr = []): string function youtube(string $url, array $options = [], array $attr = []): ?string
{ {
return Html::youtube($url, $options, $attr); return Html::youtube($url, $options, $attr);
} }

View file

@ -366,7 +366,7 @@ return function (App $app) {
* @return \Kirby\Cms\Field * @return \Kirby\Cms\Field
*/ */
'html' => function (Field $field) { 'html' => function (Field $field) {
$field->value = htmlentities($field->value, ENT_COMPAT, 'utf-8'); $field->value = Html::encode($field->value);
return $field; return $field;
}, },
@ -498,13 +498,14 @@ return function (App $app) {
*/ */
'replace' => function (Field $field, array $data = [], string $fallback = '') use ($app) { 'replace' => function (Field $field, array $data = [], string $fallback = '') use ($app) {
if ($parent = $field->parent()) { if ($parent = $field->parent()) {
$field->value = $field->parent()->toString($field->value, $data, $fallback); // never pass `null` as the $template to avoid the fallback to the model ID
$field->value = $parent->toString($field->value ?? '', $data, $fallback);
} else { } else {
$field->value = Str::template($field->value, array_replace([ $field->value = Str::template($field->value, array_replace([
'kirby' => $app, 'kirby' => $app,
'site' => $app->site(), 'site' => $app->site(),
'page' => $app->page() 'page' => $app->page()
], $data), $fallback); ], $data), ['fallback' => $fallback]);
} }
return $field; return $field;

View file

@ -1,93 +0,0 @@
<?php
return [
// kirby
'kirby' => function (array $roots) {
return realpath(__DIR__ . '/../');
},
// i18n
'i18n' => function (array $roots) {
return $roots['kirby'] . '/i18n';
},
'i18n:translations' => function (array $roots) {
return $roots['i18n'] . '/translations';
},
'i18n:rules' => function (array $roots) {
return $roots['i18n'] . '/rules';
},
// index
'index' => function (array $roots) {
return realpath(__DIR__ . '/../../');
},
// assets
'assets' => function (array $roots) {
return $roots['index'] . '/assets';
},
// content
'content' => function (array $roots) {
return $roots['index'] . '/content';
},
// media
'media' => function (array $roots) {
return $roots['index'] . '/media';
},
// panel
'panel' => function (array $roots) {
return $roots['kirby'] . '/panel';
},
// site
'site' => function (array $roots) {
return $roots['index'] . '/site';
},
'accounts' => function (array $roots) {
return $roots['site'] . '/accounts';
},
'blueprints' => function (array $roots) {
return $roots['site'] . '/blueprints';
},
'cache' => function (array $roots) {
return $roots['site'] . '/cache';
},
'collections' => function (array $roots) {
return $roots['site'] . '/collections';
},
'config' => function (array $roots) {
return $roots['site'] . '/config';
},
'controllers' => function (array $roots) {
return $roots['site'] . '/controllers';
},
'languages' => function (array $roots) {
return $roots['site'] . '/languages';
},
'logs' => function (array $roots) {
return $roots['site'] . '/logs';
},
'models' => function (array $roots) {
return $roots['site'] . '/models';
},
'plugins' => function (array $roots) {
return $roots['site'] . '/plugins';
},
'sessions' => function (array $roots) {
return $roots['site'] . '/sessions';
},
'snippets' => function (array $roots) {
return $roots['site'] . '/snippets';
},
'templates' => function (array $roots) {
return $roots['site'] . '/templates';
},
// blueprints
'roles' => function (array $roots) {
return $roots['blueprints'] . '/users';
},
];

View file

@ -2,9 +2,9 @@
use Kirby\Cms\LanguageRoutes; use Kirby\Cms\LanguageRoutes;
use Kirby\Cms\Media; use Kirby\Cms\Media;
use Kirby\Cms\Panel;
use Kirby\Cms\PanelPlugins;
use Kirby\Cms\PluginAssets; use Kirby\Cms\PluginAssets;
use Kirby\Panel\Panel;
use Kirby\Panel\Plugins;
use Kirby\Toolkit\Str; use Kirby\Toolkit\Str;
return function ($kirby) { return function ($kirby) {
@ -50,7 +50,7 @@ return function ($kirby) {
'pattern' => $media . '/plugins/index.(css|js)', 'pattern' => $media . '/plugins/index.(css|js)',
'env' => 'media', 'env' => 'media',
'action' => function (string $type) use ($kirby) { 'action' => function (string $type) use ($kirby) {
$plugins = new PanelPlugins(); $plugins = new Plugins();
return $kirby return $kirby
->response() ->response()
@ -65,17 +65,6 @@ return function ($kirby) {
return PluginAssets::resolve($provider . '/' . $pluginName, $filename . '.' . $extension); return PluginAssets::resolve($provider . '/' . $pluginName, $filename . '.' . $extension);
} }
], ],
[
'pattern' => $panel . '/(:all?)',
'env' => 'panel',
'action' => function () use ($kirby) {
if ($kirby->option('panel') === false) {
return null;
}
return Panel::render($kirby);
}
],
[ [
'pattern' => $media . '/pages/(:all)/(:any)/(:any)', 'pattern' => $media . '/pages/(:all)/(:any)/(:any)',
'env' => 'media', 'env' => 'media',
@ -103,7 +92,15 @@ return function ($kirby) {
'action' => function ($path, $hash, $filename) { 'action' => function ($path, $hash, $filename) {
return Media::thumb($path, $hash, $filename); return Media::thumb($path, $hash, $filename);
} }
] ],
[
'pattern' => $panel . '/(:all?)',
'method' => 'ALL',
'env' => 'panel',
'action' => function ($path = null) {
return Panel::router($path);
}
],
]; ];
// Multi-language setup // Multi-language setup

View file

@ -1,6 +1,6 @@
<?php <?php
use Kirby\Cms\Form; use Kirby\Form\Form;
return [ return [
'props' => [ 'props' => [

View file

@ -1,7 +1,6 @@
<?php <?php
use Kirby\Cms\File; use Kirby\Cms\File;
use Kirby\Toolkit\Escape;
use Kirby\Toolkit\I18n; use Kirby\Toolkit\I18n;
return [ return [
@ -29,7 +28,7 @@ return [
return $image ?? []; return $image ?? [];
}, },
/** /**
* Optional info text setup. Info text is shown on the right (lists) or below (cards) the filename. * Optional info text setup. Info text is shown on the right (lists, cardlets) or below (cards) the filename.
*/ */
'info' => function ($info = null) { 'info' => function ($info = null) {
return I18n::translate($info, $info); return I18n::translate($info, $info);
@ -70,6 +69,7 @@ return [
if ($this->template) { if ($this->template) {
$file = new File([ $file = new File([
'filename' => 'tmp', 'filename' => 'tmp',
'parent' => $this->model(),
'template' => $this->template 'template' => $this->template
]); ]);
@ -90,7 +90,7 @@ return [
if ($this->sortBy) { if ($this->sortBy) {
$files = $files->sort(...$files::sortArgs($this->sortBy)); $files = $files->sort(...$files::sortArgs($this->sortBy));
} else { } else {
$files = $files->sort('sort', 'asc', 'filename', 'asc'); $files = $files->sorted();
} }
// flip // flip
@ -115,28 +115,21 @@ return [
$dragTextAbsolute = $this->model->is($this->parent) === false; $dragTextAbsolute = $this->model->is($this->parent) === false;
foreach ($this->files as $file) { foreach ($this->files as $file) {
$image = $file->panelImage($this->image); $panel = $file->panel();
// escape the default text
// TODO: no longer needed in 3.6
$text = $file->toString($this->text);
if ($this->text === '{{ file.filename }}') {
$text = Escape::html($text);
}
$data[] = [ $data[] = [
'dragText' => $file->dragText('auto', $dragTextAbsolute), 'dragText' => $panel->dragText('auto', $dragTextAbsolute),
'extension' => $file->extension(), 'extension' => $file->extension(),
'filename' => $file->filename(), 'filename' => $file->filename(),
'id' => $file->id(), 'id' => $file->id(),
'icon' => $file->panelIcon($image), 'image' => $panel->image($this->image, $this->layout),
'image' => $image, 'info' => $file->toSafeString($this->info ?? false),
'info' => $file->toString($this->info ?? false), 'link' => $panel->url(true),
'link' => $file->panelUrl(true), 'mime' => $file->mime(),
'mime' => $file->mime(), 'parent' => $file->parent()->panel()->path(),
'parent' => $file->parent()->panelPath(), 'template' => $file->template(),
'text' => $text, 'text' => $file->toSafeString($this->text),
'url' => $file->url(), 'url' => $file->url(),
]; ];
} }
@ -174,8 +167,8 @@ return [
]; ];
}, },
'link' => function () { 'link' => function () {
$modelLink = $this->model->panelUrl(true); $modelLink = $this->model->panel()->url(true);
$parentLink = $this->parent->panelUrl(true); $parentLink = $this->parent->panel()->url(true);
if ($modelLink !== $parentLink) { if ($modelLink !== $parentLink) {
return $parentLink; return $parentLink;
@ -222,6 +215,7 @@ return [
'max' => $max, 'max' => $max,
'api' => $this->parent->apiUrl(true) . '/files', 'api' => $this->parent->apiUrl(true) . '/files',
'attributes' => array_filter([ 'attributes' => array_filter([
'sort' => $this->sortable === true ? $total + 1 : null,
'template' => $template 'template' => $template
]) ])
]; ];

Some files were not shown because too many files have changed in this diff Show more