Update Kirby and add password guard
This commit is contained in:
parent
aaf1aa7890
commit
55d4e45891
987 changed files with 160116 additions and 66454 deletions
|
|
@ -1,298 +1,288 @@
|
|||
<?php
|
||||
|
||||
use Kirby\Cms\Blueprint;
|
||||
use Kirby\Cms\Page;
|
||||
use Kirby\Cms\Pages;
|
||||
use Kirby\Cms\Site;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Panel\Collector\PagesCollector;
|
||||
use Kirby\Panel\Ui\Item\PageItem;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\I18n;
|
||||
|
||||
return [
|
||||
'mixins' => [
|
||||
'empty',
|
||||
'headline',
|
||||
'help',
|
||||
'layout',
|
||||
'min',
|
||||
'max',
|
||||
'pagination',
|
||||
'parent'
|
||||
],
|
||||
'props' => [
|
||||
/**
|
||||
* Optional array of templates that should only be allowed to add
|
||||
* or `false` to completely disable page creation
|
||||
*/
|
||||
'create' => function ($create = null) {
|
||||
return $create;
|
||||
},
|
||||
/**
|
||||
* Enables/disables reverse sorting
|
||||
*/
|
||||
'flip' => function (bool $flip = false) {
|
||||
return $flip;
|
||||
},
|
||||
/**
|
||||
* Image options to control the source and look of page previews
|
||||
*/
|
||||
'image' => function ($image = null) {
|
||||
return $image ?? [];
|
||||
},
|
||||
/**
|
||||
* Optional info text setup. Info text is shown on the right (lists) or below (cards) the page title.
|
||||
*/
|
||||
'info' => function (string $info = null) {
|
||||
return $info;
|
||||
},
|
||||
/**
|
||||
* The size option controls the size of cards. By default cards are auto-sized and the cards grid will always fill the full width. With a size you can disable auto-sizing. Available sizes: `tiny`, `small`, `medium`, `large`, `huge`
|
||||
*/
|
||||
'size' => function (string $size = 'auto') {
|
||||
return $size;
|
||||
},
|
||||
/**
|
||||
* Enables/disables manual sorting
|
||||
*/
|
||||
'sortable' => function (bool $sortable = true) {
|
||||
return $sortable;
|
||||
},
|
||||
/**
|
||||
* Overwrites manual sorting and sorts by the given field and sorting direction (i.e. `date desc`)
|
||||
*/
|
||||
'sortBy' => function (string $sortBy = null) {
|
||||
return $sortBy;
|
||||
},
|
||||
/**
|
||||
* Filters pages by their status. Available status settings: `draft`, `unlisted`, `listed`, `published`, `all`.
|
||||
*/
|
||||
'status' => function (string $status = '') {
|
||||
if ($status === 'drafts') {
|
||||
$status = 'draft';
|
||||
}
|
||||
'mixins' => [
|
||||
'batch',
|
||||
'details',
|
||||
'empty',
|
||||
'headline',
|
||||
'help',
|
||||
'layout',
|
||||
'min',
|
||||
'max',
|
||||
'pagination',
|
||||
'parent',
|
||||
'search',
|
||||
'sort'
|
||||
],
|
||||
'props' => [
|
||||
/**
|
||||
* Optional array of templates that should only be allowed to add
|
||||
* or `false` to completely disable page creation
|
||||
*/
|
||||
'create' => function ($create = null) {
|
||||
return $create;
|
||||
},
|
||||
/**
|
||||
* Filters pages by a query. Sorting will be disabled
|
||||
*/
|
||||
'query' => function (string|null $query = null) {
|
||||
return $query;
|
||||
},
|
||||
/**
|
||||
* Filters pages by their status. Available status settings: `draft`, `unlisted`, `listed`, `published`, `all`.
|
||||
*/
|
||||
'status' => function (string $status = '') {
|
||||
if ($status === 'drafts') {
|
||||
$status = 'draft';
|
||||
}
|
||||
|
||||
if (in_array($status, ['all', 'draft', 'published', 'listed', 'unlisted']) === false) {
|
||||
$status = 'all';
|
||||
}
|
||||
if (in_array($status, ['all', 'draft', 'published', 'listed', 'unlisted'], true) === false) {
|
||||
$status = 'all';
|
||||
}
|
||||
|
||||
return $status;
|
||||
},
|
||||
/**
|
||||
* Filters the list by templates and sets template options when adding new pages to the section.
|
||||
*/
|
||||
'templates' => function ($templates = null) {
|
||||
return A::wrap($templates ?? $this->template);
|
||||
},
|
||||
/**
|
||||
* Setup for the main text in the list or cards. By default this will display the page title.
|
||||
*/
|
||||
'text' => function (string $text = '{{ page.title }}') {
|
||||
return $text;
|
||||
}
|
||||
],
|
||||
'computed' => [
|
||||
'parent' => function () {
|
||||
return $this->parentModel();
|
||||
},
|
||||
'pages' => function () {
|
||||
switch ($this->status) {
|
||||
case 'draft':
|
||||
$pages = $this->parent->drafts();
|
||||
break;
|
||||
case 'listed':
|
||||
$pages = $this->parent->children()->listed();
|
||||
break;
|
||||
case 'published':
|
||||
$pages = $this->parent->children();
|
||||
break;
|
||||
case 'unlisted':
|
||||
$pages = $this->parent->children()->unlisted();
|
||||
break;
|
||||
default:
|
||||
$pages = $this->parent->childrenAndDrafts();
|
||||
}
|
||||
return $status;
|
||||
},
|
||||
/**
|
||||
* Filters the list by single template.
|
||||
*/
|
||||
'template' => function (string|array|null $template = null) {
|
||||
return $template;
|
||||
},
|
||||
/**
|
||||
* Filters the list by templates and sets template options when adding new pages to the section.
|
||||
*/
|
||||
'templates' => function ($templates = null) {
|
||||
return A::wrap($templates ?? $this->template);
|
||||
},
|
||||
/**
|
||||
* Excludes the selected templates.
|
||||
*/
|
||||
'templatesIgnore' => function ($templates = null) {
|
||||
return A::wrap($templates);
|
||||
}
|
||||
],
|
||||
'computed' => [
|
||||
'parent' => function () {
|
||||
$parent = $this->parentModel();
|
||||
|
||||
// loop for the best performance
|
||||
foreach ($pages->data as $id => $page) {
|
||||
if (
|
||||
$parent instanceof Site === false &&
|
||||
$parent instanceof Page === false
|
||||
) {
|
||||
throw new InvalidArgumentException(
|
||||
message: 'The parent is invalid. You must choose the site or a page as parent.'
|
||||
);
|
||||
}
|
||||
|
||||
// remove all protected pages
|
||||
if ($page->isReadable() === false) {
|
||||
unset($pages->data[$id]);
|
||||
continue;
|
||||
}
|
||||
return $parent;
|
||||
},
|
||||
'collector' => function () {
|
||||
return $this->collector ??= new PagesCollector(
|
||||
limit: $this->limit(),
|
||||
page: $this->page() ?? 1,
|
||||
parent: $this->parent(),
|
||||
query: $this->query(),
|
||||
status: $this->status(),
|
||||
templates: $this->templates(),
|
||||
templatesIgnore: $this->templatesIgnore(),
|
||||
search: $this->searchterm(),
|
||||
sortBy: $this->sortBy(),
|
||||
flip: $this->flip()
|
||||
);
|
||||
},
|
||||
'models' => function () {
|
||||
return $this->collector()->models();
|
||||
},
|
||||
'modelsPaginated' => function () {
|
||||
return $this->collector()->models(paginated: true);
|
||||
},
|
||||
'pages' => function () {
|
||||
return $this->models();
|
||||
},
|
||||
'total' => function () {
|
||||
return $this->models()->count();
|
||||
},
|
||||
'data' => function () {
|
||||
$data = [];
|
||||
|
||||
// filter by all set templates
|
||||
if ($this->templates && in_array($page->intendedTemplate()->name(), $this->templates) === false) {
|
||||
unset($pages->data[$id]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
foreach ($this->modelsPaginated() as $page) {
|
||||
$item = (new PageItem(
|
||||
page: $page,
|
||||
image: $this->image,
|
||||
layout: $this->layout,
|
||||
info: $this->info,
|
||||
text: $this->text,
|
||||
))->props();
|
||||
|
||||
// sort
|
||||
if ($this->sortBy) {
|
||||
$pages = $pages->sortBy(...$pages::sortArgs($this->sortBy));
|
||||
}
|
||||
if ($this->layout === 'table') {
|
||||
$item = $this->columnsValues($item, $page);
|
||||
}
|
||||
|
||||
// flip
|
||||
if ($this->flip === true) {
|
||||
$pages = $pages->flip();
|
||||
}
|
||||
$data[] = $item;
|
||||
}
|
||||
|
||||
// pagination
|
||||
$pages = $pages->paginate([
|
||||
'page' => $this->page,
|
||||
'limit' => $this->limit,
|
||||
'method' => 'none' // the page is manually provided
|
||||
]);
|
||||
return $data;
|
||||
},
|
||||
'errors' => function () {
|
||||
$errors = [];
|
||||
|
||||
return $pages;
|
||||
},
|
||||
'total' => function () {
|
||||
return $this->pages->pagination()->total();
|
||||
},
|
||||
'data' => function () {
|
||||
$data = [];
|
||||
if ($this->validateMax() === false) {
|
||||
$errors['max'] = I18n::template('error.section.pages.max.' . I18n::form($this->max), [
|
||||
'max' => $this->max,
|
||||
'section' => $this->headline
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($this->pages as $item) {
|
||||
$permissions = $item->permissions();
|
||||
$image = $item->panelImage($this->image);
|
||||
if ($this->validateMin() === false) {
|
||||
$errors['min'] = I18n::template('error.section.pages.min.' . I18n::form($this->min), [
|
||||
'min' => $this->min,
|
||||
'section' => $this->headline
|
||||
]);
|
||||
}
|
||||
|
||||
$data[] = [
|
||||
'id' => $item->id(),
|
||||
'dragText' => $item->dragText(),
|
||||
'text' => $item->toString($this->text),
|
||||
'info' => $item->toString($this->info ?? false),
|
||||
'parent' => $item->parentId(),
|
||||
'icon' => $item->panelIcon($image),
|
||||
'image' => $image,
|
||||
'link' => $item->panelUrl(true),
|
||||
'status' => $item->status(),
|
||||
'permissions' => [
|
||||
'sort' => $permissions->can('sort'),
|
||||
'changeStatus' => $permissions->can('changeStatus')
|
||||
]
|
||||
];
|
||||
}
|
||||
if (empty($errors) === true) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $data;
|
||||
},
|
||||
'errors' => function () {
|
||||
$errors = [];
|
||||
return [
|
||||
$this->name => [
|
||||
'label' => $this->headline,
|
||||
'message' => $errors,
|
||||
]
|
||||
];
|
||||
},
|
||||
'add' => function () {
|
||||
if ($this->create === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->validateMax() === false) {
|
||||
$errors['max'] = I18n::template('error.section.pages.max.' . I18n::form($this->max), [
|
||||
'max' => $this->max,
|
||||
'section' => $this->headline
|
||||
]);
|
||||
}
|
||||
if ($this->isFull() === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->validateMin() === false) {
|
||||
$errors['min'] = I18n::template('error.section.pages.min.' . I18n::form($this->min), [
|
||||
'min' => $this->min,
|
||||
'section' => $this->headline
|
||||
]);
|
||||
}
|
||||
// form here on, we need to check with which status
|
||||
// the pages are created and if the section can show
|
||||
// these newly created pages
|
||||
|
||||
if (empty($errors) === true) {
|
||||
return [];
|
||||
}
|
||||
// if the section shows pages no matter what status they have,
|
||||
// we can always show the add button
|
||||
if ($this->status === 'all') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return [
|
||||
$this->name => [
|
||||
'label' => $this->headline,
|
||||
'message' => $errors,
|
||||
]
|
||||
];
|
||||
},
|
||||
'add' => function () {
|
||||
if ($this->create === false) {
|
||||
return false;
|
||||
}
|
||||
// collect all statuses of the blueprints
|
||||
// that are allowed to be created
|
||||
$statuses = [];
|
||||
|
||||
if (in_array($this->status, ['draft', 'all']) === false) {
|
||||
return false;
|
||||
}
|
||||
foreach ($this->blueprintNames() as $blueprint) {
|
||||
try {
|
||||
$props = Blueprint::load('pages/' . $blueprint);
|
||||
$statuses[] = $props['create']['status'] ?? 'draft';
|
||||
} catch (Throwable) {
|
||||
$statuses[] = 'draft'; // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isFull() === true) {
|
||||
return false;
|
||||
}
|
||||
$statuses = array_unique($statuses);
|
||||
|
||||
return true;
|
||||
},
|
||||
'link' => function () {
|
||||
$modelLink = $this->model->panelUrl(true);
|
||||
$parentLink = $this->parent->panelUrl(true);
|
||||
// if there are multiple statuses or if the section is showing
|
||||
// a different status than new pages would be created with,
|
||||
// we cannot show the add button
|
||||
if (count($statuses) > 1 || $this->status !== $statuses[0]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($modelLink !== $parentLink) {
|
||||
return $parentLink;
|
||||
}
|
||||
},
|
||||
'pagination' => function () {
|
||||
return $this->pagination();
|
||||
},
|
||||
'sortable' => function () {
|
||||
if (in_array($this->status, ['listed', 'published', 'all']) === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
'pagination' => function () {
|
||||
return $this->pagination();
|
||||
}
|
||||
],
|
||||
'methods' => [
|
||||
'blueprints' => function () {
|
||||
$blueprints = [];
|
||||
|
||||
if ($this->sortable === false) {
|
||||
return false;
|
||||
}
|
||||
// convert every template to a usable option array
|
||||
// for the template select box
|
||||
foreach ($this->blueprintNames() as $blueprint) {
|
||||
try {
|
||||
$props = Blueprint::load('pages/' . $blueprint);
|
||||
|
||||
if ($this->sortBy !== null) {
|
||||
return false;
|
||||
}
|
||||
$blueprints[] = [
|
||||
'name' => basename($props['name']),
|
||||
'title' => $props['title'],
|
||||
];
|
||||
} catch (Throwable) {
|
||||
$blueprints[] = [
|
||||
'name' => basename($blueprint),
|
||||
'title' => ucfirst($blueprint),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->flip === true) {
|
||||
return false;
|
||||
}
|
||||
return $blueprints;
|
||||
},
|
||||
'blueprintNames' => function () {
|
||||
$blueprints = empty($this->create) === false ? A::wrap($this->create) : $this->templates;
|
||||
|
||||
return true;
|
||||
}
|
||||
],
|
||||
'methods' => [
|
||||
'blueprints' => function () {
|
||||
$blueprints = [];
|
||||
$templates = empty($this->create) === false ? A::wrap($this->create) : $this->templates;
|
||||
if (empty($blueprints) === true) {
|
||||
$blueprints = $this->kirby()->blueprints();
|
||||
}
|
||||
|
||||
if (empty($templates) === true) {
|
||||
$templates = $this->kirby()->blueprints();
|
||||
}
|
||||
// excludes ignored templates
|
||||
if ($templatesIgnore = $this->templatesIgnore) {
|
||||
$blueprints = array_diff($blueprints, $templatesIgnore);
|
||||
}
|
||||
|
||||
// convert every template to a usable option array
|
||||
// for the template select box
|
||||
foreach ($templates as $template) {
|
||||
try {
|
||||
$props = Blueprint::load('pages/' . $template);
|
||||
|
||||
$blueprints[] = [
|
||||
'name' => basename($props['name']),
|
||||
'title' => $props['title'],
|
||||
];
|
||||
} catch (Throwable $e) {
|
||||
$blueprints[] = [
|
||||
'name' => basename($template),
|
||||
'title' => ucfirst($template),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $blueprints;
|
||||
}
|
||||
],
|
||||
'toArray' => function () {
|
||||
return [
|
||||
'data' => $this->data,
|
||||
'errors' => $this->errors,
|
||||
'options' => [
|
||||
'add' => $this->add,
|
||||
'empty' => $this->empty,
|
||||
'headline' => $this->headline,
|
||||
'help' => $this->help,
|
||||
'layout' => $this->layout,
|
||||
'link' => $this->link,
|
||||
'max' => $this->max,
|
||||
'min' => $this->min,
|
||||
'size' => $this->size,
|
||||
'sortable' => $this->sortable
|
||||
],
|
||||
'pagination' => $this->pagination,
|
||||
];
|
||||
}
|
||||
return $blueprints;
|
||||
},
|
||||
],
|
||||
// @codeCoverageIgnoreStart
|
||||
'api' => function () {
|
||||
return [
|
||||
[
|
||||
'pattern' => 'delete',
|
||||
'method' => 'DELETE',
|
||||
'action' => function () {
|
||||
return $this->section()->deleteSelected(
|
||||
ids: $this->requestBody('ids'),
|
||||
);
|
||||
}
|
||||
]
|
||||
];
|
||||
},
|
||||
// @codeCoverageIgnoreEnd
|
||||
'toArray' => function () {
|
||||
return [
|
||||
'data' => $this->data,
|
||||
'errors' => $this->errors,
|
||||
'options' => [
|
||||
'add' => $this->add,
|
||||
'batch' => $this->batch,
|
||||
'columns' => $this->columnsWithTypes(),
|
||||
'empty' => $this->empty,
|
||||
'headline' => $this->headline,
|
||||
'help' => $this->help,
|
||||
'layout' => $this->layout,
|
||||
'link' => $this->link(),
|
||||
'max' => $this->max,
|
||||
'min' => $this->min,
|
||||
'search' => $this->search,
|
||||
'size' => $this->size,
|
||||
'sortable' => $this->sortable
|
||||
],
|
||||
'pagination' => $this->pagination,
|
||||
];
|
||||
}
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue