From: Alexander Ebert Date: Mon, 25 Sep 2017 09:59:18 +0000 (+0200) Subject: Added partial support for forward-compatibility X-Git-Tag: 3.1.0_Beta_1~10 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=89484ba030439d701c0c6302b7bf9372389426d0;p=GitHub%2FWoltLab%2FWCF.git Added partial support for forward-compatibility See #2427 --- diff --git a/XSD/package.xsd b/XSD/package.xsd index d22f0a4b62..0aea56cb24 100644 --- a/XSD/package.xsd +++ b/XSD/package.xsd @@ -13,6 +13,7 @@ + @@ -46,7 +47,16 @@ - + + + + + + + + + + @@ -123,6 +133,13 @@ + + + + + + + diff --git a/com.woltlab.wcf/package.xml b/com.woltlab.wcf/package.xml index 68687ce422..def7a2ca6a 100644 --- a/com.woltlab.wcf/package.xml +++ b/com.woltlab.wcf/package.xml @@ -1,5 +1,5 @@ - + WoltLab Suite Core Free CMS and web-framework, designed for awesome websites and communities. diff --git a/com.woltlab.wcf/templates/headIncludeJavaScript.tpl b/com.woltlab.wcf/templates/headIncludeJavaScript.tpl index 553f36eafd..4e07f2560f 100644 --- a/com.woltlab.wcf/templates/headIncludeJavaScript.tpl +++ b/com.woltlab.wcf/templates/headIncludeJavaScript.tpl @@ -14,6 +14,7 @@ var URL_LEGACY_MODE = false; var ENABLE_DEBUG_MODE = {if ENABLE_DEBUG_MODE}true{else}false{/if}; var ENABLE_DEVELOPER_TOOLS = {if ENABLE_DEVELOPER_TOOLS}true{else}false{/if}; + var WSC_API_VERSION = {@WSC_API_VERSION}; {if ENABLE_DEBUG_MODE} {* This constant is a compiler option, it does not exist in production. *} diff --git a/wcfsetup/install/files/acp/templates/header.tpl b/wcfsetup/install/files/acp/templates/header.tpl index c4a5534717..5c8dadb002 100644 --- a/wcfsetup/install/files/acp/templates/header.tpl +++ b/wcfsetup/install/files/acp/templates/header.tpl @@ -30,6 +30,7 @@ var URL_LEGACY_MODE = false; var ENABLE_DEBUG_MODE = {if ENABLE_DEBUG_MODE}true{else}false{/if}; var ENABLE_DEVELOPER_TOOLS = {if ENABLE_DEVELOPER_TOOLS}true{else}false{/if}; + var WSC_API_VERSION = {@WSC_API_VERSION}; {* This constant is a compiler option, it does not exist in production. *} {* Unlike the frontend, this option must be defined in the ACP at all times. *} diff --git a/wcfsetup/install/files/acp/templates/index.tpl b/wcfsetup/install/files/acp/templates/index.tpl index 511793d3f9..87cc2a7907 100644 --- a/wcfsetup/install/files/acp/templates/index.tpl +++ b/wcfsetup/install/files/acp/templates/index.tpl @@ -64,12 +64,16 @@

{lang}wcf.acp.index.system.software{/lang}

- {event name='softwareVersions'} -
-
{lang}wcf.acp.index.system.software.wcfVersion{/lang}
-
{@WCF_VERSION}
+
{lang}wcf.acp.index.system.software.apiVersion{/lang}
+
{@WSC_API_VERSION}
+ {if !$__wcf->getSupportedLegacyApiVersions()|empty} +
+
{lang}wcf.acp.index.system.software.legacyApiVersions{/lang}
+
{implode from=$__wcf->getSupportedLegacyApiVersions() item=version glue=', '}{$version}{/implode}
+
+ {/if} {event name='softwareFields'}
diff --git a/wcfsetup/install/files/acp/templates/package.tpl b/wcfsetup/install/files/acp/templates/package.tpl index 5e7708ead5..bf408c616a 100644 --- a/wcfsetup/install/files/acp/templates/package.tpl +++ b/wcfsetup/install/files/acp/templates/package.tpl @@ -82,6 +82,18 @@
{lang}wcf.acp.pluginStore.file.link{/lang}
{/if} + {if $package->packageID != 1} +
+
{lang}wcf.acp.package.apiVersions{/lang}
+
+ {if $compatibleVersions|empty} + {lang}wcf.acp.package.apiVersions.missing{/lang} + {else} + {implode from=$compatibleVersions item=version glue=', '}{$version}{/implode} + {/if} +
+
+ {/if} {event name='propertyFields'} diff --git a/wcfsetup/install/files/lib/acp/action/InstallPackageAction.class.php b/wcfsetup/install/files/lib/acp/action/InstallPackageAction.class.php index 684724a5c6..1db9891ab0 100755 --- a/wcfsetup/install/files/lib/acp/action/InstallPackageAction.class.php +++ b/wcfsetup/install/files/lib/acp/action/InstallPackageAction.class.php @@ -30,13 +30,13 @@ class InstallPackageAction extends AbstractDialogAction { * PackageInstallationDispatcher object * @var PackageInstallationDispatcher */ - public $installation = null; + public $installation; /** * PackageInstallationQueue object * @var PackageInstallationQueue */ - public $queue = null; + public $queue; /** * current queue id diff --git a/wcfsetup/install/files/lib/acp/page/PackageInstallationConfirmPage.class.php b/wcfsetup/install/files/lib/acp/page/PackageInstallationConfirmPage.class.php index fdc01b386b..a17dfda491 100644 --- a/wcfsetup/install/files/lib/acp/page/PackageInstallationConfirmPage.class.php +++ b/wcfsetup/install/files/lib/acp/page/PackageInstallationConfirmPage.class.php @@ -26,13 +26,13 @@ class PackageInstallationConfirmPage extends AbstractPage { * package installation dispatcher object * @var PackageInstallationDispatcher */ - public $packageInstallationDispatcher = null; + public $packageInstallationDispatcher; /** * package installation queue object * @var PackageInstallationQueue */ - public $queue = null; + public $queue; /** * queue id diff --git a/wcfsetup/install/files/lib/acp/page/PackagePage.class.php b/wcfsetup/install/files/lib/acp/page/PackagePage.class.php index 99bfff286f..6323802606 100755 --- a/wcfsetup/install/files/lib/acp/page/PackagePage.class.php +++ b/wcfsetup/install/files/lib/acp/page/PackagePage.class.php @@ -19,6 +19,12 @@ class PackagePage extends AbstractPage { */ public $activeMenuItem = 'wcf.acp.menu.link.package'; + /** + * list of compatible API versions + * @var integer[] + */ + public $compatibleVersions = []; + /** * @inheritDoc */ @@ -68,6 +74,20 @@ class PackagePage extends AbstractPage { $statement = WCF::getDB()->prepareStatement($sql); $statement->execute([$this->package->package]); $this->pluginStoreFileID = intval($statement->fetchSingleColumn()); + + $sql = "SELECT version + FROM wcf".WCF_N."_package_compatibility + WHERE packageID = ? + AND version >= ? + ORDER BY version"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute([ + $this->package->packageID, + WSC_API_VERSION + ]); + while ($version = $statement->fetchColumn()) { + $this->compatibleVersions[] = $version; + } } /** @@ -77,6 +97,7 @@ class PackagePage extends AbstractPage { parent::assignVariables(); WCF::getTPL()->assign([ + 'compatibleVersions' => $this->compatibleVersions, 'package' => $this->package, 'pluginStoreFileID' => $this->pluginStoreFileID ]); diff --git a/wcfsetup/install/files/lib/system/WCF.class.php b/wcfsetup/install/files/lib/system/WCF.class.php index 28a379d69e..0144814d02 100644 --- a/wcfsetup/install/files/lib/system/WCF.class.php +++ b/wcfsetup/install/files/lib/system/WCF.class.php @@ -49,6 +49,9 @@ if (!@ini_get('date.timezone')) { // define current woltlab suite version define('WCF_VERSION', '3.1.0 Alpha 4'); +// define current API version +define('WSC_API_VERSION', 2018); + // define current unix timestamp define('TIME_NOW', time()); @@ -68,6 +71,12 @@ if (!defined('NO_IMPORTS')) { * @package WoltLabSuite\Core\System */ class WCF { + /** + * list of supported legacy API versions + * @var integer[] + */ + private static $supportedLegacyApiVersions = [2017]; + /** * list of currently loaded applications * @var Application[] @@ -1046,6 +1055,25 @@ class WCF { return self::getActiveRequest()->isLandingPage(); } + /** + * Returns true if the given API version is currently supported. + * + * @param integer $apiVersion + * @return boolean + */ + public static function isSupportedApiVersion($apiVersion) { + return ($apiVersion == WSC_API_VERSION) || in_array($apiVersion, self::$supportedLegacyApiVersions); + } + + /** + * Returns the list of supported legacy API versions. + * + * @return integer[] + */ + public static function getSupportedLegacyApiVersions() { + return self::$supportedLegacyApiVersions; + } + /** * Initialises the cronjobs. */ diff --git a/wcfsetup/install/files/lib/system/html/input/filter/MessageHtmlInputFilter.class.php b/wcfsetup/install/files/lib/system/html/input/filter/MessageHtmlInputFilter.class.php index 86334d9fd4..4e193f06c1 100644 --- a/wcfsetup/install/files/lib/system/html/input/filter/MessageHtmlInputFilter.class.php +++ b/wcfsetup/install/files/lib/system/html/input/filter/MessageHtmlInputFilter.class.php @@ -76,7 +76,7 @@ class MessageHtmlInputFilter implements IHtmlInputFilter { */ protected function setAttributeDefinitions(\HTMLPurifier_Config $config) { $definition = $config->getHTMLDefinition(true); - + wcfDebug($config->get('HTML.AllowedAttributes')); // code $definition->addAttribute('pre', 'data-file', 'Text'); $definition->addAttribute('pre', 'data-line', 'Number'); diff --git a/wcfsetup/install/files/lib/system/package/PackageArchive.class.php b/wcfsetup/install/files/lib/system/package/PackageArchive.class.php index 6883153d12..82077a993f 100644 --- a/wcfsetup/install/files/lib/system/package/PackageArchive.class.php +++ b/wcfsetup/install/files/lib/system/package/PackageArchive.class.php @@ -22,19 +22,19 @@ class PackageArchive { * path to package archive * @var string */ - protected $archive = null; + protected $archive; /** * package object of an existing package * @var Package */ - protected $package = null; + protected $package; /** * tar archive object * @var Tar */ - protected $tar = null; + protected $tar; /** * general package information @@ -66,6 +66,12 @@ class PackageArchive { */ protected $excludedPackages = []; + /** + * list of compatible API versions + * @var integer[] + */ + protected $compatibility = []; + /** * list of instructions * @var mixed[][] @@ -282,6 +288,19 @@ class PackageArchive { $this->excludedPackages[] = $data; } + // get api compatibility + $elements = $xpath->query('child::ns:compatibility/ns:api', $package); + foreach ($elements as $element) { + if (!$element->hasAttribute('version')) continue; + + $version = $element->getAttribute('version'); + if (!preg_match('~^(?:201[7-9]|20[2-9][0-9])$~', $version)) { + throw new PackageValidationException(PackageValidationException::INVALID_API_VERSION, ['version' => $version]); + } + + $this->compatibility[] = $version; + } + // get instructions $elements = $xpath->query('./ns:instructions', $package); foreach ($elements as $element) { @@ -528,6 +547,15 @@ class PackageArchive { return $this->excludedPackages; } + /** + * Returns the list of compatible API versions. + * + * @return integer[] + */ + public function getCompatibleVersions() { + return $this->compatibility; + } + /** * Returns the package installation instructions. * diff --git a/wcfsetup/install/files/lib/system/package/PackageInstallationDispatcher.class.php b/wcfsetup/install/files/lib/system/package/PackageInstallationDispatcher.class.php index 9d3298ecf9..fcf9c6d90c 100644 --- a/wcfsetup/install/files/lib/system/package/PackageInstallationDispatcher.class.php +++ b/wcfsetup/install/files/lib/system/package/PackageInstallationDispatcher.class.php @@ -436,6 +436,21 @@ class PackageInstallationDispatcher { } } + // save compatible versions + if (!empty($this->getArchive()->getCompatibleVersions())) { + $sql = "INSERT INTO wcf".WCF_N."_package_compatibility + (packageID, version) + VALUES (?, ?)"; + $statement = WCF::getDB()->prepareStatement($sql); + + foreach ($this->getArchive()->getCompatibleVersions() as $version) { + $statement->execute([ + $this->queue->packageID, + $version + ]); + } + } + // insert requirements and dependencies $requirements = $this->getArchive()->getAllExistingRequirements(); if (!empty($requirements)) { diff --git a/wcfsetup/install/files/lib/system/package/validation/PackageValidationArchive.class.php b/wcfsetup/install/files/lib/system/package/validation/PackageValidationArchive.class.php index 8c80576e46..265268d4d1 100644 --- a/wcfsetup/install/files/lib/system/package/validation/PackageValidationArchive.class.php +++ b/wcfsetup/install/files/lib/system/package/validation/PackageValidationArchive.class.php @@ -17,7 +17,7 @@ use wcf\system\WCF; class PackageValidationArchive implements \RecursiveIterator { /** * list of excluded packages grouped by package - * @var string[] + * @var string[][] */ protected static $excludedPackages = []; @@ -25,7 +25,7 @@ class PackageValidationArchive implements \RecursiveIterator { * package archive object * @var PackageArchive */ - protected $archive = null; + protected $archive; /** * list of direct requirements delivered by this package @@ -43,19 +43,19 @@ class PackageValidationArchive implements \RecursiveIterator { * exception occurred during validation * @var \Exception */ - protected $exception = null; + protected $exception; /** * associated package object * @var Package */ - protected $package = null; + protected $package; /** * parent package validation archive object * @var PackageValidationArchive */ - protected $parent = null; + protected $parent; /** * children pointer @@ -198,6 +198,29 @@ class PackageValidationArchive implements \RecursiveIterator { ]); } + // check if this package exposes compatible api versions + $compatibleVersions = $this->archive->getCompatibleVersions(); + if (!empty($compatibleVersions)) { + $isCompatible = $isOlderVersion = false; + foreach ($compatibleVersions as $version) { + if (WCF::isSupportedApiVersion($version)) { + $isCompatible = true; + break; + } + else if ($version < WSC_API_VERSION) { + $isOlderVersion = true; + } + } + + if (!$isCompatible) { + + throw new PackageValidationException(PackageValidationException::INCOMPATIBLE_API_VERSION, ['isOlderVersion' => $isOlderVersion]); + } + } + else if (ENABLE_DEBUG_MODE && ENABLE_DEVELOPER_TOOLS) { + throw new PackageValidationException(PackageValidationException::MISSING_API_VERSION); + } + // package is not installed yet if ($package === null) { $instructions = $this->archive->getInstallInstructions(); diff --git a/wcfsetup/install/files/lib/system/package/validation/PackageValidationException.class.php b/wcfsetup/install/files/lib/system/package/validation/PackageValidationException.class.php index 677fdce0ed..6c16caa7eb 100644 --- a/wcfsetup/install/files/lib/system/package/validation/PackageValidationException.class.php +++ b/wcfsetup/install/files/lib/system/package/validation/PackageValidationException.class.php @@ -93,6 +93,24 @@ class PackageValidationException extends SystemException { */ const ALREADY_INSTALLED = 12; + /** + * the provided API version string is invalid and does not fall into the range from `2017` through `2099` + * @var integer + */ + const INVALID_API_VERSION = 13; + + /** + * the package is not compatible with the current API version or any other of the supported ones + * @var integer + */ + const INCOMPATIBLE_API_VERSION = 14; + + /** + * the package lacks any sort of API compatibility data + * @var integer + */ + const MISSING_API_VERSION = 15; + /** * Creates a new PackageArchiveValidationException. * diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index 487bf4a1d9..a38f458dee 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -691,7 +691,8 @@ - + + @@ -1449,6 +1450,8 @@ Als Benachrichtigungs-URL in der Konfiguration der sofortigen Zahlungsbestätigu + + @@ -1577,6 +1580,9 @@ Als Benachrichtigungs-URL in der Konfiguration der sofortigen Zahlungsbestätigu packageVersion}“ installiert.{/if}]]>
  • Die Datei wurde dem Archiv nicht hinzugefügt
  • Die Datei existiert, jedoch sind der Dateiname und die Angabe in den Anweisungen abweichend (Tippfehler)
  • ]]>
    + + +
    diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 83b712671b..a6755ff53d 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -674,7 +674,8 @@ - + + @@ -1443,6 +1444,8 @@ When prompted for the notification URL for the instant payment notifications, pl + + @@ -1571,6 +1574,9 @@ When prompted for the notification URL for the instant payment notifications, pl packageVersion}” is installed.{/if}]]>
  • The file has not been added to the archive at all
  • The file exists but under a (slightly) different name (typo)
  • ]]>
    + + +
    diff --git a/wcfsetup/setup/db/install.sql b/wcfsetup/setup/db/install.sql index 4c86bcaaa4..ca08ce48f2 100644 --- a/wcfsetup/setup/db/install.sql +++ b/wcfsetup/setup/db/install.sql @@ -872,6 +872,13 @@ CREATE TABLE wcf1_package ( KEY package (package) ); +DROP TABLE IF EXISTS wcf1_package_compatibility; +CREATE TABLE wcf1_package_compatibility ( + packageID INT(10) NOT NULL, + version SMALLINT(4) NOT NULL, + UNIQUE KEY compatibleVersion (packageID, version) +); + DROP TABLE IF EXISTS wcf1_package_exclusion; CREATE TABLE wcf1_package_exclusion ( packageID INT(10) NOT NULL, @@ -956,6 +963,13 @@ CREATE TABLE wcf1_package_update ( UNIQUE KEY packageUpdateServerID (packageUpdateServerID, package) ); +DROP TABLE IF EXISTS wcf1_package_update_compatibility; +CREATE TABLE wcf1_package_update_compatibility ( + packageUpdateVersionID INT(10) NOT NULL, + version SMALLINT(4) NOT NULL, + UNIQUE KEY compatibleVersion (packageUpdateVersionID, version) +); + DROP TABLE IF EXISTS wcf1_package_update_exclusion; CREATE TABLE wcf1_package_update_exclusion ( packageUpdateVersionID INT(10) NOT NULL, @@ -1886,6 +1900,8 @@ ALTER TABLE wcf1_option ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (pac ALTER TABLE wcf1_option_category ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE; +ALTER TABLE wcf1_package_compatibility ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE; + ALTER TABLE wcf1_package_exclusion ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE; ALTER TABLE wcf1_package_installation_file_log ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE; @@ -1908,6 +1924,8 @@ ALTER TABLE wcf1_package_requirement ADD FOREIGN KEY (requirement) REFERENCES wc ALTER TABLE wcf1_package_update ADD FOREIGN KEY (packageUpdateServerID) REFERENCES wcf1_package_update_server (packageUpdateServerID) ON DELETE CASCADE; +ALTER TABLE wcf1_package_update_compatibility ADD FOREIGN KEY (packageUpdateVersionID) REFERENCES wcf1_package_update_version (packageUpdateVersionID) ON DELETE CASCADE; + ALTER TABLE wcf1_package_update_exclusion ADD FOREIGN KEY (packageUpdateVersionID) REFERENCES wcf1_package_update_version (packageUpdateVersionID) ON DELETE CASCADE; ALTER TABLE wcf1_package_update_fromversion ADD FOREIGN KEY (packageUpdateVersionID) REFERENCES wcf1_package_update_version (packageUpdateVersionID) ON DELETE CASCADE; @@ -2136,7 +2154,9 @@ INSERT INTO wcf1_user_group_option_value (groupID, optionID, optionValue) VALUES -- default update servers INSERT INTO wcf1_package_update_server (serverURL, status, isDisabled, errorMessage, lastUpdateTime, loginUsername, loginPassword) VALUES ('http://update.woltlab.com/vortex/', 'online', 0, NULL, 0, '', ''); +INSERT INTO wcf1_package_update_server (serverURL, status, isDisabled, errorMessage, lastUpdateTime, loginUsername, loginPassword) VALUES ('http://update.woltlab.com/tornado/', 'online', 0, NULL, 0, '', ''); INSERT INTO wcf1_package_update_server (serverURL, status, isDisabled, errorMessage, lastUpdateTime, loginUsername, loginPassword) VALUES ('http://store.woltlab.com/vortex/', 'online', 0, NULL, 0, '', ''); +INSERT INTO wcf1_package_update_server (serverURL, status, isDisabled, errorMessage, lastUpdateTime, loginUsername, loginPassword) VALUES ('http://store.woltlab.com/tornado/', 'online', 0, NULL, 0, '', ''); -- style default values INSERT INTO wcf1_style_variable (variableName, defaultValue) VALUES ('individualScss', '');