mirror of
https://github.com/getgrav/grav-plugin-admin.git
synced 2025-10-26 07:46:31 +01:00
more improvements to safe upgrade
This commit is contained in:
@@ -290,6 +290,7 @@ class SafeUpgradeManager
|
||||
$result = [
|
||||
'job' => $manifest ?: null,
|
||||
'progress' => $progress,
|
||||
'context' => $this->buildStatusContext(),
|
||||
];
|
||||
|
||||
$this->clearJobContext();
|
||||
@@ -417,6 +418,7 @@ class SafeUpgradeManager
|
||||
'log' => $logPath,
|
||||
'progress' => $this->getProgress(),
|
||||
'job' => $this->readManifest(),
|
||||
'context' => $this->buildStatusContext(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -553,6 +555,7 @@ class SafeUpgradeManager
|
||||
'status' => 'noop',
|
||||
'version' => $localVersion,
|
||||
'message' => 'Grav is already up to date.',
|
||||
'context' => $this->buildStatusContext(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -647,6 +650,7 @@ class SafeUpgradeManager
|
||||
'version' => $remoteVersion,
|
||||
'manifest' => $manifest,
|
||||
'previous_version' => $localVersion,
|
||||
'context' => $this->buildStatusContext(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -896,6 +900,7 @@ class SafeUpgradeManager
|
||||
'status' => 'finalized',
|
||||
'version' => $localVersion,
|
||||
'message' => 'Post-install scripts completed.',
|
||||
'context' => $this->buildStatusContext(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1011,9 +1016,31 @@ class SafeUpgradeManager
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $message,
|
||||
'context' => $this->buildStatusContext(),
|
||||
] + $extra;
|
||||
}
|
||||
|
||||
protected function buildStatusContext(): ?string
|
||||
{
|
||||
$context = [];
|
||||
|
||||
if ($this->jobManifestPath) {
|
||||
$context['manifest'] = $this->jobManifestPath;
|
||||
}
|
||||
|
||||
if ($this->progressPath) {
|
||||
$context['progress'] = $this->progressPath;
|
||||
}
|
||||
|
||||
if (!$context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$encoded = json_encode($context);
|
||||
|
||||
return $encoded === false ? null : base64_encode($encoded);
|
||||
}
|
||||
|
||||
protected function ensureExecutablePermissions(): void
|
||||
{
|
||||
$executables = [
|
||||
|
||||
@@ -33,11 +33,73 @@ $readJson = static function (string $path): ?array {
|
||||
|
||||
$progress = null;
|
||||
$manifest = null;
|
||||
$manifestPath = null;
|
||||
$progressPath = null;
|
||||
|
||||
$normalizeDir = static function (string $path): string {
|
||||
$normalized = str_replace('\\', '/', $path);
|
||||
|
||||
return rtrim($normalized, '/');
|
||||
};
|
||||
|
||||
$jobsDirNormalized = $normalizeDir($jobsDir);
|
||||
$userDataDirNormalized = $normalizeDir(dirname($jobsDir));
|
||||
|
||||
$contextParam = $_GET['context'] ?? '';
|
||||
if ($contextParam !== '') {
|
||||
$decodedRaw = base64_decode(strtr($contextParam, ' ', '+'), true);
|
||||
if ($decodedRaw !== false) {
|
||||
$decoded = json_decode($decodedRaw, true);
|
||||
if (is_array($decoded)) {
|
||||
$validatePath = static function (string $candidate) use ($normalizeDir, $jobsDirNormalized, $userDataDirNormalized) {
|
||||
$candidate = str_replace('\\', '/', $candidate);
|
||||
$directory = dirname($candidate);
|
||||
$real = realpath($directory);
|
||||
if ($real === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$real = $normalizeDir($real);
|
||||
if (strpos($real, $jobsDirNormalized) !== 0 && strpos($real, $userDataDirNormalized) !== 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $candidate;
|
||||
};
|
||||
|
||||
if (!empty($decoded['manifest'])) {
|
||||
$candidate = $validatePath((string)$decoded['manifest']);
|
||||
if ($candidate) {
|
||||
$manifestPath = $candidate;
|
||||
if (is_file($candidate)) {
|
||||
$manifest = $readJson($candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($decoded['progress'])) {
|
||||
$candidate = $validatePath((string)$decoded['progress']);
|
||||
if ($candidate) {
|
||||
$progressPath = $candidate;
|
||||
if (is_file($candidate)) {
|
||||
$progress = $readJson($candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($jobId !== '') {
|
||||
$jobPath = $jobsDir . '/' . $jobId;
|
||||
$progress = $readJson($jobPath . '/progress.json');
|
||||
$manifest = $readJson($jobPath . '/manifest.json');
|
||||
$progressPath = $progressPath ?: ($jobPath . '/progress.json');
|
||||
$manifestPath = $manifestPath ?: ($jobPath . '/manifest.json');
|
||||
if (is_file($progressPath)) {
|
||||
$progress = $readJson($progressPath);
|
||||
}
|
||||
if (is_file($manifestPath)) {
|
||||
$manifest = $readJson($manifestPath);
|
||||
}
|
||||
|
||||
if (!$progress && !$manifest && !is_dir($jobPath)) {
|
||||
$progress = $readJson($fallbackProgress) ?: [
|
||||
@@ -46,37 +108,45 @@ if ($jobId !== '') {
|
||||
'percent' => null,
|
||||
'timestamp' => time(),
|
||||
];
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'message' => 'Safe upgrade job not found.',
|
||||
'data' => [
|
||||
'job' => null,
|
||||
'progress' => $progress,
|
||||
],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if ($progress === null) {
|
||||
$progress = $readJson($fallbackProgress) ?: [
|
||||
'stage' => 'idle',
|
||||
'message' => '',
|
||||
'percent' => null,
|
||||
'timestamp' => time(),
|
||||
];
|
||||
if ($progressPath && is_file($progressPath)) {
|
||||
$progress = $readJson($progressPath);
|
||||
}
|
||||
|
||||
if ($progress === null) {
|
||||
$progress = $readJson($fallbackProgress) ?: [
|
||||
'stage' => 'idle',
|
||||
'message' => '',
|
||||
'percent' => null,
|
||||
'timestamp' => time(),
|
||||
];
|
||||
$progressPath = $fallbackProgress;
|
||||
}
|
||||
}
|
||||
|
||||
if ($jobId !== '' && is_array($progress) && !isset($progress['job_id'])) {
|
||||
$progress['job_id'] = $jobId;
|
||||
}
|
||||
|
||||
$contextPayload = [];
|
||||
if ($manifestPath) {
|
||||
$contextPayload['manifest'] = $manifestPath;
|
||||
}
|
||||
if ($progressPath) {
|
||||
$contextPayload['progress'] = $progressPath;
|
||||
}
|
||||
|
||||
$contextToken = $contextPayload ? base64_encode(json_encode($contextPayload)) : null;
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'job' => $manifest ?: null,
|
||||
'progress' => $progress,
|
||||
'context' => $contextToken,
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ export default class SafeUpgrade {
|
||||
this.active = false;
|
||||
this.jobId = null;
|
||||
this.statusFailures = 0;
|
||||
this.statusContext = null;
|
||||
this.directStatusUrl = this.resolveDirectStatusUrl();
|
||||
this.preferDirectStatus = !!this.directStatusUrl;
|
||||
|
||||
@@ -120,6 +121,7 @@ export default class SafeUpgrade {
|
||||
this.decisions = {};
|
||||
this.statusFailures = 0;
|
||||
this.preferDirectStatus = !!this.directStatusUrl;
|
||||
this.statusContext = null;
|
||||
this.renderLoading();
|
||||
this.modal.open();
|
||||
this.fetchPreflight();
|
||||
@@ -412,6 +414,7 @@ export default class SafeUpgrade {
|
||||
}
|
||||
this.statusFailures = 0;
|
||||
this.preferDirectStatus = !!this.directStatusUrl;
|
||||
this.statusContext = data.context || null;
|
||||
this.beginPolling(1200);
|
||||
} else {
|
||||
this.renderResult(data);
|
||||
@@ -453,8 +456,18 @@ export default class SafeUpgrade {
|
||||
resolveStatusEndpoint() {
|
||||
const useDirect = this.directStatusUrl && this.preferDirectStatus;
|
||||
let url = useDirect ? this.directStatusUrl : this.urls.status;
|
||||
const params = [];
|
||||
|
||||
if (this.jobId) {
|
||||
url += (url.includes('?') ? '&' : '?') + `job=${encodeURIComponent(this.jobId)}`;
|
||||
params.push(`job=${encodeURIComponent(this.jobId)}`);
|
||||
}
|
||||
|
||||
if (this.statusContext) {
|
||||
params.push(`context=${encodeURIComponent(this.statusContext)}`);
|
||||
}
|
||||
|
||||
if (params.length) {
|
||||
url += (url.includes('?') ? '&' : '?') + params.join('&');
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -532,6 +545,9 @@ export default class SafeUpgrade {
|
||||
}
|
||||
|
||||
const payload = response.data || {};
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'context')) {
|
||||
this.statusContext = payload.context || null;
|
||||
}
|
||||
const job = payload.job || {};
|
||||
const data = payload.progress || payload;
|
||||
nextStage = data.stage || null;
|
||||
|
||||
15
themes/grav/js/admin.min.js
vendored
15
themes/grav/js/admin.min.js
vendored
@@ -4610,6 +4610,7 @@ var SafeUpgrade = /*#__PURE__*/function () {
|
||||
this.active = false;
|
||||
this.jobId = null;
|
||||
this.statusFailures = 0;
|
||||
this.statusContext = null;
|
||||
this.directStatusUrl = this.resolveDirectStatusUrl();
|
||||
this.preferDirectStatus = !!this.directStatusUrl;
|
||||
this.registerEvents();
|
||||
@@ -4676,6 +4677,7 @@ var SafeUpgrade = /*#__PURE__*/function () {
|
||||
this.decisions = {};
|
||||
this.statusFailures = 0;
|
||||
this.preferDirectStatus = !!this.directStatusUrl;
|
||||
this.statusContext = null;
|
||||
this.renderLoading();
|
||||
this.modal.open();
|
||||
this.fetchPreflight();
|
||||
@@ -4882,6 +4884,7 @@ var SafeUpgrade = /*#__PURE__*/function () {
|
||||
}
|
||||
_this4.statusFailures = 0;
|
||||
_this4.preferDirectStatus = !!_this4.directStatusUrl;
|
||||
_this4.statusContext = data.context || null;
|
||||
_this4.beginPolling(1200);
|
||||
} else {
|
||||
_this4.renderResult(data);
|
||||
@@ -4921,8 +4924,15 @@ var SafeUpgrade = /*#__PURE__*/function () {
|
||||
value: function resolveStatusEndpoint() {
|
||||
var useDirect = this.directStatusUrl && this.preferDirectStatus;
|
||||
var url = useDirect ? this.directStatusUrl : this.urls.status;
|
||||
var params = [];
|
||||
if (this.jobId) {
|
||||
url += (url.indexOf('?') !== -1 ? '&' : '?') + "job=".concat(encodeURIComponent(this.jobId));
|
||||
params.push("job=".concat(encodeURIComponent(this.jobId)));
|
||||
}
|
||||
if (this.statusContext) {
|
||||
params.push("context=".concat(encodeURIComponent(this.statusContext)));
|
||||
}
|
||||
if (params.length) {
|
||||
url += (url.indexOf('?') !== -1 ? '&' : '?') + params.join('&');
|
||||
}
|
||||
return {
|
||||
url: url,
|
||||
@@ -5002,6 +5012,9 @@ var SafeUpgrade = /*#__PURE__*/function () {
|
||||
return;
|
||||
}
|
||||
var payload = response.data || {};
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'context')) {
|
||||
_this6.statusContext = payload.context || null;
|
||||
}
|
||||
var job = payload.job || {};
|
||||
var data = payload.progress || payload;
|
||||
nextStage = data.stage || null;
|
||||
|
||||
Reference in New Issue
Block a user