Initial commit
This commit is contained in:
commit
73c6b816c0
716 changed files with 170045 additions and 0 deletions
80
kirby/config/aliases.php
Normal file
80
kirby/config/aliases.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
// cms classes
|
||||
'collection' => 'Kirby\Cms\Collection',
|
||||
'field' => 'Kirby\Cms\Field',
|
||||
'file' => 'Kirby\Cms\File',
|
||||
'files' => 'Kirby\Cms\Files',
|
||||
'find' => 'Kirby\Cms\Find',
|
||||
'html' => 'Kirby\Cms\Html',
|
||||
'kirby' => 'Kirby\Cms\App',
|
||||
'page' => 'Kirby\Cms\Page',
|
||||
'pages' => 'Kirby\Cms\Pages',
|
||||
'pagination' => 'Kirby\Cms\Pagination',
|
||||
'r' => 'Kirby\Cms\R',
|
||||
'response' => 'Kirby\Cms\Response',
|
||||
's' => 'Kirby\Cms\S',
|
||||
'sane' => 'Kirby\Sane\Sane',
|
||||
'site' => 'Kirby\Cms\Site',
|
||||
'structure' => 'Kirby\Cms\Structure',
|
||||
'url' => 'Kirby\Cms\Url',
|
||||
'user' => 'Kirby\Cms\User',
|
||||
'users' => 'Kirby\Cms\Users',
|
||||
'visitor' => 'Kirby\Cms\Visitor',
|
||||
|
||||
// data handler
|
||||
'data' => 'Kirby\Data\Data',
|
||||
'json' => 'Kirby\Data\Json',
|
||||
'yaml' => 'Kirby\Data\Yaml',
|
||||
|
||||
// file classes
|
||||
'asset' => 'Kirby\Filesystem\Asset',
|
||||
'dir' => 'Kirby\Filesystem\Dir',
|
||||
'f' => 'Kirby\Filesystem\F',
|
||||
'mime' => 'Kirby\Filesystem\Mime',
|
||||
|
||||
// data classes
|
||||
'database' => 'Kirby\Database\Database',
|
||||
'db' => 'Kirby\Database\Db',
|
||||
|
||||
// exceptions
|
||||
'errorpageexception' => 'Kirby\Exception\ErrorPageException',
|
||||
|
||||
// http classes
|
||||
'cookie' => 'Kirby\Http\Cookie',
|
||||
'header' => 'Kirby\Http\Header',
|
||||
'remote' => 'Kirby\Http\Remote',
|
||||
'server' => 'Kirby\Http\Server',
|
||||
|
||||
// image classes
|
||||
'dimensions' => 'Kirby\Image\Dimensions',
|
||||
|
||||
// panel classes
|
||||
'panel' => 'Kirby\Panel\Panel',
|
||||
|
||||
// toolkit classes
|
||||
'a' => 'Kirby\Toolkit\A',
|
||||
'c' => 'Kirby\Toolkit\Config',
|
||||
'config' => 'Kirby\Toolkit\Config',
|
||||
'escape' => 'Kirby\Toolkit\Escape',
|
||||
'i18n' => 'Kirby\Toolkit\I18n',
|
||||
'obj' => 'Kirby\Toolkit\Obj',
|
||||
'str' => 'Kirby\Toolkit\Str',
|
||||
'tpl' => 'Kirby\Toolkit\Tpl',
|
||||
'v' => 'Kirby\Toolkit\V',
|
||||
'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',
|
||||
];
|
27
kirby/config/api/authentication.php
Normal file
27
kirby/config/api/authentication.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Exception\PermissionException;
|
||||
|
||||
return function () {
|
||||
$auth = $this->kirby()->auth();
|
||||
$allowImpersonation = $this->kirby()->option('api.allowImpersonation') ?? false;
|
||||
|
||||
// csrf token check
|
||||
if (
|
||||
$auth->type($allowImpersonation) === 'session' &&
|
||||
$auth->csrf() === false
|
||||
) {
|
||||
throw new PermissionException('Unauthenticated');
|
||||
}
|
||||
|
||||
// get user from session or basic auth
|
||||
if ($user = $auth->user(null, $allowImpersonation)) {
|
||||
if ($user->role()->permissions()->for('access', 'panel') === false) {
|
||||
throw new PermissionException(['key' => 'access.panel']);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
throw new PermissionException('Unauthenticated');
|
||||
};
|
70
kirby/config/api/collections.php
Normal file
70
kirby/config/api/collections.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Api Collection Definitions
|
||||
*/
|
||||
return [
|
||||
|
||||
/**
|
||||
* Children
|
||||
*/
|
||||
'children' => [
|
||||
'model' => 'page',
|
||||
'type' => 'Kirby\Cms\Pages',
|
||||
'view' => 'compact'
|
||||
],
|
||||
|
||||
/**
|
||||
* Files
|
||||
*/
|
||||
'files' => [
|
||||
'model' => 'file',
|
||||
'type' => 'Kirby\Cms\Files'
|
||||
],
|
||||
|
||||
/**
|
||||
* Languages
|
||||
*/
|
||||
'languages' => [
|
||||
'model' => 'language',
|
||||
'type' => 'Kirby\Cms\Languages'
|
||||
],
|
||||
|
||||
/**
|
||||
* Pages
|
||||
*/
|
||||
'pages' => [
|
||||
'model' => 'page',
|
||||
'type' => 'Kirby\Cms\Pages',
|
||||
'view' => 'compact'
|
||||
],
|
||||
|
||||
/**
|
||||
* Roles
|
||||
*/
|
||||
'roles' => [
|
||||
'model' => 'role',
|
||||
'type' => 'Kirby\Cms\Roles',
|
||||
'view' => 'compact'
|
||||
],
|
||||
|
||||
/**
|
||||
* Translations
|
||||
*/
|
||||
'translations' => [
|
||||
'model' => 'translation',
|
||||
'type' => 'Kirby\Cms\Translations',
|
||||
'view' => 'compact'
|
||||
],
|
||||
|
||||
/**
|
||||
* Users
|
||||
*/
|
||||
'users' => [
|
||||
'default' => fn () => $this->users(),
|
||||
'model' => 'user',
|
||||
'type' => 'Kirby\Cms\Users',
|
||||
'view' => 'compact'
|
||||
]
|
||||
|
||||
];
|
20
kirby/config/api/models.php
Normal file
20
kirby/config/api/models.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Api Model Definitions
|
||||
*/
|
||||
return [
|
||||
'File' => include __DIR__ . '/models/File.php',
|
||||
'FileBlueprint' => include __DIR__ . '/models/FileBlueprint.php',
|
||||
'FileVersion' => include __DIR__ . '/models/FileVersion.php',
|
||||
'Language' => include __DIR__ . '/models/Language.php',
|
||||
'Page' => include __DIR__ . '/models/Page.php',
|
||||
'PageBlueprint' => include __DIR__ . '/models/PageBlueprint.php',
|
||||
'Role' => include __DIR__ . '/models/Role.php',
|
||||
'Site' => include __DIR__ . '/models/Site.php',
|
||||
'SiteBlueprint' => include __DIR__ . '/models/SiteBlueprint.php',
|
||||
'System' => include __DIR__ . '/models/System.php',
|
||||
'Translation' => include __DIR__ . '/models/Translation.php',
|
||||
'User' => include __DIR__ . '/models/User.php',
|
||||
'UserBlueprint' => include __DIR__ . '/models/UserBlueprint.php',
|
||||
];
|
122
kirby/config/api/models/File.php
Normal file
122
kirby/config/api/models/File.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\File;
|
||||
use Kirby\Form\Form;
|
||||
|
||||
/**
|
||||
* File
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'blueprint' => fn (File $file) => $file->blueprint(),
|
||||
'content' => fn (File $file) => Form::for($file)->values(),
|
||||
'dimensions' => fn (File $file) => $file->dimensions()->toArray(),
|
||||
'dragText' => fn (File $file) => $file->panel()->dragText(),
|
||||
'exists' => fn (File $file) => $file->exists(),
|
||||
'extension' => fn (File $file) => $file->extension(),
|
||||
'filename' => fn (File $file) => $file->filename(),
|
||||
'id' => fn (File $file) => $file->id(),
|
||||
'link' => fn (File $file) => $file->panel()->url(true),
|
||||
'mime' => fn (File $file) => $file->mime(),
|
||||
'modified' => fn (File $file) => $file->modified('c'),
|
||||
'name' => fn (File $file) => $file->name(),
|
||||
'next' => fn (File $file) => $file->next(),
|
||||
'nextWithTemplate' => function (File $file) {
|
||||
$files = $file->templateSiblings()->sorted();
|
||||
$index = $files->indexOf($file);
|
||||
|
||||
return $files->nth($index + 1);
|
||||
},
|
||||
'niceSize' => fn (File $file) => $file->niceSize(),
|
||||
'options' => fn (File $file) => $file->panel()->options(),
|
||||
'panelIcon' => function (File $file) {
|
||||
// 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' => fn (File $file) => $file->panel()->image(),
|
||||
'panelUrl' => fn (File $file) => $file->panel()->url(true),
|
||||
'prev' => fn (File $file) => $file->prev(),
|
||||
'prevWithTemplate' => function (File $file) {
|
||||
$files = $file->templateSiblings()->sorted();
|
||||
$index = $files->indexOf($file);
|
||||
|
||||
return $files->nth($index - 1);
|
||||
},
|
||||
'parent' => fn (File $file) => $file->parent(),
|
||||
'parents' => fn (File $file) => $file->parents()->flip(),
|
||||
'size' => fn (File $file) => $file->size(),
|
||||
'template' => fn (File $file) => $file->template(),
|
||||
'thumbs' => function ($file) {
|
||||
if ($file->isResizable() === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'tiny' => $file->resize(128)->url(),
|
||||
'small' => $file->resize(256)->url(),
|
||||
'medium' => $file->resize(512)->url(),
|
||||
'large' => $file->resize(768)->url(),
|
||||
'huge' => $file->resize(1024)->url(),
|
||||
];
|
||||
},
|
||||
'type' => fn (File $file) => $file->type(),
|
||||
'url' => fn (File $file) => $file->url(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\File',
|
||||
'views' => [
|
||||
'default' => [
|
||||
'content',
|
||||
'dimensions',
|
||||
'exists',
|
||||
'extension',
|
||||
'filename',
|
||||
'id',
|
||||
'link',
|
||||
'mime',
|
||||
'modified',
|
||||
'name',
|
||||
'next' => 'compact',
|
||||
'niceSize',
|
||||
'parent' => 'compact',
|
||||
'options',
|
||||
'prev' => 'compact',
|
||||
'size',
|
||||
'template',
|
||||
'type',
|
||||
'url'
|
||||
],
|
||||
'compact' => [
|
||||
'filename',
|
||||
'id',
|
||||
'link',
|
||||
'type',
|
||||
'url',
|
||||
],
|
||||
'panel' => [
|
||||
'blueprint',
|
||||
'content',
|
||||
'dimensions',
|
||||
'extension',
|
||||
'filename',
|
||||
'id',
|
||||
'link',
|
||||
'mime',
|
||||
'modified',
|
||||
'name',
|
||||
'nextWithTemplate' => 'compact',
|
||||
'niceSize',
|
||||
'options',
|
||||
'panelIcon',
|
||||
'panelImage',
|
||||
'parent' => 'compact',
|
||||
'parents' => ['id', 'slug', 'title'],
|
||||
'prevWithTemplate' => 'compact',
|
||||
'template',
|
||||
'type',
|
||||
'url'
|
||||
]
|
||||
],
|
||||
];
|
18
kirby/config/api/models/FileBlueprint.php
Normal file
18
kirby/config/api/models/FileBlueprint.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\FileBlueprint;
|
||||
|
||||
/**
|
||||
* FileBlueprint
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'name' => fn (FileBlueprint $blueprint) => $blueprint->name(),
|
||||
'options' => fn (FileBlueprint $blueprint) => $blueprint->options(),
|
||||
'tabs' => fn (FileBlueprint $blueprint) => $blueprint->tabs(),
|
||||
'title' => fn (FileBlueprint $blueprint) => $blueprint->title(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\FileBlueprint',
|
||||
'views' => [
|
||||
],
|
||||
];
|
59
kirby/config/api/models/FileVersion.php
Normal file
59
kirby/config/api/models/FileVersion.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\FileVersion;
|
||||
|
||||
/**
|
||||
* FileVersion
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'dimensions' => fn (FileVersion $file) => $file->dimensions()->toArray(),
|
||||
'exists' => fn (FileVersion $file) => $file->exists(),
|
||||
'extension' => fn (FileVersion $file) => $file->extension(),
|
||||
'filename' => fn (FileVersion $file) => $file->filename(),
|
||||
'id' => fn (FileVersion $file) => $file->id(),
|
||||
'mime' => fn (FileVersion $file) => $file->mime(),
|
||||
'modified' => fn (FileVersion $file) => $file->modified('c'),
|
||||
'name' => fn (FileVersion $file) => $file->name(),
|
||||
'niceSize' => fn (FileVersion $file) => $file->niceSize(),
|
||||
'size' => fn (FileVersion $file) => $file->size(),
|
||||
'type' => fn (FileVersion $file) => $file->type(),
|
||||
'url' => fn (FileVersion $file) => $file->url(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\FileVersion',
|
||||
'views' => [
|
||||
'default' => [
|
||||
'dimensions',
|
||||
'exists',
|
||||
'extension',
|
||||
'filename',
|
||||
'id',
|
||||
'mime',
|
||||
'modified',
|
||||
'name',
|
||||
'niceSize',
|
||||
'size',
|
||||
'type',
|
||||
'url'
|
||||
],
|
||||
'compact' => [
|
||||
'filename',
|
||||
'id',
|
||||
'type',
|
||||
'url',
|
||||
],
|
||||
'panel' => [
|
||||
'dimensions',
|
||||
'extension',
|
||||
'filename',
|
||||
'id',
|
||||
'mime',
|
||||
'modified',
|
||||
'name',
|
||||
'niceSize',
|
||||
'template',
|
||||
'type',
|
||||
'url'
|
||||
]
|
||||
],
|
||||
];
|
30
kirby/config/api/models/Language.php
Normal file
30
kirby/config/api/models/Language.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Language;
|
||||
|
||||
/**
|
||||
* Language
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'code' => fn (Language $language) => $language->code(),
|
||||
'default' => fn (Language $language) => $language->isDefault(),
|
||||
'direction' => fn (Language $language) => $language->direction(),
|
||||
'locale' => fn (Language $language) => $language->locale(),
|
||||
'name' => fn (Language $language) => $language->name(),
|
||||
'rules' => fn (Language $language) => $language->rules(),
|
||||
'url' => fn (Language $language) => $language->url(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\Language',
|
||||
'views' => [
|
||||
'default' => [
|
||||
'code',
|
||||
'default',
|
||||
'direction',
|
||||
'locale',
|
||||
'name',
|
||||
'rules',
|
||||
'url'
|
||||
]
|
||||
]
|
||||
];
|
128
kirby/config/api/models/Page.php
Normal file
128
kirby/config/api/models/Page.php
Normal file
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Page;
|
||||
use Kirby\Form\Form;
|
||||
|
||||
/**
|
||||
* Page
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'blueprint' => fn (Page $page) => $page->blueprint(),
|
||||
'blueprints' => fn (Page $page) => $page->blueprints(),
|
||||
'children' => fn (Page $page) => $page->children(),
|
||||
'content' => fn (Page $page) => Form::for($page)->values(),
|
||||
'drafts' => fn (Page $page) => $page->drafts(),
|
||||
'errors' => fn (Page $page) => $page->errors(),
|
||||
'files' => fn (Page $page) => $page->files()->sorted(),
|
||||
'hasChildren' => fn (Page $page) => $page->hasChildren(),
|
||||
'hasDrafts' => fn (Page $page) => $page->hasDrafts(),
|
||||
'hasFiles' => fn (Page $page) => $page->hasFiles(),
|
||||
'id' => fn (Page $page) => $page->id(),
|
||||
'isSortable' => fn (Page $page) => $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) {
|
||||
return $page
|
||||
->nextAll()
|
||||
->filter('intendedTemplate', $page->intendedTemplate())
|
||||
->filter('status', $page->status())
|
||||
->filter('isReadable', true)
|
||||
->first();
|
||||
},
|
||||
'num' => fn (Page $page) => $page->num(),
|
||||
'options' => fn (Page $page) => $page->panel()->options(['preview']),
|
||||
/**
|
||||
* @todo Remove in 3.7.0
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
'panelIcon' => function (Page $page) {
|
||||
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' => fn (Page $page) => $page->panel()->image(),
|
||||
'parent' => fn (Page $page) => $page->parent(),
|
||||
'parents' => fn (Page $page) => $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) {
|
||||
return $page
|
||||
->prevAll()
|
||||
->filter('intendedTemplate', $page->intendedTemplate())
|
||||
->filter('status', $page->status())
|
||||
->filter('isReadable', true)
|
||||
->last();
|
||||
},
|
||||
'previewUrl' => fn (Page $page) => $page->previewUrl(),
|
||||
'siblings' => function (Page $page) {
|
||||
if ($page->isDraft() === true) {
|
||||
return $page->parentModel()->children()->not($page);
|
||||
} else {
|
||||
return $page->siblings();
|
||||
}
|
||||
},
|
||||
'slug' => fn (Page $page) => $page->slug(),
|
||||
'status' => fn (Page $page) => $page->status(),
|
||||
'template' => fn (Page $page) => $page->intendedTemplate()->name(),
|
||||
'title' => fn (Page $page) => $page->title()->value(),
|
||||
'url' => fn (Page $page) => $page->url(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\Page',
|
||||
'views' => [
|
||||
'compact' => [
|
||||
'id',
|
||||
'title',
|
||||
'url',
|
||||
'num'
|
||||
],
|
||||
'default' => [
|
||||
'content',
|
||||
'id',
|
||||
'status',
|
||||
'num',
|
||||
'options',
|
||||
'parent' => 'compact',
|
||||
'slug',
|
||||
'template',
|
||||
'title',
|
||||
'url'
|
||||
],
|
||||
'panel' => [
|
||||
'id',
|
||||
'blueprint',
|
||||
'content',
|
||||
'status',
|
||||
'options',
|
||||
'next' => ['id', 'slug', 'title'],
|
||||
'parents' => ['id', 'slug', 'title'],
|
||||
'prev' => ['id', 'slug', 'title'],
|
||||
'previewUrl',
|
||||
'slug',
|
||||
'title',
|
||||
'url'
|
||||
],
|
||||
'selector' => [
|
||||
'id',
|
||||
'title',
|
||||
'parent' => [
|
||||
'id',
|
||||
'title'
|
||||
],
|
||||
'children' => [
|
||||
'hasChildren',
|
||||
'id',
|
||||
'panelIcon',
|
||||
'panelImage',
|
||||
'title',
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
21
kirby/config/api/models/PageBlueprint.php
Normal file
21
kirby/config/api/models/PageBlueprint.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\PageBlueprint;
|
||||
|
||||
/**
|
||||
* PageBlueprint
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'name' => fn (PageBlueprint $blueprint) => $blueprint->name(),
|
||||
'num' => fn (PageBlueprint $blueprint) => $blueprint->num(),
|
||||
'options' => fn (PageBlueprint $blueprint) => $blueprint->options(),
|
||||
'preview' => fn (PageBlueprint $blueprint) => $blueprint->preview(),
|
||||
'status' => fn (PageBlueprint $blueprint) => $blueprint->status(),
|
||||
'tabs' => fn (PageBlueprint $blueprint) => $blueprint->tabs(),
|
||||
'title' => fn (PageBlueprint $blueprint) => $blueprint->title(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\PageBlueprint',
|
||||
'views' => [
|
||||
],
|
||||
];
|
23
kirby/config/api/models/Role.php
Normal file
23
kirby/config/api/models/Role.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Role;
|
||||
|
||||
/**
|
||||
* Role
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'description' => fn (Role $role) => $role->description(),
|
||||
'name' => fn (Role $role) => $role->name(),
|
||||
'permissions' => fn (Role $role) => $role->permissions()->toArray(),
|
||||
'title' => fn (Role $role) => $role->title(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\Role',
|
||||
'views' => [
|
||||
'compact' => [
|
||||
'description',
|
||||
'name',
|
||||
'title'
|
||||
]
|
||||
]
|
||||
];
|
52
kirby/config/api/models/Site.php
Normal file
52
kirby/config/api/models/Site.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Site;
|
||||
use Kirby\Form\Form;
|
||||
|
||||
/**
|
||||
* Site
|
||||
*/
|
||||
return [
|
||||
'default' => fn () => $this->site(),
|
||||
'fields' => [
|
||||
'blueprint' => fn (Site $site) => $site->blueprint(),
|
||||
'children' => fn (Site $site) => $site->children(),
|
||||
'content' => fn (Site $site) => Form::for($site)->values(),
|
||||
'drafts' => fn (Site $site) => $site->drafts(),
|
||||
'files' => fn (Site $site) => $site->files()->sorted(),
|
||||
'options' => fn (Site $site) => $site->permissions()->toArray(),
|
||||
'previewUrl' => fn (Site $site) => $site->previewUrl(),
|
||||
'title' => fn (Site $site) => $site->title()->value(),
|
||||
'url' => fn (Site $site) => $site->url(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\Site',
|
||||
'views' => [
|
||||
'compact' => [
|
||||
'title',
|
||||
'url'
|
||||
],
|
||||
'default' => [
|
||||
'content',
|
||||
'options',
|
||||
'title',
|
||||
'url'
|
||||
],
|
||||
'panel' => [
|
||||
'title',
|
||||
'blueprint',
|
||||
'content',
|
||||
'options',
|
||||
'previewUrl',
|
||||
'url'
|
||||
],
|
||||
'selector' => [
|
||||
'title',
|
||||
'children' => [
|
||||
'id',
|
||||
'title',
|
||||
'panelIcon',
|
||||
'hasChildren'
|
||||
],
|
||||
]
|
||||
]
|
||||
];
|
17
kirby/config/api/models/SiteBlueprint.php
Normal file
17
kirby/config/api/models/SiteBlueprint.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\SiteBlueprint;
|
||||
|
||||
/**
|
||||
* SiteBlueprint
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'name' => fn (SiteBlueprint $blueprint) => $blueprint->name(),
|
||||
'options' => fn (SiteBlueprint $blueprint) => $blueprint->options(),
|
||||
'tabs' => fn (SiteBlueprint $blueprint) => $blueprint->tabs(),
|
||||
'title' => fn (SiteBlueprint $blueprint) => $blueprint->title(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\SiteBlueprint',
|
||||
'views' => [],
|
||||
];
|
98
kirby/config/api/models/System.php
Normal file
98
kirby/config/api/models/System.php
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\System;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
/**
|
||||
* System
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'ascii' => fn () => Str::$ascii,
|
||||
'authStatus' => fn () => $this->kirby()->auth()->status()->toArray(),
|
||||
'defaultLanguage' => fn () => $this->kirby()->panelLanguage(),
|
||||
'isOk' => fn (System $system) => $system->isOk(),
|
||||
'isInstallable' => fn (System $system) => $system->isInstallable(),
|
||||
'isInstalled' => fn (System $system) => $system->isInstalled(),
|
||||
'isLocal' => fn (System $system) => $system->isLocal(),
|
||||
'multilang' => fn () => $this->kirby()->option('languages', false) !== false,
|
||||
'languages' => fn () => $this->kirby()->languages(),
|
||||
'license' => fn (System $system) => $system->license(),
|
||||
'locales' => function () {
|
||||
$locales = [];
|
||||
$translations = $this->kirby()->translations();
|
||||
foreach ($translations as $translation) {
|
||||
$locales[$translation->code()] = $translation->locale();
|
||||
}
|
||||
return $locales;
|
||||
},
|
||||
'loginMethods' => fn (System $system) => array_keys($system->loginMethods()),
|
||||
'requirements' => fn (System $system) => $system->toArray(),
|
||||
'site' => fn (System $system) => $system->title(),
|
||||
'slugs' => fn () => Str::$language,
|
||||
'title' => fn () => $this->site()->title()->value(),
|
||||
'translation' => function () {
|
||||
if ($user = $this->user()) {
|
||||
$translationCode = $user->language();
|
||||
} else {
|
||||
$translationCode = $this->kirby()->panelLanguage();
|
||||
}
|
||||
|
||||
if ($translation = $this->kirby()->translation($translationCode)) {
|
||||
return $translation;
|
||||
} else {
|
||||
return $this->kirby()->translation('en');
|
||||
}
|
||||
},
|
||||
'kirbytext' => fn () => $this->kirby()->option('panel.kirbytext') ?? true,
|
||||
'user' => fn () => $this->user(),
|
||||
'version' => function () {
|
||||
$user = $this->user();
|
||||
|
||||
if ($user && $user->role()->permissions()->for('access', 'system') === true) {
|
||||
return $this->kirby()->version();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
],
|
||||
'type' => 'Kirby\Cms\System',
|
||||
'views' => [
|
||||
'login' => [
|
||||
'authStatus',
|
||||
'isOk',
|
||||
'isInstallable',
|
||||
'isInstalled',
|
||||
'loginMethods',
|
||||
'title',
|
||||
'translation'
|
||||
],
|
||||
'troubleshooting' => [
|
||||
'isOk',
|
||||
'isInstallable',
|
||||
'isInstalled',
|
||||
'title',
|
||||
'translation',
|
||||
'requirements'
|
||||
],
|
||||
'panel' => [
|
||||
'ascii',
|
||||
'defaultLanguage',
|
||||
'isOk',
|
||||
'isInstalled',
|
||||
'isLocal',
|
||||
'kirbytext',
|
||||
'languages',
|
||||
'license',
|
||||
'locales',
|
||||
'multilang',
|
||||
'requirements',
|
||||
'site',
|
||||
'slugs',
|
||||
'title',
|
||||
'translation',
|
||||
'user' => 'auth',
|
||||
'version'
|
||||
]
|
||||
],
|
||||
];
|
24
kirby/config/api/models/Translation.php
Normal file
24
kirby/config/api/models/Translation.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Translation;
|
||||
|
||||
/**
|
||||
* Translation
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'author' => fn (Translation $translation) => $translation->author(),
|
||||
'data' => fn (Translation $translation) => $translation->dataWithFallback(),
|
||||
'direction' => fn (Translation $translation) => $translation->direction(),
|
||||
'id' => fn (Translation $translation) => $translation->id(),
|
||||
'name' => fn (Translation $translation) => $translation->name(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\Translation',
|
||||
'views' => [
|
||||
'compact' => [
|
||||
'direction',
|
||||
'id',
|
||||
'name'
|
||||
]
|
||||
]
|
||||
];
|
77
kirby/config/api/models/User.php
Normal file
77
kirby/config/api/models/User.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\User;
|
||||
use Kirby\Form\Form;
|
||||
|
||||
/**
|
||||
* User
|
||||
*/
|
||||
return [
|
||||
'default' => fn () => $this->user(),
|
||||
'fields' => [
|
||||
'avatar' => fn (User $user) => $user->avatar() ? $user->avatar()->crop(512) : null,
|
||||
'blueprint' => fn (User $user) => $user->blueprint(),
|
||||
'content' => fn (User $user) => Form::for($user)->values(),
|
||||
'email' => fn (User $user) => $user->email(),
|
||||
'files' => fn (User $user) => $user->files()->sorted(),
|
||||
'id' => fn (User $user) => $user->id(),
|
||||
'language' => fn (User $user) => $user->language(),
|
||||
'name' => fn (User $user) => $user->name()->value(),
|
||||
'next' => fn (User $user) => $user->next(),
|
||||
'options' => fn (User $user) => $user->panel()->options(),
|
||||
'panelImage' => fn (User $user) => $user->panel()->image(),
|
||||
'permissions' => fn (User $user) => $user->role()->permissions()->toArray(),
|
||||
'prev' => fn (User $user) => $user->prev(),
|
||||
'role' => fn (User $user) => $user->role(),
|
||||
'roles' => fn (User $user) => $user->roles(),
|
||||
'username' => fn (User $user) => $user->username()
|
||||
],
|
||||
'type' => 'Kirby\Cms\User',
|
||||
'views' => [
|
||||
'default' => [
|
||||
'avatar',
|
||||
'content',
|
||||
'email',
|
||||
'id',
|
||||
'language',
|
||||
'name',
|
||||
'next' => 'compact',
|
||||
'options',
|
||||
'prev' => 'compact',
|
||||
'role',
|
||||
'username'
|
||||
],
|
||||
'compact' => [
|
||||
'avatar' => 'compact',
|
||||
'id',
|
||||
'email',
|
||||
'language',
|
||||
'name',
|
||||
'role' => 'compact',
|
||||
'username'
|
||||
],
|
||||
'auth' => [
|
||||
'avatar' => 'compact',
|
||||
'permissions',
|
||||
'email',
|
||||
'id',
|
||||
'name',
|
||||
'role',
|
||||
'language'
|
||||
],
|
||||
'panel' => [
|
||||
'avatar' => 'compact',
|
||||
'blueprint',
|
||||
'content',
|
||||
'email',
|
||||
'id',
|
||||
'language',
|
||||
'name',
|
||||
'next' => ['id', 'name'],
|
||||
'options',
|
||||
'prev' => ['id', 'name'],
|
||||
'role',
|
||||
'username',
|
||||
],
|
||||
]
|
||||
];
|
18
kirby/config/api/models/UserBlueprint.php
Normal file
18
kirby/config/api/models/UserBlueprint.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\UserBlueprint;
|
||||
|
||||
/**
|
||||
* UserBlueprint
|
||||
*/
|
||||
return [
|
||||
'fields' => [
|
||||
'name' => fn (UserBlueprint $blueprint) => $blueprint->name(),
|
||||
'options' => fn (UserBlueprint $blueprint) => $blueprint->options(),
|
||||
'tabs' => fn (UserBlueprint $blueprint) => $blueprint->tabs(),
|
||||
'title' => fn (UserBlueprint $blueprint) => $blueprint->title(),
|
||||
],
|
||||
'type' => 'Kirby\Cms\UserBlueprint',
|
||||
'views' => [
|
||||
],
|
||||
];
|
26
kirby/config/api/routes.php
Normal file
26
kirby/config/api/routes.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Api Routes Definitions
|
||||
*/
|
||||
return function ($kirby) {
|
||||
$routes = array_merge(
|
||||
include __DIR__ . '/routes/auth.php',
|
||||
include __DIR__ . '/routes/pages.php',
|
||||
include __DIR__ . '/routes/roles.php',
|
||||
include __DIR__ . '/routes/site.php',
|
||||
include __DIR__ . '/routes/users.php',
|
||||
include __DIR__ . '/routes/files.php',
|
||||
include __DIR__ . '/routes/lock.php',
|
||||
include __DIR__ . '/routes/system.php',
|
||||
include __DIR__ . '/routes/translations.php'
|
||||
);
|
||||
|
||||
// only add the language routes if the
|
||||
// multi language setup is activated
|
||||
if ($kirby->option('languages', false) !== false) {
|
||||
$routes = array_merge($routes, include __DIR__ . '/routes/languages.php');
|
||||
}
|
||||
|
||||
return $routes;
|
||||
};
|
108
kirby/config/api/routes/auth.php
Normal file
108
kirby/config/api/routes/auth.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
|
||||
/**
|
||||
* Authentication
|
||||
*/
|
||||
return [
|
||||
[
|
||||
'pattern' => 'auth',
|
||||
'method' => 'GET',
|
||||
'action' => function () {
|
||||
if ($user = $this->kirby()->auth()->user()) {
|
||||
return $this->resolve($user)->view('auth');
|
||||
}
|
||||
|
||||
throw new NotFoundException('The user cannot be found');
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'auth/code',
|
||||
'method' => 'POST',
|
||||
'auth' => false,
|
||||
'action' => function () {
|
||||
$auth = $this->kirby()->auth();
|
||||
|
||||
// csrf token check
|
||||
if ($auth->type() === 'session' && $auth->csrf() === false) {
|
||||
throw new InvalidArgumentException('Invalid CSRF token');
|
||||
}
|
||||
|
||||
$user = $auth->verifyChallenge($this->requestBody('code'));
|
||||
|
||||
return [
|
||||
'code' => 200,
|
||||
'status' => 'ok',
|
||||
'user' => $this->resolve($user)->view('auth')->toArray()
|
||||
];
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'auth/login',
|
||||
'method' => 'POST',
|
||||
'auth' => false,
|
||||
'action' => function () {
|
||||
$auth = $this->kirby()->auth();
|
||||
$methods = $this->kirby()->system()->loginMethods();
|
||||
|
||||
// csrf token check
|
||||
if ($auth->type() === 'session' && $auth->csrf() === false) {
|
||||
throw new InvalidArgumentException('Invalid CSRF token');
|
||||
}
|
||||
|
||||
$email = $this->requestBody('email');
|
||||
$long = $this->requestBody('long');
|
||||
$password = $this->requestBody('password');
|
||||
|
||||
if ($password) {
|
||||
if (isset($methods['password']) !== true) {
|
||||
throw new InvalidArgumentException('Login with password is not enabled');
|
||||
}
|
||||
|
||||
if (
|
||||
isset($methods['password']['2fa']) === true &&
|
||||
$methods['password']['2fa'] === true
|
||||
) {
|
||||
$status = $auth->login2fa($email, $password, $long);
|
||||
} else {
|
||||
$user = $auth->login($email, $password, $long);
|
||||
}
|
||||
} else {
|
||||
if (isset($methods['code']) === true) {
|
||||
$mode = 'login';
|
||||
} elseif (isset($methods['password-reset']) === true) {
|
||||
$mode = 'password-reset';
|
||||
} else {
|
||||
throw new InvalidArgumentException('Login without password is not enabled');
|
||||
}
|
||||
|
||||
$status = $auth->createChallenge($email, $long, $mode);
|
||||
}
|
||||
|
||||
if (isset($user)) {
|
||||
return [
|
||||
'code' => 200,
|
||||
'status' => 'ok',
|
||||
'user' => $this->resolve($user)->view('auth')->toArray()
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'code' => 200,
|
||||
'status' => 'ok',
|
||||
'challenge' => $status->challenge()
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'auth/logout',
|
||||
'method' => 'POST',
|
||||
'auth' => false,
|
||||
'action' => function () {
|
||||
$this->kirby()->auth()->logout();
|
||||
return true;
|
||||
}
|
||||
],
|
||||
];
|
132
kirby/config/api/routes/files.php
Normal file
132
kirby/config/api/routes/files.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
// routing pattern to match all models with files
|
||||
$pattern = '(account|pages/[^/]+|site|users/[^/]+)';
|
||||
|
||||
/**
|
||||
* Files Routes
|
||||
*/
|
||||
return [
|
||||
|
||||
[
|
||||
'pattern' => $pattern . '/files/(:any)/sections/(:any)',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $path, string $filename, string $sectionName) {
|
||||
if ($section = $this->file($path, $filename)->blueprint()->section($sectionName)) {
|
||||
return $section->toResponse();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files/(:any)/fields/(:any)/(:all?)',
|
||||
'method' => 'ALL',
|
||||
'action' => function (string $parent, string $filename, string $fieldName, string $path = null) {
|
||||
if ($file = $this->file($parent, $filename)) {
|
||||
return $this->fieldApi($file, $fieldName, $path);
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $path) {
|
||||
return $this->parent($path)->files()->sorted();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files',
|
||||
'method' => 'POST',
|
||||
'action' => function (string $path) {
|
||||
// move_uploaded_file() not working with unit test
|
||||
// @codeCoverageIgnoreStart
|
||||
return $this->upload(function ($source, $filename) use ($path) {
|
||||
return $this->parent($path)->createFile([
|
||||
'content' => [
|
||||
'sort' => $this->requestBody('sort')
|
||||
],
|
||||
'source' => $source,
|
||||
'template' => $this->requestBody('template'),
|
||||
'filename' => $filename
|
||||
]);
|
||||
});
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files/search',
|
||||
'method' => 'GET|POST',
|
||||
'action' => function (string $path) {
|
||||
$files = $this->parent($path)->files();
|
||||
|
||||
if ($this->requestMethod() === 'GET') {
|
||||
return $files->search($this->requestQuery('q'));
|
||||
} else {
|
||||
return $files->query($this->requestBody());
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files/sort',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $path) {
|
||||
return $this->parent($path)->files()->changeSort(
|
||||
$this->requestBody('files'),
|
||||
$this->requestBody('index')
|
||||
);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files/(:any)',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $path, string $filename) {
|
||||
return $this->file($path, $filename);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files/(:any)',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $path, string $filename) {
|
||||
return $this->file($path, $filename)->update($this->requestBody(), $this->language(), true);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files/(:any)',
|
||||
'method' => 'POST',
|
||||
'action' => function (string $path, string $filename) {
|
||||
return $this->upload(function ($source) use ($path, $filename) {
|
||||
return $this->file($path, $filename)->replace($source);
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files/(:any)',
|
||||
'method' => 'DELETE',
|
||||
'action' => function (string $path, string $filename) {
|
||||
return $this->file($path, $filename)->delete();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => $pattern . '/files/(:any)/name',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $path, string $filename) {
|
||||
return $this->file($path, $filename)->changeName($this->requestBody('name'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'files/search',
|
||||
'method' => 'GET|POST',
|
||||
'action' => function () {
|
||||
$files = $this
|
||||
->site()
|
||||
->index(true)
|
||||
->filter('isReadable', true)
|
||||
->files();
|
||||
|
||||
if ($this->requestMethod() === 'GET') {
|
||||
return $files->search($this->requestQuery('q'));
|
||||
} else {
|
||||
return $files->query($this->requestBody());
|
||||
}
|
||||
}
|
||||
],
|
||||
];
|
46
kirby/config/api/routes/languages.php
Normal file
46
kirby/config/api/routes/languages.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Roles Routes
|
||||
*/
|
||||
return [
|
||||
[
|
||||
'pattern' => 'languages',
|
||||
'method' => 'GET',
|
||||
'action' => function () {
|
||||
return $this->kirby()->languages();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'languages',
|
||||
'method' => 'POST',
|
||||
'action' => function () {
|
||||
return $this->kirby()->languages()->create($this->requestBody());
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'languages/(:any)',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $code) {
|
||||
return $this->kirby()->languages()->find($code);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'languages/(:any)',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $code) {
|
||||
if ($language = $this->kirby()->languages()->find($code)) {
|
||||
return $language->update($this->requestBody());
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'languages/(:any)',
|
||||
'method' => 'DELETE',
|
||||
'action' => function (string $code) {
|
||||
if ($language = $this->kirby()->languages()->find($code)) {
|
||||
return $language->delete();
|
||||
}
|
||||
}
|
||||
]
|
||||
];
|
91
kirby/config/api/routes/lock.php
Normal file
91
kirby/config/api/routes/lock.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* Content Lock Routes
|
||||
*/
|
||||
return [
|
||||
[
|
||||
'pattern' => '(:all)/lock',
|
||||
'method' => 'GET',
|
||||
/**
|
||||
* @deprecated 3.6.0
|
||||
* @todo Remove in 3.7.0
|
||||
*/
|
||||
'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()) {
|
||||
return [
|
||||
'supported' => true,
|
||||
'locked' => $lock->get()
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'supported' => false,
|
||||
'locked' => null
|
||||
];
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => '(:all)/lock',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $path) {
|
||||
if ($lock = $this->parent($path)->lock()) {
|
||||
return $lock->create();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => '(:all)/lock',
|
||||
'method' => 'DELETE',
|
||||
'action' => function (string $path) {
|
||||
if ($lock = $this->parent($path)->lock()) {
|
||||
return $lock->remove();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => '(:all)/unlock',
|
||||
'method' => 'GET',
|
||||
/**
|
||||
* @deprecated 3.6.0
|
||||
* @todo Remove in 3.7.0
|
||||
*/
|
||||
'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()) {
|
||||
return [
|
||||
'supported' => true,
|
||||
'unlocked' => $lock->isUnlocked()
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'supported' => false,
|
||||
'unlocked' => null
|
||||
];
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => '(:all)/unlock',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $path) {
|
||||
if ($lock = $this->parent($path)->lock()) {
|
||||
return $lock->unlock();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => '(:all)/unlock',
|
||||
'method' => 'DELETE',
|
||||
'action' => function (string $path) {
|
||||
if ($lock = $this->parent($path)->lock()) {
|
||||
return $lock->resolve();
|
||||
}
|
||||
}
|
||||
],
|
||||
];
|
132
kirby/config/api/routes/pages.php
Normal file
132
kirby/config/api/routes/pages.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Page Routes
|
||||
*/
|
||||
return [
|
||||
|
||||
[
|
||||
'pattern' => 'pages/(:any)',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id)->update($this->requestBody(), $this->language(), true);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)',
|
||||
'method' => 'DELETE',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id)->delete($this->requestBody('force', false));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/blueprint',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id)->blueprint();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'pages/(:any)/blueprints',
|
||||
/**
|
||||
* @deprecated
|
||||
* @todo remove in 3.7.0
|
||||
*/
|
||||
'pages/(:any)/children/blueprints',
|
||||
],
|
||||
'method' => 'GET',
|
||||
'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'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/children',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $id) {
|
||||
return $this->pages($id, $this->requestQuery('status'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/children',
|
||||
'method' => 'POST',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id)->createChild($this->requestBody());
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/children/search',
|
||||
'method' => 'GET|POST',
|
||||
'action' => function (string $id) {
|
||||
return $this->searchPages($id);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/duplicate',
|
||||
'method' => 'POST',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id)->duplicate($this->requestBody('slug'), [
|
||||
'children' => $this->requestBody('children'),
|
||||
'files' => $this->requestBody('files'),
|
||||
]);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/slug',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id)->changeSlug($this->requestBody('slug'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/status',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id)->changeStatus($this->requestBody('status'), $this->requestBody('position'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/template',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id)->changeTemplate($this->requestBody('template'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/title',
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->page($id)->changeTitle($this->requestBody('title'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/sections/(:any)',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $id, string $sectionName) {
|
||||
if ($section = $this->page($id)->blueprint()->section($sectionName)) {
|
||||
return $section->toResponse();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'pages/(:any)/fields/(:any)/(:all?)',
|
||||
'method' => 'ALL',
|
||||
'action' => function (string $id, string $fieldName, string $path = null) {
|
||||
if ($page = $this->page($id)) {
|
||||
return $this->fieldApi($page, $fieldName, $path);
|
||||
}
|
||||
}
|
||||
],
|
||||
];
|
28
kirby/config/api/routes/roles.php
Normal file
28
kirby/config/api/routes/roles.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Roles Routes
|
||||
*/
|
||||
return [
|
||||
[
|
||||
'pattern' => 'roles',
|
||||
'method' => 'GET',
|
||||
'action' => function () {
|
||||
switch (get('canBe')) {
|
||||
case 'changed':
|
||||
return $this->kirby()->roles()->canBeChanged();
|
||||
case 'created':
|
||||
return $this->kirby()->roles()->canBeCreated();
|
||||
default:
|
||||
return $this->kirby()->roles();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'roles/(:any)',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $name) {
|
||||
return $this->kirby()->roles()->find($name);
|
||||
}
|
||||
]
|
||||
];
|
115
kirby/config/api/routes/site.php
Normal file
115
kirby/config/api/routes/site.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Site Routes
|
||||
*/
|
||||
return [
|
||||
|
||||
[
|
||||
'pattern' => 'site',
|
||||
'action' => function () {
|
||||
return $this->site();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site',
|
||||
'method' => 'PATCH',
|
||||
'action' => function () {
|
||||
return $this->site()->update($this->requestBody(), $this->language(), true);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site/children',
|
||||
'method' => 'GET',
|
||||
'action' => function () {
|
||||
return $this->pages(null, $this->requestQuery('status'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site/children',
|
||||
'method' => 'POST',
|
||||
'action' => function () {
|
||||
return $this->site()->createChild($this->requestBody());
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site/children/search',
|
||||
'method' => 'GET|POST',
|
||||
'action' => function () {
|
||||
return $this->searchPages();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site/blueprint',
|
||||
'method' => 'GET',
|
||||
'action' => function () {
|
||||
return $this->site()->blueprint();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'site/blueprints',
|
||||
/**
|
||||
* @deprecated
|
||||
* @todo remove in 3.7.0
|
||||
*/
|
||||
'site/children/blueprints',
|
||||
],
|
||||
'method' => 'GET',
|
||||
'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'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site/find',
|
||||
'method' => 'POST',
|
||||
'action' => function () {
|
||||
return $this->site()->find(false, ...$this->requestBody());
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site/title',
|
||||
'method' => 'PATCH',
|
||||
'action' => function () {
|
||||
return $this->site()->changeTitle($this->requestBody('title'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site/search',
|
||||
'method' => 'GET|POST',
|
||||
'action' => function () {
|
||||
$pages = $this
|
||||
->site()
|
||||
->index(true)
|
||||
->filter('isReadable', true);
|
||||
|
||||
if ($this->requestMethod() === 'GET') {
|
||||
return $pages->search($this->requestQuery('q'));
|
||||
} else {
|
||||
return $pages->query($this->requestBody());
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site/sections/(:any)',
|
||||
'method' => 'GET',
|
||||
'action' => function (string $sectionName) {
|
||||
if ($section = $this->site()->blueprint()->section($sectionName)) {
|
||||
return $section->toResponse();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'site/fields/(:any)/(:all?)',
|
||||
'method' => 'ALL',
|
||||
'action' => function (string $fieldName, string $path = null) {
|
||||
return $this->fieldApi($this->site(), $fieldName, $path);
|
||||
}
|
||||
]
|
||||
|
||||
];
|
79
kirby/config/api/routes/system.php
Normal file
79
kirby/config/api/routes/system.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* System Routes
|
||||
*/
|
||||
return [
|
||||
|
||||
[
|
||||
'pattern' => 'system',
|
||||
'method' => 'GET',
|
||||
'auth' => false,
|
||||
'action' => function () {
|
||||
$system = $this->kirby()->system();
|
||||
|
||||
if ($this->kirby()->user()) {
|
||||
return $system;
|
||||
} else {
|
||||
if ($system->isOk() === true) {
|
||||
$info = $this->resolve($system)->view('login')->toArray();
|
||||
} else {
|
||||
$info = $this->resolve($system)->view('troubleshooting')->toArray();
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'ok',
|
||||
'data' => $info,
|
||||
'type' => 'model'
|
||||
];
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'system/register',
|
||||
'method' => 'POST',
|
||||
'action' => function () {
|
||||
return $this->kirby()->system()->register($this->requestBody('license'), $this->requestBody('email'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'system/install',
|
||||
'method' => 'POST',
|
||||
'auth' => false,
|
||||
'action' => function () {
|
||||
$system = $this->kirby()->system();
|
||||
$auth = $this->kirby()->auth();
|
||||
|
||||
// csrf token check
|
||||
if ($auth->type() === 'session' && $auth->csrf() === false) {
|
||||
throw new InvalidArgumentException('Invalid CSRF token');
|
||||
}
|
||||
|
||||
if ($system->isOk() === false) {
|
||||
throw new Exception('The server is not setup correctly');
|
||||
}
|
||||
|
||||
if ($system->isInstallable() === false) {
|
||||
throw new Exception('The Panel cannot be installed');
|
||||
}
|
||||
|
||||
if ($system->isInstalled() === true) {
|
||||
throw new Exception('The Panel is already installed');
|
||||
}
|
||||
|
||||
// create the first user
|
||||
$user = $this->users()->create($this->requestBody());
|
||||
$token = $user->login($this->requestBody('password'));
|
||||
|
||||
return [
|
||||
'status' => 'ok',
|
||||
'token' => $token,
|
||||
'user' => $this->resolve($user)->view('auth')->toArray()
|
||||
];
|
||||
}
|
||||
]
|
||||
|
||||
];
|
24
kirby/config/api/routes/translations.php
Normal file
24
kirby/config/api/routes/translations.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Translations Routes
|
||||
*/
|
||||
return [
|
||||
[
|
||||
'pattern' => 'translations',
|
||||
'method' => 'GET',
|
||||
'auth' => false,
|
||||
'action' => function () {
|
||||
return $this->kirby()->translations();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'translations/(:any)',
|
||||
'method' => 'GET',
|
||||
'auth' => false,
|
||||
'action' => function (string $code) {
|
||||
return $this->kirby()->translations()->find($code);
|
||||
}
|
||||
]
|
||||
|
||||
];
|
207
kirby/config/api/routes/users.php
Normal file
207
kirby/config/api/routes/users.php
Normal file
|
@ -0,0 +1,207 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Filesystem\F;
|
||||
|
||||
/**
|
||||
* User Routes
|
||||
*/
|
||||
return [
|
||||
[
|
||||
'pattern' => 'users',
|
||||
'method' => 'GET',
|
||||
'action' => function () {
|
||||
return $this->users()->sort('username', 'asc', 'email', 'asc');
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'users',
|
||||
'method' => 'POST',
|
||||
'action' => function () {
|
||||
return $this->users()->create($this->requestBody());
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'users/search',
|
||||
'method' => 'GET|POST',
|
||||
'action' => function () {
|
||||
if ($this->requestMethod() === 'GET') {
|
||||
return $this->users()->search($this->requestQuery('q'));
|
||||
} else {
|
||||
return $this->users()->query($this->requestBody());
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)',
|
||||
'users/(:any)',
|
||||
],
|
||||
'method' => 'GET',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)',
|
||||
'users/(:any)',
|
||||
],
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->update($this->requestBody(), $this->language(), true);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)',
|
||||
'users/(:any)',
|
||||
],
|
||||
'method' => 'DELETE',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->delete();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/avatar',
|
||||
'users/(:any)/avatar',
|
||||
],
|
||||
'method' => 'GET',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->avatar();
|
||||
}
|
||||
],
|
||||
// @codeCoverageIgnoreStart
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/avatar',
|
||||
'users/(:any)/avatar',
|
||||
],
|
||||
'method' => 'POST',
|
||||
'action' => function (string $id) {
|
||||
if ($avatar = $this->user($id)->avatar()) {
|
||||
$avatar->delete();
|
||||
}
|
||||
|
||||
return $this->upload(function ($source, $filename) use ($id) {
|
||||
return $this->user($id)->createFile([
|
||||
'filename' => 'profile.' . F::extension($filename),
|
||||
'template' => 'avatar',
|
||||
'source' => $source
|
||||
]);
|
||||
}, $single = true);
|
||||
}
|
||||
],
|
||||
// @codeCoverageIgnoreEnd
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/avatar',
|
||||
'users/(:any)/avatar',
|
||||
],
|
||||
'method' => 'DELETE',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->avatar()->delete();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/blueprint',
|
||||
'users/(:any)/blueprint',
|
||||
],
|
||||
'method' => 'GET',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->blueprint();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/blueprints',
|
||||
'users/(:any)/blueprints',
|
||||
],
|
||||
'method' => 'GET',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->blueprints($this->requestQuery('section'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/email',
|
||||
'users/(:any)/email',
|
||||
],
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->changeEmail($this->requestBody('email'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/language',
|
||||
'users/(:any)/language',
|
||||
],
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->changeLanguage($this->requestBody('language'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/name',
|
||||
'users/(:any)/name',
|
||||
],
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->changeName($this->requestBody('name'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/password',
|
||||
'users/(:any)/password',
|
||||
],
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->changePassword($this->requestBody('password'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/role',
|
||||
'users/(:any)/role',
|
||||
],
|
||||
'method' => 'PATCH',
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->changeRole($this->requestBody('role'));
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/roles',
|
||||
'users/(:any)/roles',
|
||||
],
|
||||
'action' => function (string $id) {
|
||||
return $this->user($id)->roles();
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => [
|
||||
'(account)/sections/(:any)',
|
||||
'users/(:any)/sections/(:any)',
|
||||
],
|
||||
'method' => 'GET',
|
||||
'action' => function (string $id, string $sectionName) {
|
||||
if ($section = $this->user($id)->blueprint()->section($sectionName)) {
|
||||
return $section->toResponse();
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'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);
|
||||
}
|
||||
],
|
||||
];
|
12
kirby/config/areas/account.php
Normal file
12
kirby/config/areas/account.php
Normal 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'
|
||||
];
|
||||
};
|
70
kirby/config/areas/account/dialogs.php
Normal file
70
kirby/config/areas/account/dialogs.php
Normal 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'],
|
||||
],
|
||||
|
||||
];
|
14
kirby/config/areas/account/dropdowns.php
Normal file
14
kirby/config/areas/account/dropdowns.php
Normal 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']
|
||||
],
|
||||
];
|
34
kirby/config/areas/account/views.php
Normal file
34
kirby/config/areas/account/views.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Find;
|
||||
use Kirby\Panel\Panel;
|
||||
|
||||
return [
|
||||
'account' => [
|
||||
'pattern' => 'account',
|
||||
'action' => fn () => [
|
||||
'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' => fn () => ['component' => 'k-reset-password-view']
|
||||
]
|
||||
];
|
131
kirby/config/areas/files/dialogs.php
Normal file
131
kirby/config/areas/files/dialogs.php
Normal 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
|
||||
];
|
||||
}
|
||||
],
|
||||
];
|
9
kirby/config/areas/files/dropdowns.php
Normal file
9
kirby/config/areas/files/dropdowns.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Find;
|
||||
|
||||
return [
|
||||
'file' => function (string $parent, string $filename) {
|
||||
return Find::file($parent, $filename)->panel()->dropdown();
|
||||
}
|
||||
];
|
39
kirby/config/areas/installation.php
Normal file
39
kirby/config/areas/installation.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?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' => fn () => Panel::go('installation')
|
||||
]
|
||||
]
|
||||
];
|
||||
};
|
11
kirby/config/areas/languages.php
Normal file
11
kirby/config/areas/languages.php
Normal 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'
|
||||
];
|
||||
};
|
149
kirby/config/areas/languages/dialogs.php
Normal file
149
kirby/config/areas/languages/dialogs.php
Normal 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'
|
||||
];
|
||||
}
|
||||
],
|
||||
];
|
24
kirby/config/areas/languages/views.php
Normal file
24
kirby/config/areas/languages/views.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Toolkit\Escape;
|
||||
|
||||
return [
|
||||
'languages' => [
|
||||
'pattern' => 'languages',
|
||||
'action' => function () {
|
||||
$kirby = kirby();
|
||||
|
||||
return [
|
||||
'component' => 'k-languages-view',
|
||||
'props' => [
|
||||
'languages' => $kirby->languages()->values(fn ($language) => [
|
||||
'default' => $language->isDefault(),
|
||||
'id' => $language->code(),
|
||||
'info' => Escape::html($language->code()),
|
||||
'text' => Escape::html($language->name()),
|
||||
])
|
||||
]
|
||||
];
|
||||
}
|
||||
],
|
||||
];
|
43
kirby/config/areas/login.php
Normal file
43
kirby/config/areas/login.php
Normal 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');
|
||||
}
|
||||
]
|
||||
]
|
||||
];
|
||||
};
|
17
kirby/config/areas/site.php
Normal file
17
kirby/config/areas/site.php
Normal 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',
|
||||
];
|
||||
};
|
551
kirby/config/areas/site/dialogs.php
Normal file
551
kirby/config/areas/site/dialogs.php
Normal file
|
@ -0,0 +1,551 @@
|
|||
<?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'],
|
||||
],
|
||||
|
||||
];
|
26
kirby/config/areas/site/dropdowns.php
Normal file
26
kirby/config/areas/site/dropdowns.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Panel\Dropdown;
|
||||
|
||||
$files = require __DIR__ . '/../files/dropdowns.php';
|
||||
|
||||
return [
|
||||
'changes' => [
|
||||
'pattern' => 'changes',
|
||||
'options' => fn () => 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']
|
||||
]
|
||||
];
|
55
kirby/config/areas/site/searches.php
Normal file
55
kirby/config/areas/site/searches.php
Normal 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;
|
||||
}
|
||||
]
|
||||
];
|
26
kirby/config/areas/site/views.php
Normal file
26
kirby/config/areas/site/views.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Find;
|
||||
|
||||
return [
|
||||
'page' => [
|
||||
'pattern' => 'pages/(:any)',
|
||||
'action' => fn (string $path) => 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' => fn () => site()->panel()->view()
|
||||
],
|
||||
'site.file' => [
|
||||
'pattern' => 'site/files/(:any)',
|
||||
'action' => function (string $filename) {
|
||||
return Find::file('site', $filename)->panel()->view();
|
||||
}
|
||||
],
|
||||
];
|
11
kirby/config/areas/system.php
Normal file
11
kirby/config/areas/system.php
Normal 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'
|
||||
];
|
||||
};
|
43
kirby/config/areas/system/dialogs.php
Normal file
43
kirby/config/areas/system/dialogs.php
Normal 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
|
||||
}
|
||||
],
|
||||
];
|
47
kirby/config/areas/system/views.php
Normal file
47
kirby/config/areas/system/views.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Http\Server;
|
||||
|
||||
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(),
|
||||
'https' => Server::https(),
|
||||
'version' => $kirby->version(),
|
||||
]
|
||||
];
|
||||
}
|
||||
],
|
||||
];
|
14
kirby/config/areas/users.php
Normal file
14
kirby/config/areas/users.php
Normal 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'
|
||||
];
|
||||
};
|
295
kirby/config/areas/users/dialogs.php
Normal file
295
kirby/config/areas/users/dialogs.php
Normal 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(),
|
||||
'translation' => Field::translation([
|
||||
'required' => true
|
||||
]),
|
||||
'role' => Field::role([
|
||||
'required' => true
|
||||
])
|
||||
],
|
||||
'submitButton' => t('create'),
|
||||
'value' => [
|
||||
'name' => '',
|
||||
'email' => '',
|
||||
'password' => '',
|
||||
'translation' => $kirby->panelLanguage(),
|
||||
'role' => $kirby->user()->role()->name()
|
||||
]
|
||||
]
|
||||
];
|
||||
},
|
||||
'submit' => function () {
|
||||
kirby()->users()->create([
|
||||
'name' => get('name'),
|
||||
'email' => get('email'),
|
||||
'password' => get('password'),
|
||||
'language' => get('translation'),
|
||||
'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'],
|
||||
]
|
||||
|
||||
];
|
18
kirby/config/areas/users/dropdowns.php
Normal file
18
kirby/config/areas/users/dropdowns.php
Normal 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']
|
||||
]
|
||||
];
|
25
kirby/config/areas/users/searches.php
Normal file
25
kirby/config/areas/users/searches.php
Normal 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;
|
||||
}
|
||||
]
|
||||
];
|
65
kirby/config/areas/users/views.php
Normal file
65
kirby/config/areas/users/views.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Find;
|
||||
use Kirby\Toolkit\Escape;
|
||||
|
||||
return [
|
||||
'users' => [
|
||||
'pattern' => 'users',
|
||||
'action' => function () {
|
||||
$kirby = kirby();
|
||||
$role = get('role');
|
||||
$roles = $kirby->roles()->toArray(fn ($role) => [
|
||||
'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(fn ($user) => [
|
||||
'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();
|
||||
}
|
||||
],
|
||||
];
|
2
kirby/config/blocks/code/code.php
Normal file
2
kirby/config/blocks/code/code.php
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?php /** @var \Kirby\Cms\Block $block */ ?>
|
||||
<pre><code class="language-<?= $block->language()->or('text') ?>"><?= $block->code()->html(false) ?></code></pre>
|
59
kirby/config/blocks/code/code.yml
Normal file
59
kirby/config/blocks/code/code.yml
Normal file
|
@ -0,0 +1,59 @@
|
|||
name: field.blocks.code.name
|
||||
icon: code
|
||||
wysiwyg: true
|
||||
preview: code
|
||||
fields:
|
||||
code:
|
||||
label: field.blocks.code.name
|
||||
type: textarea
|
||||
placeholder: field.blocks.code.placeholder
|
||||
buttons: false
|
||||
font: monospace
|
||||
language:
|
||||
label: field.blocks.code.language
|
||||
type: select
|
||||
default: text
|
||||
options:
|
||||
bash: Bash
|
||||
basic: BASIC
|
||||
c: C
|
||||
clojure: Clojure
|
||||
cpp: C++
|
||||
csharp: C#
|
||||
css: CSS
|
||||
diff: Diff
|
||||
elixir: Elixir
|
||||
elm: Elm
|
||||
erlang: Erlang
|
||||
go: Go
|
||||
graphql: GraphQL
|
||||
haskell: Haskell
|
||||
html: HTML
|
||||
java: Java
|
||||
js: JavaScript
|
||||
json: JSON
|
||||
latext: LaTeX
|
||||
less: Less
|
||||
lisp: Lisp
|
||||
lua: Lua
|
||||
makefile: Makefile
|
||||
markdown: Markdown
|
||||
markup: Markup
|
||||
objectivec: Objective-C
|
||||
pascal: Pascal
|
||||
perl: Perl
|
||||
php: PHP
|
||||
text: Plain Text
|
||||
python: Python
|
||||
r: R
|
||||
ruby: Ruby
|
||||
rust: Rust
|
||||
sass: Sass
|
||||
scss: SCSS
|
||||
shell: Shell
|
||||
sql: SQL
|
||||
swift: Swift
|
||||
typescript: TypeScript
|
||||
vbnet: VB.net
|
||||
xml: XML
|
||||
yaml: YAML
|
10
kirby/config/blocks/gallery/gallery.php
Normal file
10
kirby/config/blocks/gallery/gallery.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php /** @var \Kirby\Cms\Block $block */ ?>
|
||||
<figure>
|
||||
<ul>
|
||||
<?php foreach ($block->images()->toFiles() as $image): ?>
|
||||
<li>
|
||||
<?= $image ?>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</figure>
|
15
kirby/config/blocks/gallery/gallery.yml
Normal file
15
kirby/config/blocks/gallery/gallery.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
name: field.blocks.gallery.name
|
||||
icon: dashboard
|
||||
preview: gallery
|
||||
fields:
|
||||
images:
|
||||
label: field.blocks.gallery.images.label
|
||||
type: files
|
||||
multiple: true
|
||||
layout: cards
|
||||
size: tiny
|
||||
empty: field.blocks.gallery.images.empty
|
||||
uploads:
|
||||
template: blocks/image
|
||||
image:
|
||||
ratio: 1/1
|
2
kirby/config/blocks/heading/heading.php
Normal file
2
kirby/config/blocks/heading/heading.php
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?php /** @var \Kirby\Cms\Block $block */ ?>
|
||||
<<?= $level = $block->level()->or('h2') ?>><?= $block->text() ?></<?= $level ?>>
|
24
kirby/config/blocks/heading/heading.yml
Normal file
24
kirby/config/blocks/heading/heading.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
name: field.blocks.heading.name
|
||||
icon: title
|
||||
wysiwyg: true
|
||||
preview: heading
|
||||
fields:
|
||||
level:
|
||||
label: field.blocks.heading.level
|
||||
type: select
|
||||
empty: false
|
||||
default: "h2"
|
||||
width: 1/6
|
||||
options:
|
||||
- h1
|
||||
- h2
|
||||
- h3
|
||||
- h4
|
||||
- h5
|
||||
- h6
|
||||
text:
|
||||
label: field.blocks.heading.text
|
||||
type: writer
|
||||
inline: true
|
||||
width: 5/6
|
||||
placeholder: field.blocks.heading.placeholder
|
35
kirby/config/blocks/image/image.php
Normal file
35
kirby/config/blocks/image/image.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/** @var \Kirby\Cms\Block $block */
|
||||
$alt = $block->alt();
|
||||
$caption = $block->caption();
|
||||
$crop = $block->crop()->isTrue();
|
||||
$link = $block->link();
|
||||
$ratio = $block->ratio()->or('auto');
|
||||
$src = null;
|
||||
|
||||
if ($block->location() == 'web') {
|
||||
$src = $block->src()->esc();
|
||||
} elseif ($image = $block->image()->toFile()) {
|
||||
$alt = $alt ?? $image->alt();
|
||||
$src = $image->url();
|
||||
}
|
||||
|
||||
?>
|
||||
<?php if ($src): ?>
|
||||
<figure<?= attr(['data-ratio' => $ratio, 'data-crop' => $crop], ' ') ?>>
|
||||
<?php if ($link->isNotEmpty()): ?>
|
||||
<a href="<?= esc($link->toUrl()) ?>">
|
||||
<img src="<?= $src ?>" alt="<?= $alt->esc() ?>">
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<img src="<?= $src ?>" alt="<?= $alt->esc() ?>">
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($caption->isNotEmpty()): ?>
|
||||
<figcaption>
|
||||
<?= $caption ?>
|
||||
</figcaption>
|
||||
<?php endif ?>
|
||||
</figure>
|
||||
<?php endif ?>
|
59
kirby/config/blocks/image/image.yml
Normal file
59
kirby/config/blocks/image/image.yml
Normal file
|
@ -0,0 +1,59 @@
|
|||
name: field.blocks.image.name
|
||||
icon: image
|
||||
preview: image
|
||||
fields:
|
||||
location:
|
||||
label: field.blocks.image.location
|
||||
type: radio
|
||||
columns: 2
|
||||
default: "kirby"
|
||||
options:
|
||||
kirby: Kirby
|
||||
web: Web
|
||||
image:
|
||||
label: field.blocks.image.name
|
||||
type: files
|
||||
multiple: false
|
||||
image:
|
||||
back: black
|
||||
uploads:
|
||||
template: blocks/image
|
||||
when:
|
||||
location: kirby
|
||||
src:
|
||||
label: field.blocks.image.url
|
||||
type: url
|
||||
when:
|
||||
location: web
|
||||
alt:
|
||||
label: field.blocks.image.alt
|
||||
type: text
|
||||
icon: title
|
||||
caption:
|
||||
label: field.blocks.image.caption
|
||||
type: writer
|
||||
icon: text
|
||||
inline: true
|
||||
link:
|
||||
label: field.blocks.image.link
|
||||
type: text
|
||||
icon: url
|
||||
ratio:
|
||||
label: field.blocks.image.ratio
|
||||
type: select
|
||||
placeholder: Auto
|
||||
width: 1/2
|
||||
options:
|
||||
1/1: "1:1"
|
||||
16/9: "16:9"
|
||||
10/8: "10:8"
|
||||
21/9: "21:9"
|
||||
7/5: "7:5"
|
||||
4/3: "4:3"
|
||||
5/3: "5:3"
|
||||
3/2: "3:2"
|
||||
3/1: "3:1"
|
||||
crop:
|
||||
label: field.blocks.image.crop
|
||||
type: toggle
|
||||
width: 1/2
|
1
kirby/config/blocks/line/line.php
Normal file
1
kirby/config/blocks/line/line.php
Normal file
|
@ -0,0 +1 @@
|
|||
<hr />
|
4
kirby/config/blocks/line/line.yml
Normal file
4
kirby/config/blocks/line/line.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
name: field.blocks.line.name
|
||||
icon: divider
|
||||
preview: line
|
||||
wysiwyg: true
|
2
kirby/config/blocks/list/list.php
Normal file
2
kirby/config/blocks/list/list.php
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?php /** @var \Kirby\Cms\Block $block */ ?>
|
||||
<?= $block->text();
|
8
kirby/config/blocks/list/list.yml
Normal file
8
kirby/config/blocks/list/list.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
name: field.blocks.list.name
|
||||
icon: list-bullet
|
||||
wysiwyg: true
|
||||
preview: list
|
||||
fields:
|
||||
text:
|
||||
label: field.blocks.list.name
|
||||
type: list
|
2
kirby/config/blocks/markdown/markdown.php
Normal file
2
kirby/config/blocks/markdown/markdown.php
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?php /** @var \Kirby\Cms\Block $block */ ?>
|
||||
<?= $block->text()->kt();
|
11
kirby/config/blocks/markdown/markdown.yml
Normal file
11
kirby/config/blocks/markdown/markdown.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
name: field.blocks.markdown.name
|
||||
icon: markdown
|
||||
preview: markdown
|
||||
wysiwyg: true
|
||||
fields:
|
||||
text:
|
||||
label: field.blocks.markdown.label
|
||||
placeholder: field.blocks.markdown.placeholder
|
||||
type: textarea
|
||||
buttons: false
|
||||
font: monospace
|
9
kirby/config/blocks/quote/quote.php
Normal file
9
kirby/config/blocks/quote/quote.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php /** @var \Kirby\Cms\Block $block */ ?>
|
||||
<blockquote>
|
||||
<?= $block->text() ?>
|
||||
<?php if ($block->citation()->isNotEmpty()): ?>
|
||||
<footer>
|
||||
<?= $block->citation() ?>
|
||||
</footer>
|
||||
<?php endif ?>
|
||||
</blockquote>
|
17
kirby/config/blocks/quote/quote.yml
Normal file
17
kirby/config/blocks/quote/quote.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
name: field.blocks.quote.name
|
||||
icon: quote
|
||||
wysiwyg: true
|
||||
preview: quote
|
||||
fields:
|
||||
text:
|
||||
label: field.blocks.quote.text.label
|
||||
placeholder: field.blocks.quote.text.placeholder
|
||||
type: writer
|
||||
inline: true
|
||||
icon: quote
|
||||
citation:
|
||||
label: field.blocks.quote.citation.label
|
||||
placeholder: field.blocks.quote.citation.placeholder
|
||||
type: writer
|
||||
inline: true
|
||||
icon: user
|
3
kirby/config/blocks/table/table.yml
Normal file
3
kirby/config/blocks/table/table.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
name: Table
|
||||
icon: menu
|
||||
preview: table
|
2
kirby/config/blocks/text/text.php
Normal file
2
kirby/config/blocks/text/text.php
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?php /** @var \Kirby\Cms\Block $block */ ?>
|
||||
<?= $block->text();
|
9
kirby/config/blocks/text/text.yml
Normal file
9
kirby/config/blocks/text/text.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
name: field.blocks.text.name
|
||||
icon: text
|
||||
wysiwyg: true
|
||||
preview: text
|
||||
fields:
|
||||
text:
|
||||
type: writer
|
||||
nodes: false
|
||||
placeholder: field.blocks.text.placeholder
|
9
kirby/config/blocks/video/video.php
Normal file
9
kirby/config/blocks/video/video.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php /** @var \Kirby\Cms\Block $block */ ?>
|
||||
<?php if ($video = video($block->url())): ?>
|
||||
<figure>
|
||||
<?= $video ?>
|
||||
<?php if ($block->caption()->isNotEmpty()): ?>
|
||||
<figcaption><?= $block->caption() ?></figcaption>
|
||||
<?php endif ?>
|
||||
</figure>
|
||||
<?php endif ?>
|
12
kirby/config/blocks/video/video.yml
Normal file
12
kirby/config/blocks/video/video.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
name: field.blocks.video.name
|
||||
icon: video
|
||||
preview: video
|
||||
fields:
|
||||
url:
|
||||
label: field.blocks.video.url.label
|
||||
type: url
|
||||
placeholder: field.blocks.video.url.placeholder
|
||||
caption:
|
||||
label: field.blocks.video.caption
|
||||
type: writer
|
||||
inline: true
|
56
kirby/config/blueprints/blocks/code.yml
Normal file
56
kirby/config/blueprints/blocks/code.yml
Normal file
|
@ -0,0 +1,56 @@
|
|||
name: Code
|
||||
icon: code
|
||||
fields:
|
||||
code:
|
||||
label: Code
|
||||
type: textarea
|
||||
buttons: false
|
||||
font: monospace
|
||||
language:
|
||||
label: Language
|
||||
type: select
|
||||
default: text
|
||||
options:
|
||||
bash: Bash
|
||||
basic: BASIC
|
||||
c: C
|
||||
clojure: Clojure
|
||||
cpp: C++
|
||||
csharp: C#
|
||||
css: CSS
|
||||
diff: Diff
|
||||
elixir: Elixir
|
||||
elm: Elm
|
||||
erlang: Erlang
|
||||
go: Go
|
||||
graphql: GraphQL
|
||||
haskell: Haskell
|
||||
html: HTML
|
||||
java: Java
|
||||
js: JavaScript
|
||||
json: JSON
|
||||
latext: LaTeX
|
||||
less: Less
|
||||
lisp: Lisp
|
||||
lua: Lua
|
||||
makefile: Makefile
|
||||
markdown: Markdown
|
||||
markup: Markup
|
||||
objectivec: Objective-C
|
||||
pascal: Pascal
|
||||
perl: Perl
|
||||
php: PHP
|
||||
text: Plain Text
|
||||
python: Python
|
||||
r: R
|
||||
ruby: Ruby
|
||||
rust: Rust
|
||||
sass: Sass
|
||||
scss: SCSS
|
||||
shell: Shell
|
||||
sql: SQL
|
||||
swift: Swift
|
||||
typescript: TypeScript
|
||||
vbnet: VB.net
|
||||
xml: XML
|
||||
yaml: YAML
|
20
kirby/config/blueprints/blocks/heading.yml
Normal file
20
kirby/config/blueprints/blocks/heading.yml
Normal file
|
@ -0,0 +1,20 @@
|
|||
icon: title
|
||||
fields:
|
||||
text:
|
||||
type: text
|
||||
level:
|
||||
type: select
|
||||
width: 1/2
|
||||
empty: false
|
||||
default: "2"
|
||||
options:
|
||||
- value: "1"
|
||||
text: Heading 1
|
||||
- value: "2"
|
||||
text: Heading 2
|
||||
- value: "3"
|
||||
text: Heading 3
|
||||
id:
|
||||
type: text
|
||||
label: ID
|
||||
width: 1/2
|
16
kirby/config/blueprints/blocks/image.yml
Normal file
16
kirby/config/blueprints/blocks/image.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
name: Image
|
||||
icon: image
|
||||
fields:
|
||||
image:
|
||||
type: files
|
||||
multiple: false
|
||||
alt:
|
||||
type: text
|
||||
icon: title
|
||||
caption:
|
||||
type: writer
|
||||
inline: true
|
||||
icon: text
|
||||
link:
|
||||
type: text
|
||||
icon: url
|
12
kirby/config/blueprints/blocks/quote.yml
Normal file
12
kirby/config/blueprints/blocks/quote.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
name: Quote
|
||||
icon: quote
|
||||
fields:
|
||||
text:
|
||||
label: Quote Text
|
||||
type: writer
|
||||
inline: true
|
||||
citation:
|
||||
label: Citation
|
||||
type: writer
|
||||
inline: true
|
||||
placeholder: by …
|
25
kirby/config/blueprints/blocks/table.yml
Normal file
25
kirby/config/blueprints/blocks/table.yml
Normal file
|
@ -0,0 +1,25 @@
|
|||
name: Table
|
||||
icon: menu
|
||||
fields:
|
||||
rows:
|
||||
label: Menu
|
||||
type: structure
|
||||
columns:
|
||||
dish: true
|
||||
description: true
|
||||
price:
|
||||
before: €
|
||||
width: 1/4
|
||||
align: right
|
||||
fields:
|
||||
dish:
|
||||
label: Dish
|
||||
type: text
|
||||
description:
|
||||
label: Description
|
||||
type: text
|
||||
price:
|
||||
label: Price
|
||||
type: number
|
||||
before: €
|
||||
step: 0.01
|
5
kirby/config/blueprints/blocks/text.yml
Normal file
5
kirby/config/blueprints/blocks/text.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
name: Text
|
||||
icon: text
|
||||
fields:
|
||||
text:
|
||||
type: writer
|
8
kirby/config/blueprints/blocks/video.yml
Normal file
8
kirby/config/blueprints/blocks/video.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
name: Video
|
||||
icon: video
|
||||
label: "{{ url }}"
|
||||
fields:
|
||||
url:
|
||||
type: url
|
||||
caption:
|
||||
type: writer
|
2
kirby/config/blueprints/files/default.yml
Normal file
2
kirby/config/blueprints/files/default.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
name: File
|
||||
title: file
|
3
kirby/config/blueprints/pages/default.yml
Normal file
3
kirby/config/blueprints/pages/default.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
name: Page
|
||||
title: Page
|
||||
|
7
kirby/config/blueprints/site.yml
Normal file
7
kirby/config/blueprints/site.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
name: Site
|
||||
title: Site
|
||||
sections:
|
||||
pages:
|
||||
headline: Pages
|
||||
type: pages
|
||||
|
400
kirby/config/components.php
Normal file
400
kirby/config/components.php
Normal file
|
@ -0,0 +1,400 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\App;
|
||||
use Kirby\Cms\Collection;
|
||||
use Kirby\Cms\File;
|
||||
use Kirby\Cms\FileVersion;
|
||||
use Kirby\Cms\Template;
|
||||
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\Uri;
|
||||
use Kirby\Http\Url;
|
||||
use Kirby\Image\Darkroom;
|
||||
use Kirby\Text\Markdown;
|
||||
use Kirby\Text\SmartyPants;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Kirby\Toolkit\Tpl as Snippet;
|
||||
|
||||
return [
|
||||
|
||||
/**
|
||||
* Used by the `css()` helper
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param string $url Relative or absolute URL
|
||||
* @param string|array $options An array of attributes for the link tag or a media attribute string
|
||||
*/
|
||||
'css' => fn (App $kirby, string $url, $options = null): string => $url,
|
||||
|
||||
|
||||
/**
|
||||
* Object and variable dumper
|
||||
* to help with debugging.
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param mixed $variable
|
||||
* @param bool $echo
|
||||
* @return string
|
||||
*/
|
||||
'dump' => function (App $kirby, $variable, bool $echo = true) {
|
||||
if (Server::cli() === true) {
|
||||
$output = print_r($variable, true) . PHP_EOL;
|
||||
} else {
|
||||
$output = '<pre>' . print_r($variable, true) . '</pre>';
|
||||
}
|
||||
|
||||
if ($echo === true) {
|
||||
echo $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
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param \Kirby\Cms\File $file The original file object
|
||||
* @return string
|
||||
*/
|
||||
'file::url' => function (App $kirby, File $file): string {
|
||||
return $file->mediaUrl();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adapt file characteristics
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param \Kirby\Cms\File|\Kirby\Filesystem\Asset $file The file object
|
||||
* @param array $options All thumb options (width, height, crop, blur, grayscale)
|
||||
* @return \Kirby\Cms\File|\Kirby\Cms\FileVersion|\Kirby\Filesystem\Asset
|
||||
*/
|
||||
'file::version' => function (App $kirby, $file, array $options = []) {
|
||||
// if file is not resizable, return
|
||||
if ($file->isResizable() === false) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
// create url and root
|
||||
$mediaRoot = dirname($file->mediaRoot());
|
||||
$template = $mediaRoot . '/{{ name }}{{ attributes }}.{{ extension }}';
|
||||
$thumbRoot = (new Filename($file->root(), $template, $options))->toString();
|
||||
$thumbName = basename($thumbRoot);
|
||||
|
||||
// check if the thumb already exists
|
||||
if (file_exists($thumbRoot) === false) {
|
||||
|
||||
// if not, create job file
|
||||
$job = $mediaRoot . '/.jobs/' . $thumbName . '.json';
|
||||
|
||||
try {
|
||||
Data::write($job, array_merge($options, [
|
||||
'filename' => $file->filename()
|
||||
]));
|
||||
} catch (Throwable $e) {
|
||||
// if thumb doesn't exist yet and job file cannot
|
||||
// be created, return
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
return new FileVersion([
|
||||
'modifications' => $options,
|
||||
'original' => $file,
|
||||
'root' => $thumbRoot,
|
||||
'url' => dirname($file->mediaUrl()) . '/' . $thumbName,
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Used by the `js()` helper
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param string $url Relative or absolute URL
|
||||
* @param string|array $options An array of attributes for the link tag or a media attribute string
|
||||
*/
|
||||
'js' => fn (App $kirby, string $url, $options = null): string => $url,
|
||||
|
||||
/**
|
||||
* Add your own Markdown parser
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param string $text Text to parse
|
||||
* @param array $options Markdown options
|
||||
* @param bool $inline Whether to wrap the text in `<p>` tags (deprecated: set via $options['inline'] instead)
|
||||
* @return string
|
||||
* @todo add deprecation warning for $inline parameter in 3.7.0
|
||||
* @todo remove $inline parameter in in 3.8.0
|
||||
*/
|
||||
'markdown' => function (App $kirby, string $text = null, array $options = [], bool $inline = false): string {
|
||||
static $markdown;
|
||||
static $config;
|
||||
|
||||
// support for the deprecated fourth argument
|
||||
$options['inline'] ??= $inline;
|
||||
|
||||
// if the config options have changed or the component is called for the first time,
|
||||
// (re-)initialize the parser object
|
||||
if ($config !== $options) {
|
||||
$markdown = new Markdown($options);
|
||||
$config = $options;
|
||||
}
|
||||
|
||||
return $markdown->parse($text, $options['inline']);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add your own search engine
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param \Kirby\Cms\Collection $collection Collection of searchable models
|
||||
* @param string $query
|
||||
* @param mixed $params
|
||||
* @return \Kirby\Cms\Collection|bool
|
||||
*/
|
||||
'search' => function (App $kirby, Collection $collection, string $query = null, $params = []) {
|
||||
if (empty(trim($query)) === true) {
|
||||
return $collection->limit(0);
|
||||
}
|
||||
|
||||
if (is_string($params) === true) {
|
||||
$params = ['fields' => Str::split($params, '|')];
|
||||
}
|
||||
|
||||
$defaults = [
|
||||
'fields' => [],
|
||||
'minlength' => 2,
|
||||
'score' => [],
|
||||
'words' => false,
|
||||
];
|
||||
|
||||
$options = array_merge($defaults, $params);
|
||||
$collection = clone $collection;
|
||||
$searchWords = preg_replace('/(\s)/u', ',', $query);
|
||||
$searchWords = Str::split($searchWords, ',', $options['minlength']);
|
||||
$lowerQuery = Str::lower($query);
|
||||
$exactQuery = $options['words'] ? '(\b' . preg_quote($query) . '\b)' : preg_quote($query);
|
||||
|
||||
if (empty($options['stopwords']) === false) {
|
||||
$searchWords = array_diff($searchWords, $options['stopwords']);
|
||||
}
|
||||
|
||||
$searchWords = array_map(function ($value) use ($options) {
|
||||
return $options['words'] ? '\b' . preg_quote($value) . '\b' : preg_quote($value);
|
||||
}, $searchWords);
|
||||
|
||||
$preg = '!(' . implode('|', $searchWords) . ')!i';
|
||||
$results = $collection->filter(function ($item) use ($query, $preg, $options, $lowerQuery, $exactQuery) {
|
||||
$data = $item->content()->toArray();
|
||||
$keys = array_keys($data);
|
||||
$keys[] = 'id';
|
||||
|
||||
if (is_a($item, 'Kirby\Cms\User') === true) {
|
||||
$keys[] = 'name';
|
||||
$keys[] = 'email';
|
||||
$keys[] = 'role';
|
||||
} elseif (is_a($item, 'Kirby\Cms\Page') === true) {
|
||||
// apply the default score for pages
|
||||
$options['score'] = array_merge([
|
||||
'id' => 64,
|
||||
'title' => 64,
|
||||
], $options['score']);
|
||||
}
|
||||
|
||||
if (empty($options['fields']) === false) {
|
||||
$fields = array_map('strtolower', $options['fields']);
|
||||
$keys = array_intersect($keys, $fields);
|
||||
}
|
||||
|
||||
$item->searchHits = 0;
|
||||
$item->searchScore = 0;
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$score = $options['score'][$key] ?? 1;
|
||||
$value = $data[$key] ?? (string)$item->$key();
|
||||
|
||||
$lowerValue = Str::lower($value);
|
||||
|
||||
// check for exact matches
|
||||
if ($lowerQuery == $lowerValue) {
|
||||
$item->searchScore += 16 * $score;
|
||||
$item->searchHits += 1;
|
||||
|
||||
// check for exact beginning matches
|
||||
} elseif ($options['words'] === false && Str::startsWith($lowerValue, $lowerQuery) === true) {
|
||||
$item->searchScore += 8 * $score;
|
||||
$item->searchHits += 1;
|
||||
|
||||
// check for exact query matches
|
||||
} elseif ($matches = preg_match_all('!' . $exactQuery . '!i', $value, $r)) {
|
||||
$item->searchScore += 2 * $score;
|
||||
$item->searchHits += $matches;
|
||||
}
|
||||
|
||||
// check for any match
|
||||
if ($matches = preg_match_all($preg, $value, $r)) {
|
||||
$item->searchHits += $matches;
|
||||
$item->searchScore += $matches * $score;
|
||||
}
|
||||
}
|
||||
|
||||
return $item->searchHits > 0;
|
||||
});
|
||||
|
||||
return $results->sort('searchScore', 'desc');
|
||||
},
|
||||
|
||||
/**
|
||||
* Add your own SmartyPants parser
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param string $text Text to parse
|
||||
* @param array $options SmartyPants options
|
||||
* @return string
|
||||
*/
|
||||
'smartypants' => function (App $kirby, string $text = null, array $options = []): string {
|
||||
static $smartypants;
|
||||
static $config;
|
||||
|
||||
// if the config options have changed or the component is called for the first time,
|
||||
// (re-)initialize the parser object
|
||||
if ($config !== $options) {
|
||||
$smartypants = new Smartypants($options);
|
||||
$config = $options;
|
||||
}
|
||||
|
||||
return $smartypants->parse($text);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add your own snippet loader
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param string|array $name Snippet name
|
||||
* @param array $data Data array for the snippet
|
||||
* @return string|null
|
||||
*/
|
||||
'snippet' => function (App $kirby, $name, array $data = []): ?string {
|
||||
$snippets = A::wrap($name);
|
||||
|
||||
foreach ($snippets as $name) {
|
||||
$name = (string)$name;
|
||||
$file = $kirby->root('snippets') . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($file) === false) {
|
||||
$file = $kirby->extensions('snippets')[$name] ?? null;
|
||||
}
|
||||
|
||||
if ($file) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Snippet::load($file, $data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add your own template engine
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param string $name Template name
|
||||
* @param string $type Extension type
|
||||
* @param string $defaultType Default extension type
|
||||
* @return \Kirby\Cms\Template
|
||||
*/
|
||||
'template' => function (App $kirby, string $name, string $type = 'html', string $defaultType = 'html') {
|
||||
return new Template($name, $type, $defaultType);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add your own thumb generator
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param string $src Root of the original file
|
||||
* @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`
|
||||
* @return string
|
||||
*/
|
||||
'thumb' => function (App $kirby, string $src, string $dst, array $options): string {
|
||||
$darkroom = Darkroom::factory(
|
||||
option('thumbs.driver', 'gd'),
|
||||
option('thumbs', [])
|
||||
);
|
||||
$options = $darkroom->preprocess($src, $options);
|
||||
$root = (new Filename($src, $dst, $options))->toString();
|
||||
|
||||
F::copy($src, $root, true);
|
||||
$darkroom->process($root, $options);
|
||||
|
||||
return $root;
|
||||
},
|
||||
|
||||
/**
|
||||
* Modify all URLs
|
||||
*
|
||||
* @param \Kirby\Cms\App $kirby Kirby instance
|
||||
* @param string|null $path URL path
|
||||
* @param array|string|null $options Array of options for the Uri class
|
||||
* @return string
|
||||
*/
|
||||
'url' => function (App $kirby, string $path = null, $options = null): string {
|
||||
$language = null;
|
||||
|
||||
// get language from simple string option
|
||||
if (is_string($options) === true) {
|
||||
$language = $options;
|
||||
$options = null;
|
||||
}
|
||||
|
||||
// get language from array
|
||||
if (is_array($options) === true && isset($options['language']) === true) {
|
||||
$language = $options['language'];
|
||||
unset($options['language']);
|
||||
}
|
||||
|
||||
// get a language url for the linked page, if the page can be found
|
||||
if ($kirby->multilang() === true) {
|
||||
$parts = Str::split($path, '#');
|
||||
|
||||
if ($page = page($parts[0] ?? null)) {
|
||||
$path = $page->url($language);
|
||||
|
||||
if (isset($parts[1]) === true) {
|
||||
$path .= '#' . $parts[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// keep relative urls
|
||||
if (
|
||||
$path !== null &&
|
||||
(substr($path, 0, 2) === './' || substr($path, 0, 3) === '../')
|
||||
) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$url = Url::makeAbsolute($path, $kirby->url());
|
||||
|
||||
if ($options === null) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
return (new Uri($url, $options))->toString();
|
||||
},
|
||||
|
||||
];
|
61
kirby/config/fields/checkboxes.php
Normal file
61
kirby/config/fields/checkboxes.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
return [
|
||||
'mixins' => ['min', 'options'],
|
||||
'props' => [
|
||||
/**
|
||||
* Unset inherited props
|
||||
*/
|
||||
'after' => null,
|
||||
'before' => null,
|
||||
'icon' => null,
|
||||
'placeholder' => null,
|
||||
|
||||
/**
|
||||
* Arranges the checkboxes in the given number of columns
|
||||
*/
|
||||
'columns' => function (int $columns = 1) {
|
||||
return $columns;
|
||||
},
|
||||
/**
|
||||
* Default value for the field, which will be used when a page/file/user is created
|
||||
*/
|
||||
'default' => function ($default = null) {
|
||||
return Str::split($default, ',');
|
||||
},
|
||||
/**
|
||||
* Maximum number of checked boxes
|
||||
*/
|
||||
'max' => function (int $max = null) {
|
||||
return $max;
|
||||
},
|
||||
/**
|
||||
* Minimum number of checked boxes
|
||||
*/
|
||||
'min' => function (int $min = null) {
|
||||
return $min;
|
||||
},
|
||||
'value' => function ($value = null) {
|
||||
return Str::split($value, ',');
|
||||
},
|
||||
],
|
||||
'computed' => [
|
||||
'default' => function () {
|
||||
return $this->sanitizeOptions($this->default);
|
||||
},
|
||||
'value' => function () {
|
||||
return $this->sanitizeOptions($this->value);
|
||||
},
|
||||
],
|
||||
'save' => function ($value): string {
|
||||
return A::join($value, ', ');
|
||||
},
|
||||
'validations' => [
|
||||
'options',
|
||||
'max',
|
||||
'min'
|
||||
]
|
||||
];
|
154
kirby/config/fields/date.php
Normal file
154
kirby/config/fields/date.php
Normal file
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Exception\Exception;
|
||||
use Kirby\Form\Field;
|
||||
use Kirby\Toolkit\Date;
|
||||
use Kirby\Toolkit\I18n;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
return [
|
||||
'mixins' => ['datetime'],
|
||||
'props' => [
|
||||
/**
|
||||
* Unset inherited props
|
||||
*/
|
||||
'placeholder' => null,
|
||||
|
||||
/**
|
||||
* Activate/deactivate the dropdown calendar
|
||||
*/
|
||||
'calendar' => function (bool $calendar = true) {
|
||||
return $calendar;
|
||||
},
|
||||
|
||||
/**
|
||||
* Default date when a new page/file/user gets created
|
||||
*/
|
||||
'default' => function (string $default = null): string {
|
||||
return $this->toDatetime($default) ?? '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Custom format (dayjs tokens: `DD`, `MM`, `YYYY`) that is
|
||||
* used to display the field in the Panel
|
||||
*/
|
||||
'display' => function ($display = 'YYYY-MM-DD') {
|
||||
return I18n::translate($display, $display);
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the calendar icon to something custom
|
||||
*/
|
||||
'icon' => function (string $icon = 'calendar') {
|
||||
return $icon;
|
||||
},
|
||||
|
||||
/**
|
||||
* Latest date, which can be selected/saved (Y-m-d)
|
||||
*/
|
||||
'max' => function (string $max = null): ?string {
|
||||
return Date::optional($max);
|
||||
},
|
||||
/**
|
||||
* Earliest date, which can be selected/saved (Y-m-d)
|
||||
*/
|
||||
'min' => function (string $min = null): ?string {
|
||||
return Date::optional($min);
|
||||
},
|
||||
|
||||
/**
|
||||
* Round to the nearest: sub-options for `unit` (day) and `size` (1)
|
||||
*/
|
||||
'step' => function ($step = null) {
|
||||
return $step;
|
||||
},
|
||||
|
||||
/**
|
||||
* Pass `true` or an array of time field options to show the time selector.
|
||||
*/
|
||||
'time' => function ($time = false) {
|
||||
return $time;
|
||||
},
|
||||
/**
|
||||
* Must be a parseable date string
|
||||
*/
|
||||
'value' => function ($value = null) {
|
||||
return $value;
|
||||
}
|
||||
],
|
||||
'computed' => [
|
||||
'display' => function () {
|
||||
if ($this->display) {
|
||||
return Str::upper($this->display);
|
||||
}
|
||||
},
|
||||
'format' => function () {
|
||||
return $this->props['format'] ?? ($this->time === false ? 'Y-m-d' : 'Y-m-d H:i:s');
|
||||
},
|
||||
'time' => function () {
|
||||
if ($this->time === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$props = is_array($this->time) ? $this->time : [];
|
||||
$props['model'] = $this->model();
|
||||
$field = new Field('time', $props);
|
||||
return $field->toArray();
|
||||
},
|
||||
'step' => function () {
|
||||
if ($this->time === false || empty($this->time['step']) === true) {
|
||||
return Date::stepConfig($this->step, [
|
||||
'size' => 1,
|
||||
'unit' => 'day'
|
||||
]);
|
||||
}
|
||||
|
||||
return Date::stepConfig($this->time['step'], [
|
||||
'size' => 5,
|
||||
'unit' => 'minute'
|
||||
]);
|
||||
},
|
||||
'value' => function (): string {
|
||||
return $this->toDatetime($this->value) ?? '';
|
||||
},
|
||||
],
|
||||
'validations' => [
|
||||
'date',
|
||||
'minMax' => function ($value) {
|
||||
if (!$value = Date::optional($value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$min = Date::optional($this->min);
|
||||
$max = Date::optional($this->max);
|
||||
|
||||
$format = $this->time === false ? 'd.m.Y' : 'd.m.Y H:i';
|
||||
|
||||
if ($min && $max && $value->isBetween($min, $max) === false) {
|
||||
throw new Exception([
|
||||
'key' => 'validation.date.between',
|
||||
'data' => [
|
||||
'min' => $min->format($format),
|
||||
'max' => $min->format($format)
|
||||
]
|
||||
]);
|
||||
} elseif ($min && $value->isMin($min) === false) {
|
||||
throw new Exception([
|
||||
'key' => 'validation.date.after',
|
||||
'data' => [
|
||||
'date' => $min->format($format),
|
||||
]
|
||||
]);
|
||||
} elseif ($max && $value->isMax($max) === false) {
|
||||
throw new Exception([
|
||||
'key' => 'validation.date.before',
|
||||
'data' => [
|
||||
'date' => $max->format($format),
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
]
|
||||
];
|
40
kirby/config/fields/email.php
Normal file
40
kirby/config/fields/email.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Toolkit\I18n;
|
||||
|
||||
return [
|
||||
'extends' => 'text',
|
||||
'props' => [
|
||||
/**
|
||||
* Unset inherited props
|
||||
*/
|
||||
'converter' => null,
|
||||
'counter' => null,
|
||||
|
||||
/**
|
||||
* Sets the HTML5 autocomplete mode for the input
|
||||
*/
|
||||
'autocomplete' => function (string $autocomplete = 'email') {
|
||||
return $autocomplete;
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the email icon to something custom
|
||||
*/
|
||||
'icon' => function (string $icon = 'email') {
|
||||
return $icon;
|
||||
},
|
||||
|
||||
/**
|
||||
* Custom placeholder text, when the field is empty.
|
||||
*/
|
||||
'placeholder' => function ($value = null) {
|
||||
return I18n::translate($value, $value) ?? I18n::translate('email.placeholder');
|
||||
}
|
||||
],
|
||||
'validations' => [
|
||||
'minlength',
|
||||
'maxlength',
|
||||
'email'
|
||||
]
|
||||
];
|
131
kirby/config/fields/files.php
Normal file
131
kirby/config/fields/files.php
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Toolkit\A;
|
||||
|
||||
return [
|
||||
'mixins' => [
|
||||
'filepicker',
|
||||
'layout',
|
||||
'min',
|
||||
'picker',
|
||||
'upload'
|
||||
],
|
||||
'props' => [
|
||||
/**
|
||||
* Unset inherited props
|
||||
*/
|
||||
'after' => null,
|
||||
'before' => null,
|
||||
'autofocus' => null,
|
||||
'icon' => null,
|
||||
'placeholder' => null,
|
||||
|
||||
/**
|
||||
* Sets the file(s), which are selected by default when a new page is created
|
||||
*/
|
||||
'default' => function ($default = null) {
|
||||
return $default;
|
||||
},
|
||||
|
||||
'value' => function ($value = null) {
|
||||
return $value;
|
||||
}
|
||||
],
|
||||
'computed' => [
|
||||
'parentModel' => function () {
|
||||
if (is_string($this->parent) === true && $model = $this->model()->query($this->parent, 'Kirby\Cms\Model')) {
|
||||
return $model;
|
||||
}
|
||||
|
||||
return $this->model();
|
||||
},
|
||||
'parent' => function () {
|
||||
return $this->parentModel->apiUrl(true);
|
||||
},
|
||||
'query' => function () {
|
||||
return $this->query ?? $this->parentModel::CLASS_ALIAS . '.files';
|
||||
},
|
||||
'default' => function () {
|
||||
return $this->toFiles($this->default);
|
||||
},
|
||||
'value' => function () {
|
||||
return $this->toFiles($this->value);
|
||||
},
|
||||
],
|
||||
'methods' => [
|
||||
'fileResponse' => function ($file) {
|
||||
return $file->panel()->pickerData([
|
||||
'image' => $this->image,
|
||||
'info' => $this->info ?? false,
|
||||
'layout' => $this->layout,
|
||||
'model' => $this->model(),
|
||||
'text' => $this->text,
|
||||
]);
|
||||
},
|
||||
'toFiles' => function ($value = null) {
|
||||
$files = [];
|
||||
|
||||
foreach (Data::decode($value, 'yaml') as $id) {
|
||||
if (is_array($id) === true) {
|
||||
$id = $id['id'] ?? null;
|
||||
}
|
||||
|
||||
if ($id !== null && ($file = $this->kirby()->file($id, $this->model()))) {
|
||||
$files[] = $this->fileResponse($file);
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
],
|
||||
'api' => function () {
|
||||
return [
|
||||
[
|
||||
'pattern' => '/',
|
||||
'action' => function () {
|
||||
$field = $this->field();
|
||||
|
||||
return $field->filepicker([
|
||||
'image' => $field->image(),
|
||||
'info' => $field->info(),
|
||||
'layout' => $field->layout(),
|
||||
'limit' => $field->limit(),
|
||||
'page' => $this->requestQuery('page'),
|
||||
'query' => $field->query(),
|
||||
'search' => $this->requestQuery('search'),
|
||||
'text' => $field->text()
|
||||
]);
|
||||
}
|
||||
],
|
||||
[
|
||||
'pattern' => 'upload',
|
||||
'method' => 'POST',
|
||||
'action' => function () {
|
||||
$field = $this->field();
|
||||
$uploads = $field->uploads();
|
||||
|
||||
// move_uploaded_file() not working with unit test
|
||||
// @codeCoverageIgnoreStart
|
||||
return $field->upload($this, $uploads, function ($file, $parent) use ($field) {
|
||||
return $file->panel()->pickerData([
|
||||
'image' => $field->image(),
|
||||
'info' => $field->info(),
|
||||
'layout' => $field->layout(),
|
||||
'model' => $field->model(),
|
||||
'text' => $field->text(),
|
||||
]);
|
||||
});
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
]
|
||||
];
|
||||
},
|
||||
'save' => function ($value = null) {
|
||||
return A::pluck($value, 'uuid');
|
||||
},
|
||||
'validations' => [
|
||||
'max',
|
||||
'min'
|
||||
]
|
||||
];
|
5
kirby/config/fields/gap.php
Normal file
5
kirby/config/fields/gap.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'save' => false
|
||||
];
|
26
kirby/config/fields/headline.php
Normal file
26
kirby/config/fields/headline.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'save' => false,
|
||||
'props' => [
|
||||
/**
|
||||
* Unset inherited props
|
||||
*/
|
||||
'after' => null,
|
||||
'autofocus' => null,
|
||||
'before' => null,
|
||||
'default' => null,
|
||||
'disabled' => null,
|
||||
'icon' => null,
|
||||
'placeholder' => null,
|
||||
'required' => null,
|
||||
'translate' => null,
|
||||
|
||||
/**
|
||||
* If `false`, the prepended number will be hidden
|
||||
*/
|
||||
'numbered' => function (bool $numbered = true) {
|
||||
return $numbered;
|
||||
}
|
||||
]
|
||||
];
|
3
kirby/config/fields/hidden.php
Normal file
3
kirby/config/fields/hidden.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
return [];
|
44
kirby/config/fields/info.php
Normal file
44
kirby/config/fields/info.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Toolkit\I18n;
|
||||
|
||||
return [
|
||||
'props' => [
|
||||
/**
|
||||
* Unset inherited props
|
||||
*/
|
||||
'after' => null,
|
||||
'autofocus' => null,
|
||||
'before' => null,
|
||||
'default' => null,
|
||||
'disabled' => null,
|
||||
'icon' => null,
|
||||
'placeholder' => null,
|
||||
'required' => null,
|
||||
'translate' => null,
|
||||
|
||||
/**
|
||||
* Text to be displayed
|
||||
*/
|
||||
'text' => function ($value = null) {
|
||||
return I18n::translate($value, $value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Change the design of the info box
|
||||
*/
|
||||
'theme' => function (string $theme = null) {
|
||||
return $theme;
|
||||
}
|
||||
],
|
||||
'computed' => [
|
||||
'text' => function () {
|
||||
if ($text = $this->text) {
|
||||
$text = $this->model()->toSafeString($text);
|
||||
$text = $this->kirby()->kirbytext($text);
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
],
|
||||
'save' => false,
|
||||
];
|
5
kirby/config/fields/line.php
Normal file
5
kirby/config/fields/line.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'save' => false
|
||||
];
|
17
kirby/config/fields/list.php
Normal file
17
kirby/config/fields/list.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'props' => [
|
||||
/**
|
||||
* 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`
|
||||
*/
|
||||
'marks' => function ($marks = true) {
|
||||
return $marks;
|
||||
}
|
||||
],
|
||||
'computed' => [
|
||||
'value' => function () {
|
||||
return trim($this->value ?? '');
|
||||
}
|
||||
]
|
||||
];
|
35
kirby/config/fields/mixins/datetime.php
Normal file
35
kirby/config/fields/mixins/datetime.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Toolkit\Date;
|
||||
|
||||
return [
|
||||
'props' => [
|
||||
/**
|
||||
* Defines a custom format that is used when the field is saved
|
||||
*/
|
||||
'format' => function (string $format = null) {
|
||||
return $format;
|
||||
}
|
||||
],
|
||||
'methods' => [
|
||||
'toDatetime' => function ($value, string $format = 'Y-m-d H:i:s') {
|
||||
if ($date = Date::optional($value)) {
|
||||
if ($this->step) {
|
||||
$step = Date::stepConfig($this->step);
|
||||
$date->round($step['unit'], $step['size']);
|
||||
}
|
||||
|
||||
return $date->format($format);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
],
|
||||
'save' => function ($value) {
|
||||
if ($date = Date::optional($value)) {
|
||||
return $date->format($this->format);
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
];
|
14
kirby/config/fields/mixins/filepicker.php
Normal file
14
kirby/config/fields/mixins/filepicker.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\FilePicker;
|
||||
|
||||
return [
|
||||
'methods' => [
|
||||
'filepicker' => function (array $params = []) {
|
||||
// fetch the parent model
|
||||
$params['model'] = $this->model();
|
||||
|
||||
return (new FilePicker($params))->toArray();
|
||||
}
|
||||
]
|
||||
];
|
21
kirby/config/fields/mixins/layout.php
Normal file
21
kirby/config/fields/mixins/layout.php
Normal 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;
|
||||
},
|
||||
]
|
||||
];
|
22
kirby/config/fields/mixins/min.php
Normal file
22
kirby/config/fields/mixins/min.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'computed' => [
|
||||
'min' => function () {
|
||||
// set min to at least 1, if required
|
||||
if ($this->required === true) {
|
||||
return $this->min ?? 1;
|
||||
}
|
||||
|
||||
return $this->min;
|
||||
},
|
||||
'required' => function () {
|
||||
// set required to true if min is set
|
||||
if ($this->min) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->required;
|
||||
}
|
||||
]
|
||||
];
|
48
kirby/config/fields/mixins/options.php
Normal file
48
kirby/config/fields/mixins/options.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Form\Options;
|
||||
|
||||
return [
|
||||
'props' => [
|
||||
/**
|
||||
* API settings for options requests. This will only take affect when `options` is set to `api`.
|
||||
*/
|
||||
'api' => function ($api = null) {
|
||||
return $api;
|
||||
},
|
||||
/**
|
||||
* An array with options
|
||||
*/
|
||||
'options' => function ($options = []) {
|
||||
return $options;
|
||||
},
|
||||
/**
|
||||
* Query settings for options queries. This will only take affect when `options` is set to `query`.
|
||||
*/
|
||||
'query' => function ($query = null) {
|
||||
return $query;
|
||||
},
|
||||
],
|
||||
'computed' => [
|
||||
'options' => function (): array {
|
||||
return $this->getOptions();
|
||||
}
|
||||
],
|
||||
'methods' => [
|
||||
'getOptions' => function () {
|
||||
return Options::factory(
|
||||
$this->options(),
|
||||
$this->props,
|
||||
$this->model()
|
||||
);
|
||||
},
|
||||
'sanitizeOption' => function ($option) {
|
||||
$allowed = array_column($this->options(), 'value');
|
||||
return in_array($option, $allowed, true) === true ? $option : null;
|
||||
},
|
||||
'sanitizeOptions' => function ($options) {
|
||||
$allowed = array_column($this->options(), 'value');
|
||||
return array_intersect($options, $allowed);
|
||||
},
|
||||
]
|
||||
];
|
14
kirby/config/fields/mixins/pagepicker.php
Normal file
14
kirby/config/fields/mixins/pagepicker.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\PagePicker;
|
||||
|
||||
return [
|
||||
'methods' => [
|
||||
'pagepicker' => function (array $params = []) {
|
||||
// inject the current model
|
||||
$params['model'] = $this->model();
|
||||
|
||||
return (new PagePicker($params))->toArray();
|
||||
}
|
||||
]
|
||||
];
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue