From 50173806265ba2e7f6c13216e8a7530e5e8beca1 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Fri, 14 Jun 2024 13:26:59 +0200 Subject: [PATCH] Add a proper error message for incompatible Plugin-Store packages Fixes #5800 See https://www.woltlab.com/community/thread/306394-error-message-when-trying-to-install-a-package-by-storecode/ --- .../Core/Acp/Ui/Package/QuickInstallation.ts | 59 +++++++++++++------ .../acp/templates/packageStartInstall.tpl | 3 +- .../Core/Acp/Ui/Package/QuickInstallation.js | 57 ++++++++++++------ .../form/PackageStartInstallForm.class.php | 3 + wcfsetup/install/lang/de.xml | 1 + wcfsetup/install/lang/en.xml | 1 + 6 files changed, 86 insertions(+), 38 deletions(-) diff --git a/ts/WoltLabSuite/Core/Acp/Ui/Package/QuickInstallation.ts b/ts/WoltLabSuite/Core/Acp/Ui/Package/QuickInstallation.ts index d2c465867b..6416a4e741 100644 --- a/ts/WoltLabSuite/Core/Acp/Ui/Package/QuickInstallation.ts +++ b/ts/WoltLabSuite/Core/Acp/Ui/Package/QuickInstallation.ts @@ -13,6 +13,7 @@ import { isPlainObject } from "../../../Core"; import * as Language from "../../../Language"; import { innerError } from "../../../Dom/Util"; import UiDialog from "../../../Ui/Dialog"; +import { StatusNotOk } from "WoltLabSuite/Core/Ajax/Error"; let codeInput: HTMLInputElement; @@ -32,7 +33,7 @@ type Response = type: string; }; -function detectCode(): void { +function detectCode(versionNumber: string): void { const value = codeInput.value.trim(); if (value === "") { innerError(codeInput, false); @@ -55,7 +56,7 @@ function detectCode(): void { if (json.package && json.password && json.username) { isValid = true; - void prepareInstallation(json); + void prepareInstallation(json, versionNumber); } } } @@ -78,7 +79,7 @@ function refreshPackageDatabase() { return refreshedPackageDatabase; } -async function prepareInstallation(data: InstallationCode): Promise { +async function prepareInstallation(data: InstallationCode, versionNumber: string): Promise { try { AjaxStatus.show(); await refreshPackageDatabase(); @@ -86,19 +87,41 @@ async function prepareInstallation(data: InstallationCode): Promise { AjaxStatus.hide(); } - const response = (await dboAction("prepareInstallation", "wcf\\data\\package\\update\\PackageUpdateAction") - .payload({ - packages: { - [data.package]: "", - }, - authData: { - username: data.username, - password: data.password, - saveCredentials: false, - isStoreCode: true, - }, - }) - .dispatch()) as Response; + let response: Response; + try { + response = (await dboAction("prepareInstallation", "wcf\\data\\package\\update\\PackageUpdateAction") + .payload({ + packages: { + [data.package]: "", + }, + authData: { + username: data.username, + password: data.password, + saveCredentials: false, + isStoreCode: true, + }, + }) + .dispatch()) as Response; + } catch (e) { + if (e instanceof StatusNotOk) { + try { + const json = await e.response.clone().json(); + if (typeof json.message === "string" && json.message.startsWith("Cannot find the package '")) { + codeInput.value = ""; + innerError( + codeInput, + Language.getPhrase("wcf.acp.package.error.incompatibleStoreProduct", { versionNumber }), + ); + + return; + } + } catch { + throw e; + } + } + + throw e; + } if ("queueID" in response) { if (response.queueID === null) { @@ -129,7 +152,7 @@ async function prepareInstallation(data: InstallationCode): Promise { } } -export function setup(): void { +export function setup(versionNumber: string): void { codeInput = document.getElementById("quickInstallationCode") as HTMLInputElement; codeInput.addEventListener("focus", () => { @@ -140,6 +163,6 @@ export function setup(): void { }); codeInput.addEventListener("input", () => { - detectCode(); + detectCode(versionNumber); }); } diff --git a/wcfsetup/install/files/acp/templates/packageStartInstall.tpl b/wcfsetup/install/files/acp/templates/packageStartInstall.tpl index ca9856ae67..c56f585188 100644 --- a/wcfsetup/install/files/acp/templates/packageStartInstall.tpl +++ b/wcfsetup/install/files/acp/templates/packageStartInstall.tpl @@ -9,6 +9,7 @@ require([ "WoltLabSuite/Core/Acp/Ui/Package/QuickInstallation", "WoltLabSuite/Core/Acp/Ui/Package/Search"], (AcpUiPackageQuickInstallation, AcpUiPackageSearch) => { + {jsphrase name='wcf.acp.package.error.incompatibleStoreProduct'} {jsphrase name='wcf.acp.package.error.uniqueAlreadyInstalled'} {jsphrase name='wcf.acp.package.install.title'} {jsphrase name='wcf.acp.package.quickInstallation.code.error.invalid'} @@ -16,7 +17,7 @@ {jsphrase name='wcf.acp.package.update.title'} {jsphrase name='wcf.acp.package.update.unauthorized'} - AcpUiPackageQuickInstallation.setup(); + AcpUiPackageQuickInstallation.setup('{$majorMinorVersion}'); new AcpUiPackageSearch(); {if $errorField === 'uploadPackage'} diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Package/QuickInstallation.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Package/QuickInstallation.js index ad500753b8..3190d9fc63 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Package/QuickInstallation.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Package/QuickInstallation.js @@ -6,7 +6,7 @@ * @copyright 2001-2022 WoltLab GmbH * @license GNU Lesser General Public License */ -define(["require", "exports", "tslib", "../../../Ajax", "../../../Ajax/Status", "../../../Core", "../../../Language", "../../../Dom/Util", "../../../Ui/Dialog"], function (require, exports, tslib_1, Ajax_1, AjaxStatus, Core_1, Language, Util_1, Dialog_1) { +define(["require", "exports", "tslib", "../../../Ajax", "../../../Ajax/Status", "../../../Core", "../../../Language", "../../../Dom/Util", "../../../Ui/Dialog", "WoltLabSuite/Core/Ajax/Error"], function (require, exports, tslib_1, Ajax_1, AjaxStatus, Core_1, Language, Util_1, Dialog_1, Error_1) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.setup = void 0; @@ -14,7 +14,7 @@ define(["require", "exports", "tslib", "../../../Ajax", "../../../Ajax/Status", Language = tslib_1.__importStar(Language); Dialog_1 = tslib_1.__importDefault(Dialog_1); let codeInput; - function detectCode() { + function detectCode(versionNumber) { const value = codeInput.value.trim(); if (value === "") { (0, Util_1.innerError)(codeInput, false); @@ -34,7 +34,7 @@ define(["require", "exports", "tslib", "../../../Ajax", "../../../Ajax/Status", const json = maybeJson; if (json.package && json.password && json.username) { isValid = true; - void prepareInstallation(json); + void prepareInstallation(json, versionNumber); } } } @@ -54,7 +54,7 @@ define(["require", "exports", "tslib", "../../../Ajax", "../../../Ajax/Status", } return refreshedPackageDatabase; } - async function prepareInstallation(data) { + async function prepareInstallation(data, versionNumber) { try { AjaxStatus.show(); await refreshPackageDatabase(); @@ -62,19 +62,38 @@ define(["require", "exports", "tslib", "../../../Ajax", "../../../Ajax/Status", finally { AjaxStatus.hide(); } - const response = (await (0, Ajax_1.dboAction)("prepareInstallation", "wcf\\data\\package\\update\\PackageUpdateAction") - .payload({ - packages: { - [data.package]: "", - }, - authData: { - username: data.username, - password: data.password, - saveCredentials: false, - isStoreCode: true, - }, - }) - .dispatch()); + let response; + try { + response = (await (0, Ajax_1.dboAction)("prepareInstallation", "wcf\\data\\package\\update\\PackageUpdateAction") + .payload({ + packages: { + [data.package]: "", + }, + authData: { + username: data.username, + password: data.password, + saveCredentials: false, + isStoreCode: true, + }, + }) + .dispatch()); + } + catch (e) { + if (e instanceof Error_1.StatusNotOk) { + try { + const json = await e.response.clone().json(); + if (typeof json.message === "string" && json.message.startsWith("Cannot find the package '")) { + codeInput.value = ""; + (0, Util_1.innerError)(codeInput, Language.getPhrase("wcf.acp.package.error.incompatibleStoreProduct", { versionNumber })); + return; + } + } + catch { + throw e; + } + } + throw e; + } if ("queueID" in response) { if (response.queueID === null) { codeInput.value = ""; @@ -102,7 +121,7 @@ define(["require", "exports", "tslib", "../../../Ajax", "../../../Ajax/Status", throw new Error("Unreachable"); } } - function setup() { + function setup(versionNumber) { codeInput = document.getElementById("quickInstallationCode"); codeInput.addEventListener("focus", () => { // Refresh the package database when focusing the input to hide the latency of the package @@ -111,7 +130,7 @@ define(["require", "exports", "tslib", "../../../Ajax", "../../../Ajax/Status", void refreshPackageDatabase(); }); codeInput.addEventListener("input", () => { - detectCode(); + detectCode(versionNumber); }); } exports.setup = setup; diff --git a/wcfsetup/install/files/lib/acp/form/PackageStartInstallForm.class.php b/wcfsetup/install/files/lib/acp/form/PackageStartInstallForm.class.php index 504923fd9b..5d9fd0f0ee 100755 --- a/wcfsetup/install/files/lib/acp/form/PackageStartInstallForm.class.php +++ b/wcfsetup/install/files/lib/acp/form/PackageStartInstallForm.class.php @@ -241,9 +241,12 @@ class PackageStartInstallForm extends AbstractForm { parent::assignVariables(); + $majorMinorVersion = \preg_replace('/^(\d+\.\d+)\..*$/', '\\1', \WCF_VERSION); + WCF::getTPL()->assign([ 'package' => $this->package, 'installingImportedStyle' => $this->stylePackageImportLocation != '', + 'majorMinorVersion' => $majorMinorVersion, ]); } diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index a45d0ef629..34beb4d64c 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -1824,6 +1824,7 @@ Die Datenbestände werden sorgfältig gepflegt, aber es ist nicht ausgeschlossen getName()}“ kann mit dem angegebenen Archiv nicht aktualisiert werden.]]> in unserem Handbuch.]]> + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 99e1a0a57d..b4b3999f32 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -1807,6 +1807,7 @@ The database is carefully maintained, but there will be always be a margin of er getName()}” cannot be updated using the selected archive.]]> in our manual.]]> + -- 2.20.1