Merge branch 'release/1.10.50'

This commit is contained in:
Andy Miller
2025-11-14 16:35:09 +00:00
7 changed files with 74 additions and 8 deletions

View File

@@ -10,6 +10,7 @@
1. [](#bugfix)
* Fix for deeply nested sortable fields (at last!)
* Restore admin session timeout modal by returning 401 for timed-out AJAX requests
* Honor `system.updates.safe_upgrade` so legacy Grav installs keep the classic updater
# v1.10.49.1
## 09/03/2025

View File

@@ -385,6 +385,11 @@ class AdminPlugin extends Plugin
'direct-install' => [['admin.super'], 'PLUGIN_ADMIN.DIRECT_INSTALL'],
]);
$config = $this->grav['config'] ?? null;
if (!SafeUpgradeManager::configAllowsSafeUpgrade($config)) {
return;
}
try {
$manifestFiles = glob(GRAV_ROOT . '/user/data/upgrades/*.json') ?: [];

View File

@@ -14,6 +14,7 @@
namespace Grav\Plugin\Admin;
use Grav\Common\Config\Config;
use Grav\Common\Filesystem\Folder;
use Grav\Common\GPM\Installer;
use Grav\Common\GPM\GPM;
@@ -178,6 +179,14 @@ class SafeUpgradeManager
*/
public function restoreSnapshot(string $snapshotId): array
{
if (!$this->isSafeUpgradeEnabled()) {
return [
'status' => 'error',
'message' => 'Safe upgrade is disabled in configuration.',
'manifest' => null,
];
}
try {
$safeUpgrade = $this->getSafeUpgradeService();
$manifest = $safeUpgrade->rollback($snapshotId);
@@ -934,6 +943,12 @@ class SafeUpgradeManager
public function runSnapshot(array $options): array
{
if (!$this->isSafeUpgradeEnabled()) {
return $this->errorResult('Safe upgrade is disabled in configuration.', [
'operation' => 'snapshot'
]);
}
$label = isset($options['label']) ? (string)$options['label'] : null;
if ($label !== null) {
$label = trim($label);
@@ -1068,14 +1083,37 @@ class SafeUpgradeManager
{
try {
$config = $this->grav['config'] ?? null;
if ($config === null) {
return true;
return self::configAllowsSafeUpgrade($config);
} catch (Throwable $e) {
return false;
}
}
/**
* @param Config|null $config
* @return bool
*/
public static function configAllowsSafeUpgrade(?Config $config): bool
{
if ($config === null) {
return false;
}
$value = $config->get('system.updates.safe_upgrade');
if ($value === null) {
return false;
}
if (is_string($value)) {
$filtered = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
if ($filtered === null) {
return false;
}
return (bool)$config->get('system.updates.safe_upgrade', true);
} catch (Throwable $e) {
return true;
return $filtered;
}
return (bool)$value;
}
/**

View File

@@ -10,12 +10,14 @@ import './update';
import './channel-switcher';
import SafeUpgrade from './safe-upgrade';
const SAFE_UPGRADE_ENABLED = Number(config.safe_upgrade_enabled || 0) === 1;
export default class Updates {
constructor(payload = {}) {
this.setPayload(payload);
this.task = `task${config.param_sep}`;
this.updateURL = '';
this.safeUpgrade = new SafeUpgrade(this);
this.safeUpgrade = SAFE_UPGRADE_ENABLED ? new SafeUpgrade(this) : null;
}
setPayload(payload = {}) {

View File

@@ -3055,6 +3055,7 @@ function updates_toPrimitive(t, r) { if ("object" != updates_typeof(t) || !t) re
var SAFE_UPGRADE_ENABLED = Number(external_GravAdmin_namespaceObject.config.safe_upgrade_enabled || 0) === 1;
var Updates = /*#__PURE__*/function () {
function Updates() {
var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -3062,7 +3063,7 @@ var Updates = /*#__PURE__*/function () {
this.setPayload(payload);
this.task = "task".concat(external_GravAdmin_namespaceObject.config.param_sep);
this.updateURL = '';
this.safeUpgrade = new SafeUpgrade(this);
this.safeUpgrade = SAFE_UPGRADE_ENABLED ? new SafeUpgrade(this) : null;
}
return updates_createClass(Updates, [{
key: "setPayload",

View File

@@ -82,7 +82,8 @@
</div>
{% endblock %}
{% block modals %}
{% set safe_upgrade_enabled = config.system.updates.safe_upgrade|default(false) %}
{% block modals %}
{# Session expired blocking modal #}
<div class="remodal" data-remodal-id="session-expired" data-remodal-options="hashTracking: false">
<form>
@@ -127,6 +128,7 @@
</div>
</form>
</div>
{% if safe_upgrade_enabled %}
<div class="remodal safe-upgrade-modal" data-remodal-id="update-grav" data-remodal-options="hashTracking: false">
<form class="safe-upgrade-form">
<div class="safe-upgrade-header">
@@ -146,6 +148,21 @@
</div>
</form>
</div>
{% else %}
<div class="remodal" data-remodal-id="update-grav" data-remodal-options="hashTracking: false">
<form>
<h1>{{ "PLUGIN_ADMIN.MODAL_DELETE_FILE_CONFIRMATION_REQUIRED_TITLE"|t }}</h1>
<p class="bigger">
{{ "PLUGIN_ADMIN.MODAL_UPDATE_GRAV_CONFIRMATION_REQUIRED_DESC"|t }}
</p>
<br>
<div class="button-bar">
<button data-remodal-action="cancel" class="button secondary remodal-cancel"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|t }}</button>
<button data-remodal-action="confirm" class="button remodal-confirm disable-after-click"><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONTINUE"|t }}</button>
</div>
</form>
</div>
{% endif %}
{% endblock %}
</main>

View File

@@ -4,6 +4,7 @@
{% set plugins_enabled = config.plugins.admin.notifications.plugins is same as(true) or config.plugins.admin.notifications.plugins == 'true' %}
{% set themes_enabled = config.plugins.admin.notifications.themes is same as(true) or config.plugins.admin.notifications.themes == 'true' %}
{% set notifications = (feed_enabled or dashboard_enabled or plugins_enabled or themes_enabled) ? 1 : 0 %}
{% set safe_upgrade_enabled = config.system.updates.safe_upgrade|default(false) %}
{% switch template_route %}
{% case 'dashboard' %}
@@ -28,6 +29,7 @@
{% endif %}
admin_timeout: '{{ config.plugins.admin.session.timeout ?: 1800 }}',
keep_alive_enabled: {{ (config.plugins.admin.session.keep_alive is defined ? config.plugins.admin.session.keep_alive : true) ? 1 : 0 }},
safe_upgrade_enabled: {{ safe_upgrade_enabled ? 1 : 0 }},
admin_nonce: '{{ admin.getNonce }}',
language: '{{ grav.user.language|default('en') }}',
pro_enabled: '{{ config.plugins["admin-pro"].enabled }}',