Upgrade Kirby from 4.3.0 to 4.4.0
This commit is contained in:
parent
03905dbd83
commit
3bed01af75
293 changed files with 54254 additions and 187 deletions
|
|
@ -782,7 +782,7 @@ class App
|
|||
if ($input instanceof Page) {
|
||||
try {
|
||||
$html = $input->render();
|
||||
} catch (ErrorPageException $e) {
|
||||
} catch (ErrorPageException|NotFoundException $e) {
|
||||
return $this->io($e);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,8 +190,19 @@ trait AppErrors
|
|||
protected function getAdditionalWhoopsHandler(): CallbackHandler
|
||||
{
|
||||
return new CallbackHandler(function ($exception, $inspector, $run) {
|
||||
$this->trigger('system.exception', compact('exception'));
|
||||
error_log($exception);
|
||||
$isLogged = true;
|
||||
|
||||
// allow hook to modify whether the exception should be logged
|
||||
$isLogged = $this->apply(
|
||||
'system.exception',
|
||||
compact('exception', 'isLogged'),
|
||||
'isLogged'
|
||||
);
|
||||
|
||||
if ($isLogged !== false) {
|
||||
error_log($exception);
|
||||
}
|
||||
|
||||
return Handler::DONE;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -717,7 +717,7 @@ trait AppPlugins
|
|||
array $info = [],
|
||||
string|null $root = null,
|
||||
string|null $version = null
|
||||
): PLugin|null {
|
||||
): Plugin|null {
|
||||
if ($extends === null) {
|
||||
return static::$plugins[$name] ?? null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ class File extends ModelWithContent
|
|||
* Page URL and the filename as a more stable
|
||||
* alternative for the media URLs.
|
||||
*/
|
||||
public function previewUrl(): string
|
||||
public function previewUrl(): string|null
|
||||
{
|
||||
$parent = $this->parent();
|
||||
$url = Url::to($this->id());
|
||||
|
|
@ -633,6 +633,12 @@ class File extends ModelWithContent
|
|||
case 'page':
|
||||
$preview = $parent->blueprint()->preview();
|
||||
|
||||
// user has no permission to preview page,
|
||||
// also return null for file preview
|
||||
if ($preview === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// the page has a custom preview setting,
|
||||
// thus the file is only accessible through
|
||||
// the direct media URL
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ class FileRules
|
|||
public static function validMime(File $file, string $mime = null): bool
|
||||
{
|
||||
// make it easier to compare the mime
|
||||
$mime = strtolower($mime);
|
||||
$mime = strtolower($mime ?? '');
|
||||
|
||||
if (empty($mime)) {
|
||||
throw new InvalidArgumentException([
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use Kirby\Data\Data;
|
|||
use Kirby\Exception\Exception;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
use Kirby\Exception\PermissionException;
|
||||
use Kirby\Filesystem\F;
|
||||
use Kirby\Toolkit\Locale;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
|
@ -145,8 +146,17 @@ class Language
|
|||
*/
|
||||
public static function create(array $props): static
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
|
||||
if (
|
||||
$user === null ||
|
||||
$user->role()->permissions()->for('languages', 'create') === false
|
||||
) {
|
||||
throw new PermissionException(['key' => 'language.create.permission']);
|
||||
}
|
||||
|
||||
$props['code'] = Str::slug($props['code'] ?? null);
|
||||
$kirby = App::instance();
|
||||
$languages = $kirby->languages();
|
||||
|
||||
// make the first language the default language
|
||||
|
|
@ -204,8 +214,16 @@ class Language
|
|||
public function delete(): bool
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
$code = $this->code();
|
||||
|
||||
if (
|
||||
$user === null ||
|
||||
$user->role()->permissions()->for('languages', 'delete') === false
|
||||
) {
|
||||
throw new PermissionException(['key' => 'language.delete.permission']);
|
||||
}
|
||||
|
||||
if ($this->isDeletable() === false) {
|
||||
throw new Exception('The language cannot be deleted');
|
||||
}
|
||||
|
|
@ -497,13 +515,22 @@ class Language
|
|||
*/
|
||||
public function update(array $props = null): static
|
||||
{
|
||||
$kirby = App::instance();
|
||||
$user = $kirby->user();
|
||||
|
||||
if (
|
||||
$user === null ||
|
||||
$user->role()->permissions()->for('languages', 'update') === false
|
||||
) {
|
||||
throw new PermissionException(['key' => 'language.update.permission']);
|
||||
}
|
||||
|
||||
// don't change the language code
|
||||
unset($props['code']);
|
||||
|
||||
// make sure the slug is nice and clean
|
||||
$props['slug'] = Str::slug($props['slug'] ?? null);
|
||||
|
||||
$kirby = App::instance();
|
||||
$updated = $this->clone($props);
|
||||
|
||||
if (isset($props['translations']) === true) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use Kirby\Exception\NotFoundException;
|
|||
use Kirby\Http\Router;
|
||||
use Kirby\Toolkit\A;
|
||||
use Kirby\Toolkit\Str;
|
||||
use Kirby\Uuid\Uuid;
|
||||
|
||||
/**
|
||||
* The language router is used internally
|
||||
|
|
@ -84,6 +85,27 @@ class LanguageRouter
|
|||
}
|
||||
}
|
||||
|
||||
// Language-specific UUID URLs
|
||||
$routes[] = [
|
||||
'pattern' => '@/(page|file)/(:all)',
|
||||
'method' => 'ALL',
|
||||
'env' => 'site',
|
||||
'action' => function (string $languageCode, string $type, string $id) use ($kirby, $language) {
|
||||
// try to resolve to model, but only from UUID cache;
|
||||
// this ensures that only existing UUIDs can be queried
|
||||
// and attackers can't force Kirby to go through the whole
|
||||
// site index with a non-existing UUID
|
||||
if ($model = Uuid::for($type . '://' . $id)?->model(true)) {
|
||||
return $kirby
|
||||
->response()
|
||||
->redirect($model->url($language->code()));
|
||||
}
|
||||
|
||||
// render the error page
|
||||
return false;
|
||||
}
|
||||
];
|
||||
|
||||
return $routes;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Filesystem\F;
|
||||
use Kirby\Toolkit\Str;
|
||||
|
||||
class LanguageRoutes
|
||||
{
|
||||
|
|
@ -29,9 +30,26 @@ class LanguageRoutes
|
|||
'pattern' => $language->pattern(),
|
||||
'method' => 'ALL',
|
||||
'env' => 'site',
|
||||
'action' => function ($path = null) use ($language) {
|
||||
'action' => function ($path = null) use ($kirby, $language) {
|
||||
$result = $language->router()->call($path);
|
||||
|
||||
// redirect secondary-language pages that have
|
||||
// been accessed with non-translated slugs in their path
|
||||
// to their fully translated URL
|
||||
if ($path !== null && $result instanceof Page) {
|
||||
if (Str::endsWith($result->url(), $path) === false) {
|
||||
$url = $result->url();
|
||||
$query = $kirby->request()->query()->toString();
|
||||
|
||||
// preserve query across redirect
|
||||
if (empty($query) === false) {
|
||||
$url .= '?' . $query;
|
||||
}
|
||||
|
||||
return $kirby->response()->redirect($url);
|
||||
}
|
||||
}
|
||||
|
||||
// explicitly test for null as $result can
|
||||
// contain falsy values that should still be returned
|
||||
if ($result !== null) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use Throwable;
|
|||
*/
|
||||
class License
|
||||
{
|
||||
protected const HISTORY = [
|
||||
public const HISTORY = [
|
||||
'3' => '2019-02-05',
|
||||
'4' => '2023-11-28'
|
||||
];
|
||||
|
|
|
|||
|
|
@ -43,8 +43,16 @@ abstract class ModelPermissions
|
|||
return $this->toArray();
|
||||
}
|
||||
|
||||
public function can(string $action): bool
|
||||
{
|
||||
/**
|
||||
* Returns whether the current user is allowed to do
|
||||
* a certain action on the model
|
||||
*
|
||||
* @param bool $default Will be returned if $action does not exist
|
||||
*/
|
||||
public function can(
|
||||
string $action,
|
||||
bool $default = false
|
||||
): bool {
|
||||
$user = $this->user->id();
|
||||
$role = $this->user->role()->id();
|
||||
|
||||
|
|
@ -95,12 +103,20 @@ abstract class ModelPermissions
|
|||
}
|
||||
}
|
||||
|
||||
return $this->permissions->for($this->category, $action);
|
||||
return $this->permissions->for($this->category, $action, $default);
|
||||
}
|
||||
|
||||
public function cannot(string $action): bool
|
||||
{
|
||||
return $this->can($action) === false;
|
||||
/**
|
||||
* Returns whether the current user is not allowed to do
|
||||
* a certain action on the model
|
||||
*
|
||||
* @param bool $default Will be returned if $action does not exist
|
||||
*/
|
||||
public function cannot(
|
||||
string $action,
|
||||
bool $default = true
|
||||
): bool {
|
||||
return $this->can($action, !$default) === false;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ class PageBlueprint extends Blueprint
|
|||
return $this->model->toString($preview);
|
||||
}
|
||||
|
||||
return $preview;
|
||||
return $this->model->permissions()->can('preview', true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ class Permissions
|
|||
],
|
||||
'languages' => [
|
||||
'create' => true,
|
||||
'delete' => true
|
||||
'delete' => true,
|
||||
'update' => true
|
||||
],
|
||||
'pages' => [
|
||||
'access' => true,
|
||||
|
|
@ -109,18 +110,21 @@ class Permissions
|
|||
}
|
||||
}
|
||||
|
||||
public function for(string $category = null, string $action = null): bool
|
||||
{
|
||||
public function for(
|
||||
string|null $category = null,
|
||||
string|null $action = null,
|
||||
bool $default = false
|
||||
): bool {
|
||||
if ($action === null) {
|
||||
if ($this->hasCategory($category) === false) {
|
||||
return false;
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $this->actions[$category];
|
||||
}
|
||||
|
||||
if ($this->hasAction($category, $action) === false) {
|
||||
return false;
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $this->actions[$category][$action];
|
||||
|
|
|
|||
|
|
@ -51,6 +51,6 @@ class SiteBlueprint extends Blueprint
|
|||
return $this->model->toString($preview);
|
||||
}
|
||||
|
||||
return $preview;
|
||||
return $this->model->permissions()->can('preview', true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue