<xs:element name="requiredpackages" type="requiredPackages" minOccurs="0" maxOccurs="1" />
<xs:element name="optionalpackages" type="optionalPackages" minOccurs="0" maxOccurs="1" />
<xs:element name="excludedpackages" type="excludedPackages" minOccurs="0" maxOccurs="1" />
+ <xs:element name="compatibility" type="compatibility" minOccurs="0" maxOccurs="1" />
</xs:choice>
<xs:attribute name="name" type="woltlab_varchar" use="required" />
</xs:complexType>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
-
+
+ <!-- api compatibility version element -->
+ <xs:complexType name="apiVersion">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="version" type="xs:integer" use="required" />
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
<!-- instructions elements -->
<xs:complexType name="instructions">
<xs:sequence>
<xs:element name="excludedpackage" type="excludedPackage" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
+
+ <!-- api compatibility element -->
+ <xs:complexType name="compatibility">
+ <xs:sequence>
+ <xs:element name="api" type="apiVersion" minOccurs="1" maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:complexType>
<xs:complexType name="instructionType">
<xs:simpleContent>
<?xml version="1.0" encoding="UTF-8"?>
-<package name="com.woltlab.wcf" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/vortex/package.xsd">
+<package name="com.woltlab.wcf" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/tornado/package.xsd">
<packageinformation>
<packagename>WoltLab Suite Core</packagename>
<packagedescription>Free CMS and web-framework, designed for awesome websites and communities.</packagedescription>
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. *}
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. *}
<section class="section">
<h2 class="sectionTitle">{lang}wcf.acp.index.system.software{/lang}</h2>
- {event name='softwareVersions'}
-
<dl>
- <dt>{lang}wcf.acp.index.system.software.wcfVersion{/lang}</dt>
- <dd>{@WCF_VERSION}</dd>
+ <dt>{lang}wcf.acp.index.system.software.apiVersion{/lang}</dt>
+ <dd>{@WSC_API_VERSION}</dd>
</dl>
+ {if !$__wcf->getSupportedLegacyApiVersions()|empty}
+ <dl>
+ <dt>{lang}wcf.acp.index.system.software.legacyApiVersions{/lang}</dt>
+ <dd><small>{implode from=$__wcf->getSupportedLegacyApiVersions() item=version glue=', '}{$version}{/implode}</small></dd>
+ </dl>
+ {/if}
{event name='softwareFields'}
</section>
<dd><a href="{@$__wcf->getPath()}acp/dereferrer.php?url={$_storeUrl|rawurlencode}" class="externalURL">{lang}wcf.acp.pluginStore.file.link{/lang}</a></dd>
</dl>
{/if}
+ {if $package->packageID != 1}
+ <dl>
+ <dt>{lang}wcf.acp.package.apiVersions{/lang}</dt>
+ <dd>
+ {if $compatibleVersions|empty}
+ <small>{lang}wcf.acp.package.apiVersions.missing{/lang}</small>
+ {else}
+ {implode from=$compatibleVersions item=version glue=', '}{$version}{/implode}
+ {/if}
+ </dd>
+ </dl>
+ {/if}
{event name='propertyFields'}
</div>
* PackageInstallationDispatcher object
* @var PackageInstallationDispatcher
*/
- public $installation = null;
+ public $installation;
/**
* PackageInstallationQueue object
* @var PackageInstallationQueue
*/
- public $queue = null;
+ public $queue;
/**
* current queue id
* package installation dispatcher object
* @var PackageInstallationDispatcher
*/
- public $packageInstallationDispatcher = null;
+ public $packageInstallationDispatcher;
/**
* package installation queue object
* @var PackageInstallationQueue
*/
- public $queue = null;
+ public $queue;
/**
* queue id
*/
public $activeMenuItem = 'wcf.acp.menu.link.package';
+ /**
+ * list of compatible API versions
+ * @var integer[]
+ */
+ public $compatibleVersions = [];
+
/**
* @inheritDoc
*/
$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;
+ }
}
/**
parent::assignVariables();
WCF::getTPL()->assign([
+ 'compatibleVersions' => $this->compatibleVersions,
'package' => $this->package,
'pluginStoreFileID' => $this->pluginStoreFileID
]);
// 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());
* @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[]
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.
*/
*/
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');
* 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
*/
protected $excludedPackages = [];
+ /**
+ * list of compatible API versions
+ * @var integer[]
+ */
+ protected $compatibility = [];
+
/**
* list of instructions
* @var mixed[][]
$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) {
return $this->excludedPackages;
}
+ /**
+ * Returns the list of compatible API versions.
+ *
+ * @return integer[]
+ */
+ public function getCompatibleVersions() {
+ return $this->compatibility;
+ }
+
/**
* Returns the package installation instructions.
*
}
}
+ // 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)) {
class PackageValidationArchive implements \RecursiveIterator {
/**
* list of excluded packages grouped by package
- * @var string[]
+ * @var string[][]
*/
protected static $excludedPackages = [];
* package archive object
* @var PackageArchive
*/
- protected $archive = null;
+ protected $archive;
/**
* list of direct requirements delivered by this package
* 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
]);
}
+ // 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();
*/
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.
*
<item name="wcf.acp.index.setup.title"><![CDATA[Bitte warten]]></item>
<item name="wcf.acp.index.system"><![CDATA[System]]></item>
<item name="wcf.acp.index.system.software"><![CDATA[Software]]></item>
- <item name="wcf.acp.index.system.software.wcfVersion"><![CDATA[WoltLab Suite™-Version]]></item>
+ <item name="wcf.acp.index.system.software.apiVersion"><![CDATA[WoltLab Suite™ API-Version]]></item>
+ <item name="wcf.acp.index.system.software.legacyApiVersions"><![CDATA[Ältere, noch unterstützte API-Versionen]]></item>
<item name="wcf.acp.index.system.server"><![CDATA[Server]]></item>
<item name="wcf.acp.index.system.os"><![CDATA[Betriebssystem]]></item>
<item name="wcf.acp.index.system.webserver"><![CDATA[Webserver]]></item>
</category>
<category name="wcf.acp.package">
+ <item name="wcf.acp.package.apiVersions"><![CDATA[Unterstütze WoltLab Suite™ API-Versionen]]></item>
+ <item name="wcf.acp.package.apiVersions.missing"><![CDATA[Dieses Paket stellt keine Informationen zur Kompatibilität bereit.]]></item>
<item name="wcf.acp.package.application.installed"><![CDATA[Installierte Apps]]></item>
<item name="wcf.acp.package.application.title"><![CDATA[Apps]]></item>
<item name="wcf.acp.package.author"><![CDATA[Entwickler]]></item>
<item name="wcf.acp.package.validation.errorCode.10"><![CDATA[Benötigt das Paket {if $package === null}„{$packageName}“{else}„{$package}“{/if} in Version „{$packageVersion}“ oder höher, {if $package === null}dies ist aber weder installiert noch wird es mitgeliefert.{else}es ist aber nur Version „{$package->packageVersion}“ installiert.{/if}]]></item>
<item name="wcf.acp.package.validation.errorCode.11"><![CDATA[Die {if $type == 'install'}Installations{else}Update{/if}-Anweisungen geben für das Package Installation Plugin „{$pip}“ die Datei „{$value}“ an, diese ist jedoch nicht im Archiv enthalten. Mögliche Ursachen:<ul class="nativeList"><li>Die Datei wurde dem Archiv nicht hinzugefügt</li><li>Die Datei existiert, jedoch sind der Dateiname und die Angabe in den Anweisungen abweichend (Tippfehler)</li></ul>]]></item>
<item name="wcf.acp.package.validation.errorCode.12"><![CDATA[Das Paket „{lang}{$packageName}{/lang}“ ist bereits in Version „{$packageVersion}“ installiert.]]></item>
+ <item name="wcf.acp.package.validation.errorCode.13"><![CDATA[Die API-Version „{$version}“ ist ungültig.]]></item>
+ <item name="wcf.acp.package.validation.errorCode.14"><![CDATA[Das Paket wurde für eine {if $isOlderVersion}ältere{else}neuere{/if} Version von WoltLab Suite entwickelt und ist nicht kompatibel.]]></item>
+ <item name="wcf.acp.package.validation.errorCode.15"><![CDATA[Das Paket verfügt über keine Angaben zur API-Kompatibilität, eine Installation mit aktivierten Entwickler-Werkzeugen ist daher nicht möglich.]]></item>
<item name="wcf.acp.package.validation.failed"><![CDATA[Das hochgeladene Paket kann nicht installiert werden, bitte {if LANGUAGE_USE_INFORMAL_VARIANT}beachte{else}beachten Sie{/if} das unten stehende Prüfungsergebnis.]]></item>
</category>
<item name="wcf.acp.index.setup.title"><![CDATA[Please Wait]]></item>
<item name="wcf.acp.index.system"><![CDATA[System]]></item>
<item name="wcf.acp.index.system.software"><![CDATA[Software]]></item>
- <item name="wcf.acp.index.system.software.wcfVersion"><![CDATA[WoltLab Suite™ Version]]></item>
+ <item name="wcf.acp.index.system.software.apiVersion"><![CDATA[WoltLab Suite™ API-version]]></item>
+ <item name="wcf.acp.index.system.software.legacyApiVersions"><![CDATA[Older, still supported, API-versions]]></item>
<item name="wcf.acp.index.system.server"><![CDATA[Server]]></item>
<item name="wcf.acp.index.system.os"><![CDATA[Operating System]]></item>
<item name="wcf.acp.index.system.webserver"><![CDATA[Web Server]]></item>
</category>
<category name="wcf.acp.package">
+ <item name="wcf.acp.package.apiVersions"><![CDATA[Supported WoltLab Suite™ API-versions]]></item>
+ <item name="wcf.acp.package.apiVersions.missing"><![CDATA[This package does not provide any compatibility data.]]></item>
<item name="wcf.acp.package.application.installed"><![CDATA[Installed Apps]]></item>
<item name="wcf.acp.package.application.title"><![CDATA[Apps]]></item>
<item name="wcf.acp.package.author"><![CDATA[Developer]]></item>
<item name="wcf.acp.package.validation.errorCode.10"><![CDATA[Requires the package {if $package === null}“{$packageName}”{else}“{$package}”{/if} in version “{$packageVersion}” or higher, {if $package === null}but it is neither installed nor shipped.{else}but only version “{$package->packageVersion}” is installed.{/if}]]></item>
<item name="wcf.acp.package.validation.errorCode.11"><![CDATA[The {if $type == 'install'}install{else}update{/if}-instructions specify the file “{$value}” for the Package Installation Plugin “{$pip}”, but it cannot be found in the specified location. Possible causes:<ul class="nativeList"><li>The file has not been added to the archive at all</li><li>The file exists but under a (slightly) different name (typo)</li></ul>]]></item>
<item name="wcf.acp.package.validation.errorCode.12"><![CDATA[The package “{lang}{$packageName}{/lang}” is already installed in version “{$packageVersion}”.]]></item>
+ <item name="wcf.acp.package.validation.errorCode.13"><![CDATA[The API version API-Version “{$version}” is invalid.]]></item>
+ <item name="wcf.acp.package.validation.errorCode.14"><![CDATA[This package was created for {if $isOlderVersion}an older{else}a newer{/if} version of WoltLab Suite and is not compatible.]]></item>
+ <item name="wcf.acp.package.validation.errorCode.15"><![CDATA[This package does not contain any data on API compatibility, the installation is prevented while the developer tools are enabled.]]></item>
<item name="wcf.acp.package.validation.failed"><![CDATA[The package cannot be installed, please review the validation results below.]]></item>
</category>
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,
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,
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;
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;
-- 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', '');